Collation functions for PouchDB map/reduce to maintain consistent CouchDB collation ordering
npx @tessl/cli install tessl/npm-pouchdb-collate@7.0.00
# PouchDB Collate
1
2
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.
3
4
## Package Information
5
6
- **Package Name**: pouchdb-collate
7
- **Package Type**: npm
8
- **Language**: JavaScript (ES6 modules)
9
- **Installation**: `npm install pouchdb-collate`
10
11
## Core Imports
12
13
```javascript
14
import { collate, normalizeKey, toIndexableString, parseIndexableString } from "pouchdb-collate";
15
```
16
17
For CommonJS:
18
19
```javascript
20
const { collate, normalizeKey, toIndexableString, parseIndexableString } = require("pouchdb-collate");
21
```
22
23
## Basic Usage
24
25
```javascript
26
import { collate, toIndexableString, parseIndexableString, normalizeKey } from "pouchdb-collate";
27
28
// Compare objects with proper CouchDB ordering
29
const comparison = collate("apple", "banana"); // -1 (apple < banana)
30
const sameComparison = collate([1, 2], [1, 2]); // 0 (equal)
31
32
// Convert objects to sortable strings
33
const sortableId = toIndexableString([67, true, "McDuck", "Scrooge"]);
34
// Result: '5323256.70000000000000017764\u000021\u00004McDuck\u00004Scrooge\u0000\u0000'
35
36
// Parse strings back to original objects
37
const originalData = parseIndexableString(sortableId);
38
// Result: [67, true, "McDuck", "Scrooge"]
39
40
// Normalize keys for CouchDB compatibility
41
const normalized = normalizeKey(undefined); // null
42
const dateNormalized = normalizeKey(new Date("2023-01-01")); // "2023-01-01T00:00:00.000Z"
43
```
44
45
## Capabilities
46
47
### Object Comparison
48
49
Compares two objects using CouchDB collation ordering rules.
50
51
```javascript { .api }
52
/**
53
* Compares two objects using CouchDB collation ordering
54
* @param {any} a - First object to compare
55
* @param {any} b - Second object to compare
56
* @returns {number} Number indicating comparison result (-1, 0, 1)
57
*/
58
function collate(a, b);
59
```
60
61
CouchDB collation order: null < boolean < number < string < array < object
62
63
**Usage Examples:**
64
65
```javascript
66
// Basic comparisons
67
collate(null, false); // -1 (null comes before boolean)
68
collate(42, "hello"); // -1 (number comes before string)
69
collate([1, 2], {a: 1}); // -1 (array comes before object)
70
71
// String comparison
72
collate("apple", "banana"); // -1
73
collate("banana", "apple"); // 1
74
collate("same", "same"); // 0
75
76
// Array comparison (element by element)
77
collate([1, 2, 3], [1, 2, 4]); // -1
78
collate([1, 2], [1, 2, 3]); // -1 (shorter array comes first)
79
80
// Object comparison (by keys and values)
81
collate({a: 1, b: 2}, {a: 1, b: 3}); // -1
82
collate({a: 1}, {a: 1, b: 2}); // -1 (fewer keys comes first)
83
```
84
85
### String Serialization
86
87
Converts any object to a serialized string that maintains proper CouchDB collation ordering for lexical sorting.
88
89
```javascript { .api }
90
/**
91
* Converts any object to a serialized string maintaining CouchDB collation ordering
92
* @param {any} key - Object to convert to indexable string
93
* @returns {string} String representation suitable for lexical sorting
94
*/
95
function toIndexableString(key);
96
```
97
98
**Usage Examples:**
99
100
```javascript
101
// Create sortable document IDs
102
const docId1 = toIndexableString([25, true, "Smith", "John"]);
103
const docId2 = toIndexableString([30, false, "Doe", "Jane"]);
104
105
// These strings will sort lexically in the same order as collate() would sort the original objects
106
console.log(docId1 < docId2); // true (matches collate([25, true, "Smith", "John"], [30, false, "Doe", "Jane"]) < 0)
107
108
// Handle different data types
109
toIndexableString(null); // "1\u0000"
110
toIndexableString(true); // "21\u0000"
111
toIndexableString(42); // "532342.00000000000000000000\u0000"
112
toIndexableString("hello"); // "4hello\u0000"
113
toIndexableString([1, 2]); // "5532141.00000000000000000000532242.00000000000000000000\u0000"
114
115
// For CouchDB compatibility, replace null bytes with another separator
116
const couchDbSafeId = toIndexableString([1, 2, 3]).replace(/\u0000/g, '\u0001');
117
```
118
119
### String Parsing
120
121
Reverses the toIndexableString operation, converting a serialized string back to its original structured object.
122
123
```javascript { .api }
124
/**
125
* Converts an indexable string back to its original structured object
126
* @param {string} str - Indexable string created by toIndexableString
127
* @returns {any} Original JavaScript value
128
* @throws {Error} If the string format is invalid
129
*/
130
function parseIndexableString(str);
131
```
132
133
**Usage Examples:**
134
135
```javascript
136
// Round-trip conversion
137
const originalData = [67, true, "McDuck", "Scrooge"];
138
const serialized = toIndexableString(originalData);
139
const restored = parseIndexableString(serialized);
140
console.log(restored); // [67, true, "McDuck", "Scrooge"]
141
142
// Parse different data types
143
parseIndexableString("1\u0000"); // null
144
parseIndexableString("21\u0000"); // true
145
parseIndexableString("20\u0000"); // false
146
parseIndexableString("532342.00000000000000000000\u0000"); // 42
147
148
// Error handling
149
try {
150
parseIndexableString("invalid-string");
151
} catch (error) {
152
console.error("Invalid indexable string format");
153
}
154
```
155
156
### Key Normalization
157
158
Normalizes objects to match CouchDB expectations by converting undefined to null, NaN/Infinity to null, and Date objects to JSON strings.
159
160
```javascript { .api }
161
/**
162
* Normalizes objects to match CouchDB expectations
163
* @param {any} key - Object to normalize
164
* @returns {any} Normalized version compatible with CouchDB
165
*/
166
function normalizeKey(key);
167
```
168
169
**Usage Examples:**
170
171
```javascript
172
// Handle undefined and special values
173
normalizeKey(undefined); // null
174
normalizeKey(NaN); // null
175
normalizeKey(Infinity); // null
176
normalizeKey(-Infinity); // null
177
178
// Convert dates to JSON strings
179
normalizeKey(new Date("2023-01-01")); // "2023-01-01T00:00:00.000Z"
180
181
// Recursively normalize arrays and objects
182
normalizeKey([1, undefined, new Date("2023-01-01")]);
183
// [1, null, "2023-01-01T00:00:00.000Z"]
184
185
normalizeKey({
186
name: "John",
187
birthDate: new Date("1990-01-01"),
188
score: undefined
189
});
190
// { name: "John", birthDate: "1990-01-01T00:00:00.000Z" }
191
// Note: undefined properties are omitted
192
193
// Equivalent to JSON.parse(JSON.stringify(obj)) but faster
194
const fastNormalized = normalizeKey(complexObject);
195
const jsonNormalized = JSON.parse(JSON.stringify(complexObject));
196
// Results are equivalent
197
```
198
199
## Types
200
201
```javascript { .api }
202
// All functions accept any JavaScript value including:
203
// null, undefined, boolean, number, string, Date, arrays, and objects
204
205
// Comparison functions return one of: -1, 0, 1
206
// Indexable strings are encoded strings with specific format for sorting
207
```
208
209
## Error Handling
210
211
The package throws errors in the following cases:
212
213
- `parseIndexableString()` throws an Error if given a malformed indexable string
214
- All other functions handle invalid inputs gracefully by normalizing them according to CouchDB rules
215
216
## Advanced Usage
217
218
### Creating Compound Sort Keys
219
220
```javascript
221
// Sort by age (ascending), then by gender (descending), then by name (ascending)
222
function createSortKey(person) {
223
return toIndexableString([
224
person.age,
225
!person.male, // Invert boolean for descending order
226
person.lastName,
227
person.firstName
228
]);
229
}
230
231
const people = [
232
{ age: 25, male: true, lastName: "Smith", firstName: "John" },
233
{ age: 25, male: false, lastName: "Smith", firstName: "Jane" },
234
{ age: 30, male: true, lastName: "Doe", firstName: "Bob" }
235
];
236
237
// Create sortable IDs
238
people.forEach(person => {
239
person._id = createSortKey(person);
240
});
241
242
// Now people can be sorted lexically by _id and maintain proper ordering
243
```
244
245
### Data Type Priority
246
247
Objects are sorted according to CouchDB collation rules:
248
249
1. **null** (includes undefined, NaN, Infinity, -Infinity)
250
2. **boolean** (false < true)
251
3. **number** (numeric comparison)
252
4. **string** (lexicographic comparison)
253
5. **array** (element-by-element comparison, shorter arrays first)
254
6. **object** (key-by-key comparison, fewer keys first)