or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-pouchdb-collate

Collation functions for PouchDB map/reduce to maintain consistent CouchDB collation ordering

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/pouchdb-collate@7.0.x

To install, run

npx @tessl/cli install tessl/npm-pouchdb-collate@7.0.0

index.mddocs/

PouchDB Collate

PouchDB Collate provides collation functions for PouchDB map/reduce operations to maintain consistent CouchDB collation ordering. It offers four key functions for converting objects to serialized strings that maintain proper sort order, parsing those strings back to objects, comparing objects with proper ordering semantics, and normalizing objects to match CouchDB expectations.

Package Information

  • Package Name: pouchdb-collate
  • Package Type: npm
  • Language: JavaScript (ES6 modules)
  • Installation: npm install pouchdb-collate

Core Imports

import { collate, normalizeKey, toIndexableString, parseIndexableString } from "pouchdb-collate";

For CommonJS:

const { collate, normalizeKey, toIndexableString, parseIndexableString } = require("pouchdb-collate");

Basic Usage

import { collate, toIndexableString, parseIndexableString, normalizeKey } from "pouchdb-collate";

// Compare objects with proper CouchDB ordering
const comparison = collate("apple", "banana"); // -1 (apple < banana)
const sameComparison = collate([1, 2], [1, 2]); // 0 (equal)

// Convert objects to sortable strings
const sortableId = toIndexableString([67, true, "McDuck", "Scrooge"]);
// Result: '5323256.70000000000000017764\u000021\u00004McDuck\u00004Scrooge\u0000\u0000'

// Parse strings back to original objects
const originalData = parseIndexableString(sortableId);
// Result: [67, true, "McDuck", "Scrooge"]

// Normalize keys for CouchDB compatibility
const normalized = normalizeKey(undefined); // null
const dateNormalized = normalizeKey(new Date("2023-01-01")); // "2023-01-01T00:00:00.000Z"

Capabilities

Object Comparison

Compares two objects using CouchDB collation ordering rules.

/**
 * Compares two objects using CouchDB collation ordering
 * @param {any} a - First object to compare
 * @param {any} b - Second object to compare
 * @returns {number} Number indicating comparison result (-1, 0, 1)
 */
function collate(a, b);

CouchDB collation order: null < boolean < number < string < array < object

Usage Examples:

// Basic comparisons
collate(null, false); // -1 (null comes before boolean)
collate(42, "hello"); // -1 (number comes before string)
collate([1, 2], {a: 1}); // -1 (array comes before object)

// String comparison
collate("apple", "banana"); // -1
collate("banana", "apple"); // 1
collate("same", "same"); // 0

// Array comparison (element by element)
collate([1, 2, 3], [1, 2, 4]); // -1
collate([1, 2], [1, 2, 3]); // -1 (shorter array comes first)

// Object comparison (by keys and values)
collate({a: 1, b: 2}, {a: 1, b: 3}); // -1
collate({a: 1}, {a: 1, b: 2}); // -1 (fewer keys comes first)

String Serialization

Converts any object to a serialized string that maintains proper CouchDB collation ordering for lexical sorting.

/**
 * Converts any object to a serialized string maintaining CouchDB collation ordering
 * @param {any} key - Object to convert to indexable string
 * @returns {string} String representation suitable for lexical sorting
 */
function toIndexableString(key);

Usage Examples:

// Create sortable document IDs
const docId1 = toIndexableString([25, true, "Smith", "John"]);
const docId2 = toIndexableString([30, false, "Doe", "Jane"]);

// These strings will sort lexically in the same order as collate() would sort the original objects
console.log(docId1 < docId2); // true (matches collate([25, true, "Smith", "John"], [30, false, "Doe", "Jane"]) < 0)

// Handle different data types
toIndexableString(null); // "1\u0000"
toIndexableString(true); // "21\u0000"
toIndexableString(42); // "532342.00000000000000000000\u0000"
toIndexableString("hello"); // "4hello\u0000"
toIndexableString([1, 2]); // "5532141.00000000000000000000532242.00000000000000000000\u0000"

