@onchaindb/sdk 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.DS_Store +0 -0
- package/.claude/settings.local.json +8 -0
- package/.gitignore +5 -0
- package/.idea/.gitignore +5 -0
- package/.idea/compiler.xml +6 -0
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/jsLinters/eslint.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/prettier.xml +7 -0
- package/.idea/sdk.iml +12 -0
- package/.idea/vcs.xml +6 -0
- package/.idea/workspace.xml +257 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +11 -3
- package/dist/client.js.map +1 -1
- package/dist/database.d.ts +0 -20
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +0 -40
- package/dist/database.js.map +1 -1
- package/dist/query-sdk/tests/setup.d.ts +16 -0
- package/dist/query-sdk/tests/setup.d.ts.map +1 -0
- package/dist/query-sdk/tests/setup.js +49 -0
- package/dist/query-sdk/tests/setup.js.map +1 -0
- package/examples/basic-usage.ts +136 -0
- package/examples/blob-upload-example.ts +140 -0
- package/examples/collection-schema-example.ts +304 -0
- package/examples/server-side-joins.ts +201 -0
- package/examples/tweet-self-joins-example.ts +352 -0
- package/package-lock.json +3823 -0
- package/package.json +1 -1
- package/skills.md +1096 -0
- package/src/.env +1 -0
- package/src/batch.d.ts +121 -0
- package/src/batch.js +205 -0
- package/src/batch.ts +257 -0
- package/src/client.ts +1856 -0
- package/src/database.d.ts +268 -0
- package/src/database.js +294 -0
- package/src/database.ts +695 -0
- package/src/index.d.ts +160 -0
- package/src/index.js +186 -0
- package/src/index.ts +253 -0
- package/src/query-sdk/ConditionBuilder.ts +103 -0
- package/src/query-sdk/FieldConditionBuilder.ts +2 -0
- package/src/query-sdk/NestedBuilders.ts +186 -0
- package/src/query-sdk/OnChainDB.ts +294 -0
- package/src/query-sdk/QueryBuilder.ts +1191 -0
- package/src/query-sdk/QueryResult.ts +375 -0
- package/src/query-sdk/README.md +866 -0
- package/src/query-sdk/SelectionBuilder.ts +94 -0
- package/src/query-sdk/adapters/HttpClientAdapter.ts +249 -0
- package/src/query-sdk/dist/ConditionBuilder.d.ts +22 -0
- package/src/query-sdk/dist/ConditionBuilder.js +90 -0
- package/src/query-sdk/dist/FieldConditionBuilder.d.ts +1 -0
- package/src/query-sdk/dist/FieldConditionBuilder.js +6 -0
- package/src/query-sdk/dist/NestedBuilders.d.ts +43 -0
- package/src/query-sdk/dist/NestedBuilders.js +144 -0
- package/src/query-sdk/dist/OnChainDB.d.ts +19 -0
- package/src/query-sdk/dist/OnChainDB.js +123 -0
- package/src/query-sdk/dist/QueryBuilder.d.ts +70 -0
- package/src/query-sdk/dist/QueryBuilder.js +295 -0
- package/src/query-sdk/dist/QueryResult.d.ts +52 -0
- package/src/query-sdk/dist/QueryResult.js +293 -0
- package/src/query-sdk/dist/SelectionBuilder.d.ts +20 -0
- package/src/query-sdk/dist/SelectionBuilder.js +80 -0
- package/src/query-sdk/dist/adapters/HttpClientAdapter.d.ts +27 -0
- package/src/query-sdk/dist/adapters/HttpClientAdapter.js +170 -0
- package/src/query-sdk/dist/index.d.ts +36 -0
- package/src/query-sdk/dist/index.js +27 -0
- package/src/query-sdk/dist/operators.d.ts +56 -0
- package/src/query-sdk/dist/operators.js +289 -0
- package/src/query-sdk/dist/tests/setup.d.ts +15 -0
- package/src/query-sdk/dist/tests/setup.js +46 -0
- package/src/query-sdk/index.ts +59 -0
- package/src/query-sdk/jest.config.js +25 -0
- package/src/query-sdk/operators.ts +335 -0
- package/src/query-sdk/package.json +46 -0
- package/src/query-sdk/tests/FieldConditionBuilder.test.ts +84 -0
- package/src/query-sdk/tests/LogicalOperator.test.ts +85 -0
- package/src/query-sdk/tests/NestedBuilders.test.ts +321 -0
- package/src/query-sdk/tests/QueryBuilder.test.ts +348 -0
- package/src/query-sdk/tests/QueryResult.test.ts +464 -0
- package/src/query-sdk/tests/aggregations.test.ts +653 -0
- package/src/query-sdk/tests/comprehensive.test.ts +279 -0
- package/src/query-sdk/tests/integration.test.ts +608 -0
- package/src/query-sdk/tests/operators.test.ts +327 -0
- package/src/query-sdk/tests/setup.ts +59 -0
- package/src/query-sdk/tests/unit.test.ts +794 -0
- package/src/query-sdk/tsconfig.json +26 -0
- package/src/query-sdk/yarn.lock +3092 -0
- package/src/types.d.ts +131 -0
- package/src/types.js +46 -0
- package/src/types.ts +534 -0
- package/src/x402/index.ts +12 -0
- package/src/x402/types.ts +250 -0
- package/src/x402/utils.ts +332 -0
- package/tsconfig.json +20 -0
- package/yarn.lock +2309 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
// Query result utilities class matching Rust SDK functionality
|
|
2
|
+
export class QueryResult<T = any> {
|
|
3
|
+
public data: T[];
|
|
4
|
+
|
|
5
|
+
constructor(data: T[]) {
|
|
6
|
+
this.data = Array.isArray(data) ? data : [data];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// ===== BASIC UTILITIES =====
|
|
10
|
+
|
|
11
|
+
len(): number {
|
|
12
|
+
return this.data.length;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
length(): number {
|
|
16
|
+
return this.len();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
isEmpty(): boolean {
|
|
20
|
+
return this.data.length === 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
first(): T | undefined {
|
|
24
|
+
return this.data[0];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
last(): T | undefined {
|
|
28
|
+
return this.data[this.data.length - 1];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get(index: number): T | undefined {
|
|
32
|
+
return this.data[index];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ===== ITERATION UTILITIES =====
|
|
36
|
+
|
|
37
|
+
any(predicate: (item: T) => boolean): boolean {
|
|
38
|
+
return this.data.some(predicate);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
all(predicate: (item: T) => boolean): boolean {
|
|
42
|
+
return this.data.every(predicate);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
find(predicate: (item: T) => boolean): T | undefined {
|
|
46
|
+
return this.data.find(predicate);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
filter(predicate: (item: T) => boolean): T[] {
|
|
50
|
+
return this.data.filter(predicate);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
map<U>(transform: (item: T) => U): U[] {
|
|
54
|
+
return this.data.map(transform);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
forEach(callback: (item: T, index: number) => void): void {
|
|
58
|
+
this.data.forEach(callback);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
reduce<U>(callback: (accumulator: U, item: T, index: number) => U, initialValue: U): U {
|
|
62
|
+
return this.data.reduce(callback, initialValue);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ===== AGGREGATION UTILITIES =====
|
|
66
|
+
|
|
67
|
+
groupBy(field: string): Record<string, T[]> {
|
|
68
|
+
const groups: Record<string, T[]> = {};
|
|
69
|
+
|
|
70
|
+
this.data.forEach(item => {
|
|
71
|
+
const key = this.getNestedValue(item, field);
|
|
72
|
+
const keyString = String(key ?? 'null');
|
|
73
|
+
|
|
74
|
+
if (!groups[keyString]) {
|
|
75
|
+
groups[keyString] = [];
|
|
76
|
+
}
|
|
77
|
+
groups[keyString].push(item);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return groups;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Pluck values from a specific field across all records
|
|
84
|
+
pluck(field: string): any[] {
|
|
85
|
+
return this.data.map(item => this.getNestedValue(item, field));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pluckStrings(field: string): (string | null)[] {
|
|
89
|
+
return this.data.map(item => {
|
|
90
|
+
const value = this.getNestedValue(item, field);
|
|
91
|
+
return typeof value === 'string' ? value : (value != null ? String(value) : null);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
pluckNumbers(field: string): (number | null)[] {
|
|
96
|
+
return this.data.map(item => {
|
|
97
|
+
const value = this.getNestedValue(item, field);
|
|
98
|
+
if (typeof value === 'number' && !isNaN(value)) {
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
const parsed = Number(value);
|
|
102
|
+
return !isNaN(parsed) ? parsed : null;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ===== NUMERIC SUMMARY =====
|
|
107
|
+
|
|
108
|
+
summarizeNumeric(field: string): NumericSummary | null {
|
|
109
|
+
const numbers = this.pluckNumbers(field).filter(n => n !== null) as number[];
|
|
110
|
+
|
|
111
|
+
if (numbers.length === 0) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
|
116
|
+
const mean = sum / numbers.length;
|
|
117
|
+
const min = Math.min(...numbers);
|
|
118
|
+
const max = Math.max(...numbers);
|
|
119
|
+
|
|
120
|
+
// Calculate median
|
|
121
|
+
const sortedNumbers = [...numbers].sort((a, b) => a - b);
|
|
122
|
+
const mid = Math.floor(sortedNumbers.length / 2);
|
|
123
|
+
const median = sortedNumbers.length % 2 !== 0
|
|
124
|
+
? sortedNumbers[mid]
|
|
125
|
+
: (sortedNumbers[mid - 1] + sortedNumbers[mid]) / 2;
|
|
126
|
+
|
|
127
|
+
// Calculate standard deviation
|
|
128
|
+
const variance = numbers.reduce((acc, n) => acc + Math.pow(n - mean, 2), 0) / numbers.length;
|
|
129
|
+
const standardDeviation = Math.sqrt(variance);
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
count: numbers.length,
|
|
133
|
+
sum,
|
|
134
|
+
mean,
|
|
135
|
+
median,
|
|
136
|
+
min,
|
|
137
|
+
max,
|
|
138
|
+
standardDeviation,
|
|
139
|
+
variance
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ===== SORTING =====
|
|
144
|
+
|
|
145
|
+
sortBy(field: string, ascending: boolean = true): T[] {
|
|
146
|
+
const sorted = [...this.data].sort((a, b) => {
|
|
147
|
+
const valueA = this.getNestedValue(a, field);
|
|
148
|
+
const valueB = this.getNestedValue(b, field);
|
|
149
|
+
|
|
150
|
+
// Handle null/undefined values
|
|
151
|
+
if (valueA == null && valueB == null) return 0;
|
|
152
|
+
if (valueA == null) return ascending ? -1 : 1;
|
|
153
|
+
if (valueB == null) return ascending ? 1 : -1;
|
|
154
|
+
|
|
155
|
+
// Compare values
|
|
156
|
+
let comparison = 0;
|
|
157
|
+
if (valueA < valueB) comparison = -1;
|
|
158
|
+
else if (valueA > valueB) comparison = 1;
|
|
159
|
+
|
|
160
|
+
return ascending ? comparison : -comparison;
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
return sorted;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Multiple field sorting
|
|
167
|
+
sortByMultiple(fields: Array<{field: string, ascending?: boolean}>): T[] {
|
|
168
|
+
const sorted = [...this.data].sort((a, b) => {
|
|
169
|
+
for (const {field, ascending = true} of fields) {
|
|
170
|
+
const valueA = this.getNestedValue(a, field);
|
|
171
|
+
const valueB = this.getNestedValue(b, field);
|
|
172
|
+
|
|
173
|
+
// Handle null/undefined values
|
|
174
|
+
if (valueA == null && valueB == null) continue;
|
|
175
|
+
if (valueA == null) return ascending ? -1 : 1;
|
|
176
|
+
if (valueB == null) return ascending ? 1 : -1;
|
|
177
|
+
|
|
178
|
+
// Compare values
|
|
179
|
+
let comparison = 0;
|
|
180
|
+
if (valueA < valueB) comparison = -1;
|
|
181
|
+
else if (valueA > valueB) comparison = 1;
|
|
182
|
+
|
|
183
|
+
if (comparison !== 0) {
|
|
184
|
+
return ascending ? comparison : -comparison;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return 0;
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
return sorted;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ===== PAGINATION =====
|
|
194
|
+
|
|
195
|
+
paginate(page: number, pageSize: number): T[] {
|
|
196
|
+
const startIndex = (page - 1) * pageSize;
|
|
197
|
+
const endIndex = startIndex + pageSize;
|
|
198
|
+
return this.data.slice(startIndex, endIndex);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
chunk(size: number): T[][] {
|
|
202
|
+
const chunks: T[][] = [];
|
|
203
|
+
for (let i = 0; i < this.data.length; i += size) {
|
|
204
|
+
chunks.push(this.data.slice(i, i + size));
|
|
205
|
+
}
|
|
206
|
+
return chunks;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ===== DISTINCT/UNIQUE =====
|
|
210
|
+
|
|
211
|
+
distinctBy(field: string): T[] {
|
|
212
|
+
const seen = new Set();
|
|
213
|
+
return this.data.filter(item => {
|
|
214
|
+
const value = this.getNestedValue(item, field);
|
|
215
|
+
const key = String(value);
|
|
216
|
+
if (seen.has(key)) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
seen.add(key);
|
|
220
|
+
return true;
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
unique(): T[] {
|
|
225
|
+
return [...new Set(this.data)];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ===== STATISTICAL FUNCTIONS =====
|
|
229
|
+
|
|
230
|
+
count(predicate?: (item: T) => boolean): number {
|
|
231
|
+
if (predicate) {
|
|
232
|
+
return this.data.filter(predicate).length;
|
|
233
|
+
}
|
|
234
|
+
return this.data.length;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
countBy(field: string): Record<string, number> {
|
|
238
|
+
const counts: Record<string, number> = {};
|
|
239
|
+
|
|
240
|
+
this.data.forEach(item => {
|
|
241
|
+
const key = String(this.getNestedValue(item, field) ?? 'null');
|
|
242
|
+
counts[key] = (counts[key] || 0) + 1;
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
return counts;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// ===== UTILITY METHODS =====
|
|
249
|
+
|
|
250
|
+
// Get nested field value using dot notation
|
|
251
|
+
private getNestedValue(obj: any, path: string): any {
|
|
252
|
+
return path.split('.').reduce((current, key) => {
|
|
253
|
+
return current && typeof current === 'object' ? current[key] : undefined;
|
|
254
|
+
}, obj);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ===== TRANSFORMATION =====
|
|
258
|
+
|
|
259
|
+
toArray(): T[] {
|
|
260
|
+
return [...this.data];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
toJSON(): string {
|
|
264
|
+
return JSON.stringify(this.data);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Convert to QueryResult with different type
|
|
268
|
+
cast<U>(): QueryResult<U> {
|
|
269
|
+
return new QueryResult(this.data as unknown as U[]);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// ===== JOINING (similar to SQL joins) =====
|
|
273
|
+
|
|
274
|
+
innerJoin<U>(
|
|
275
|
+
other: QueryResult<U>,
|
|
276
|
+
thisKey: string,
|
|
277
|
+
otherKey: string
|
|
278
|
+
): Array<T & U> {
|
|
279
|
+
const results: Array<T & U> = [];
|
|
280
|
+
|
|
281
|
+
this.data.forEach(thisItem => {
|
|
282
|
+
const thisValue = this.getNestedValue(thisItem, thisKey);
|
|
283
|
+
other.data.forEach(otherItem => {
|
|
284
|
+
const otherValue = this.getNestedValue(otherItem, otherKey);
|
|
285
|
+
if (thisValue === otherValue) {
|
|
286
|
+
results.push({...thisItem, ...otherItem});
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
return results;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
leftJoin<U>(
|
|
295
|
+
other: QueryResult<U>,
|
|
296
|
+
thisKey: string,
|
|
297
|
+
otherKey: string
|
|
298
|
+
): Array<T & Partial<U>> {
|
|
299
|
+
const results: Array<T & Partial<U>> = [];
|
|
300
|
+
|
|
301
|
+
this.data.forEach(thisItem => {
|
|
302
|
+
const thisValue = this.getNestedValue(thisItem, thisKey);
|
|
303
|
+
const matches = other.data.filter(otherItem =>
|
|
304
|
+
this.getNestedValue(otherItem, otherKey) === thisValue
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
if (matches.length > 0) {
|
|
308
|
+
matches.forEach(match => {
|
|
309
|
+
results.push({...thisItem, ...match});
|
|
310
|
+
});
|
|
311
|
+
} else {
|
|
312
|
+
results.push({...thisItem} as T & Partial<U>);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
return results;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// ===== EXPORT/FORMATTING =====
|
|
320
|
+
|
|
321
|
+
toCsv(delimiter: string = ','): string {
|
|
322
|
+
if (this.data.length === 0) return '';
|
|
323
|
+
|
|
324
|
+
// Get all unique keys from all objects
|
|
325
|
+
const allKeys = new Set<string>();
|
|
326
|
+
this.data.forEach(item => {
|
|
327
|
+
if (typeof item === 'object' && item !== null) {
|
|
328
|
+
Object.keys(item).forEach(key => allKeys.add(key));
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
const headers = Array.from(allKeys);
|
|
333
|
+
const csvRows = [headers.join(delimiter)];
|
|
334
|
+
|
|
335
|
+
this.data.forEach(item => {
|
|
336
|
+
const row = headers.map(header => {
|
|
337
|
+
const value = typeof item === 'object' && item !== null ? (item as any)[header] : '';
|
|
338
|
+
// Escape values that contain the delimiter
|
|
339
|
+
const stringValue = String(value ?? '');
|
|
340
|
+
return stringValue.includes(delimiter) ? `"${stringValue}"` : stringValue;
|
|
341
|
+
});
|
|
342
|
+
csvRows.push(row.join(delimiter));
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
return csvRows.join('\n');
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// ===== DEBUGGING =====
|
|
349
|
+
|
|
350
|
+
inspect(limit?: number): void {
|
|
351
|
+
const itemsToShow = limit ? this.data.slice(0, limit) : this.data;
|
|
352
|
+
console.log('QueryResult:', {
|
|
353
|
+
count: this.data.length,
|
|
354
|
+
showing: itemsToShow.length,
|
|
355
|
+
data: itemsToShow
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Numeric summary interface
|
|
361
|
+
export interface NumericSummary {
|
|
362
|
+
count: number;
|
|
363
|
+
sum: number;
|
|
364
|
+
mean: number;
|
|
365
|
+
median: number;
|
|
366
|
+
min: number;
|
|
367
|
+
max: number;
|
|
368
|
+
standardDeviation: number;
|
|
369
|
+
variance: number;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Utility function to create QueryResult
|
|
373
|
+
export function createQueryResult<T>(data: T[]): QueryResult<T> {
|
|
374
|
+
return new QueryResult(data);
|
|
375
|
+
}
|