// For CouchDB compatibility, replace null bytes with another separator
const couchDbSafeId = toIndexableString([1, 2, 3]).replace(/\u0000/g, '\u0001');

String Parsing

Reverses the toIndexableString operation, converting a serialized string back to its original structured object.

/**
 * Converts an indexable string back to its original structured object
 * @param {string} str - Indexable string created by toIndexableString
 * @returns {any} Original JavaScript value
 * @throws {Error} If the string format is invalid
 */
function parseIndexableString(str);

Usage Examples:

// Round-trip conversion
const originalData = [67, true, "McDuck", "Scrooge"];
const serialized = toIndexableString(originalData);
const restored = parseIndexableString(serialized);
console.log(restored); // [67, true, "McDuck", "Scrooge"]

// Parse different data types
parseIndexableString("1\u0000"); // null
parseIndexableString("21\u0000"); // true
parseIndexableString("20\u0000"); // false
parseIndexableString("532342.00000000000000000000\u0000"); // 42

// Error handling
try {
  parseIndexableString("invalid-string");
} catch (error) {
  console.error("Invalid indexable string format");
}

Key Normalization

Normalizes objects to match CouchDB expectations by converting undefined to null, NaN/Infinity to null, and Date objects to JSON strings.

/**
 * Normalizes objects to match CouchDB expectations
 * @param {any} key - Object to normalize
 * @returns {any} Normalized version compatible with CouchDB
 */
function normalizeKey(key);

Usage Examples:

// Handle undefined and special values
normalizeKey(undefined); // null
normalizeKey(NaN); // null
normalizeKey(Infinity); // null
normalizeKey(-Infinity); // null

// Convert dates to JSON strings
normalizeKey(new Date("2023-01-01")); // "2023-01-01T00:00:00.000Z"

// Recursively normalize arrays and objects
normalizeKey([1, undefined, new Date("2023-01-01")]); 
// [1, null, "2023-01-01T00:00:00.000Z"]

normalizeKey({
  name: "John",
  birthDate: new Date("1990-01-01"),
  score: undefined
});
// { name: "John", birthDate: "1990-01-01T00:00:00.000Z" }
// Note: undefined properties are omitted

// Equivalent to JSON.parse(JSON.stringify(obj)) but faster
const fastNormalized = normalizeKey(complexObject);
const jsonNormalized = JSON.parse(JSON.stringify(complexObject));
// Results are equivalent

Types

// All functions accept any JavaScript value including:
// null, undefined, boolean, number, string, Date, arrays, and objects

// Comparison functions return one of: -1, 0, 1
// Indexable strings are encoded strings with specific format for sorting

Error Handling

The package throws errors in the following cases:

  • parseIndexableString() throws an Error if given a malformed indexable string
  • All other functions handle invalid inputs gracefully by normalizing them according to CouchDB rules

Advanced Usage

Creating Compound Sort Keys

// Sort by age (ascending), then by gender (descending), then by name (ascending)
function createSortKey(person) {
  return toIndexableString([
    person.age,
    !person.male, // Invert boolean for descending order
    person.lastName,
    person.firstName
  ]);
}

const people = [
  { age: 25, male: true, lastName: "Smith", firstName: "John" },
  { age: 25, male: false, lastName: "Smith", firstName: "Jane" },
  { age: 30, male: true, lastName: "Doe", firstName: "Bob" }
];

// Create sortable IDs
people.forEach(person => {
  person._id = createSortKey(person);
});

// Now people can be sorted lexically by _id and maintain proper ordering

Data Type Priority

Objects are sorted according to CouchDB collation rules:

  1. null (includes undefined, NaN, Infinity, -Infinity)
  2. boolean (false < true)
  3. number (numeric comparison)
  4. string (lexicographic comparison)
  5. array (element-by-element comparison, shorter arrays first)
  6. object (key-by-key comparison, fewer keys first)