@onchaindb/sdk 0.4.5 → 2.0.0

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.
Files changed (117) hide show
  1. package/.claude/settings.local.json +10 -2
  2. package/README.md +422 -355
  3. package/dist/batch.d.ts +1 -10
  4. package/dist/batch.d.ts.map +1 -1
  5. package/dist/batch.js +4 -26
  6. package/dist/batch.js.map +1 -1
  7. package/dist/client.d.ts +31 -46
  8. package/dist/client.d.ts.map +1 -1
  9. package/dist/client.js +222 -357
  10. package/dist/client.js.map +1 -1
  11. package/dist/database.d.ts +14 -131
  12. package/dist/database.d.ts.map +1 -1
  13. package/dist/database.js +35 -131
  14. package/dist/database.js.map +1 -1
  15. package/dist/index.d.ts +10 -13
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +4 -18
  18. package/dist/index.js.map +1 -1
  19. package/dist/query-sdk/ConditionBuilder.d.ts +3 -11
  20. package/dist/query-sdk/ConditionBuilder.d.ts.map +1 -1
  21. package/dist/query-sdk/ConditionBuilder.js +10 -48
  22. package/dist/query-sdk/ConditionBuilder.js.map +1 -1
  23. package/dist/query-sdk/NestedBuilders.d.ts +33 -30
  24. package/dist/query-sdk/NestedBuilders.d.ts.map +1 -1
  25. package/dist/query-sdk/NestedBuilders.js +46 -43
  26. package/dist/query-sdk/NestedBuilders.js.map +1 -1
  27. package/{src/query-sdk/dist/OnChainDB.d.ts → dist/query-sdk/OnDB.d.ts} +10 -2
  28. package/dist/query-sdk/OnDB.d.ts.map +1 -0
  29. package/{src/query-sdk/dist/OnChainDB.js → dist/query-sdk/OnDB.js} +86 -18
  30. package/dist/query-sdk/OnDB.js.map +1 -0
  31. package/dist/query-sdk/QueryBuilder.d.ts +4 -2
  32. package/dist/query-sdk/QueryBuilder.d.ts.map +1 -1
  33. package/dist/query-sdk/QueryBuilder.js +47 -169
  34. package/dist/query-sdk/QueryBuilder.js.map +1 -1
  35. package/dist/query-sdk/QueryResult.d.ts +0 -38
  36. package/dist/query-sdk/QueryResult.d.ts.map +1 -1
  37. package/dist/query-sdk/QueryResult.js +1 -227
  38. package/dist/query-sdk/QueryResult.js.map +1 -1
  39. package/dist/query-sdk/index.d.ts +2 -2
  40. package/dist/query-sdk/index.d.ts.map +1 -1
  41. package/dist/query-sdk/index.js +3 -3
  42. package/dist/query-sdk/index.js.map +1 -1
  43. package/dist/query-sdk/operators.d.ts +32 -28
  44. package/dist/query-sdk/operators.d.ts.map +1 -1
  45. package/dist/query-sdk/operators.js +45 -155
  46. package/dist/query-sdk/operators.js.map +1 -1
  47. package/dist/types.d.ts +159 -36
  48. package/dist/types.d.ts.map +1 -1
  49. package/dist/types.js +8 -8
  50. package/dist/types.js.map +1 -1
  51. package/dist/x402/types.d.ts +1 -1
  52. package/dist/x402/types.d.ts.map +1 -1
  53. package/dist/x402/utils.js +2 -2
  54. package/dist/x402/utils.js.map +1 -1
  55. package/jest.config.js +4 -0
  56. package/package.json +1 -1
  57. package/skills.md +0 -1
  58. package/src/batch.d.ts +3 -3
  59. package/src/batch.js +1 -1
  60. package/src/client.ts +287 -823
  61. package/src/database.d.ts +1 -1
  62. package/src/database.js +4 -4
  63. package/src/database.ts +71 -494
  64. package/src/index.d.ts +18 -18
  65. package/src/index.js +16 -16
  66. package/src/index.ts +44 -198
  67. package/src/query-sdk/ConditionBuilder.ts +37 -89
  68. package/src/query-sdk/NestedBuilders.ts +90 -92
  69. package/src/query-sdk/{OnChainDB.ts → OnDB.ts} +1 -1
  70. package/src/query-sdk/QueryBuilder.ts +59 -218
  71. package/src/query-sdk/QueryResult.ts +4 -330
  72. package/src/query-sdk/README.md +218 -587
  73. package/src/query-sdk/index.ts +2 -2
  74. package/src/query-sdk/operators.ts +91 -200
  75. package/src/query-sdk/tests/FieldConditionBuilder.test.ts +70 -71
  76. package/src/query-sdk/tests/LogicalOperator.test.ts +43 -82
  77. package/src/query-sdk/tests/NestedBuilders.test.ts +229 -309
  78. package/src/query-sdk/tests/QueryBuilder.test.ts +5 -5
  79. package/src/query-sdk/tests/QueryResult.test.ts +41 -435
  80. package/src/query-sdk/tests/comprehensive.test.ts +4 -185
  81. package/src/tests/client-requests.test.ts +280 -0
  82. package/src/tests/client-validation.test.ts +80 -0
  83. package/src/types.d.ts +6 -6
  84. package/src/types.js +8 -8
  85. package/src/types.ts +239 -54
  86. package/src/x402/types.ts +3 -3
  87. package/src/x402/utils.ts +3 -3
  88. package/examples/blob-upload-example.ts +0 -140
  89. package/src/batch.ts +0 -257
  90. package/src/query-sdk/dist/ConditionBuilder.d.ts +0 -22
  91. package/src/query-sdk/dist/ConditionBuilder.js +0 -90
  92. package/src/query-sdk/dist/FieldConditionBuilder.d.ts +0 -1
  93. package/src/query-sdk/dist/FieldConditionBuilder.js +0 -6
  94. package/src/query-sdk/dist/NestedBuilders.d.ts +0 -43
  95. package/src/query-sdk/dist/NestedBuilders.js +0 -144
  96. package/src/query-sdk/dist/QueryBuilder.d.ts +0 -70
  97. package/src/query-sdk/dist/QueryBuilder.js +0 -295
  98. package/src/query-sdk/dist/QueryResult.d.ts +0 -52
  99. package/src/query-sdk/dist/QueryResult.js +0 -293
  100. package/src/query-sdk/dist/SelectionBuilder.d.ts +0 -20
  101. package/src/query-sdk/dist/SelectionBuilder.js +0 -80
  102. package/src/query-sdk/dist/adapters/HttpClientAdapter.d.ts +0 -27
  103. package/src/query-sdk/dist/adapters/HttpClientAdapter.js +0 -170
  104. package/src/query-sdk/dist/index.d.ts +0 -36
  105. package/src/query-sdk/dist/index.js +0 -27
  106. package/src/query-sdk/dist/operators.d.ts +0 -56
  107. package/src/query-sdk/dist/operators.js +0 -289
  108. package/src/query-sdk/dist/tests/setup.d.ts +0 -15
  109. package/src/query-sdk/dist/tests/setup.js +0 -46
  110. package/src/query-sdk/jest.config.js +0 -25
  111. package/src/query-sdk/package.json +0 -46
  112. package/src/query-sdk/tests/aggregations.test.ts +0 -653
  113. package/src/query-sdk/tests/integration.test.ts +0 -608
  114. package/src/query-sdk/tests/operators.test.ts +0 -327
  115. package/src/query-sdk/tests/unit.test.ts +0 -794
  116. package/src/query-sdk/tsconfig.json +0 -26
  117. package/src/query-sdk/yarn.lock +0 -3092
@@ -1,295 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WhereClause = exports.QueryBuilder = void 0;
4
- const operators_1 = require("./operators");
5
- const SelectionBuilder_1 = require("./SelectionBuilder");
6
- const ConditionBuilder_1 = require("./ConditionBuilder");
7
- // Main query builder providing fluent API for building queries
8
- class QueryBuilder {
9
- constructor(httpClient, serverUrl, app) {
10
- this.httpClient = httpClient;
11
- this.serverUrl = serverUrl;
12
- this.app = app;
13
- }
14
- static new(httpClient, serverUrl, app) {
15
- return new QueryBuilder(httpClient, serverUrl, app);
16
- }
17
- // Set HTTP client and server URL (for method chaining)
18
- withHttpClient(httpClient) {
19
- this.httpClient = httpClient;
20
- return this;
21
- }
22
- withServerUrl(serverUrl) {
23
- this.serverUrl = serverUrl;
24
- return this;
25
- }
26
- // Build find conditions using a builder function
27
- find(builderFn) {
28
- const conditionBuilder = new ConditionBuilder_1.ConditionBuilder();
29
- this.findConditions = builderFn(conditionBuilder);
30
- return this;
31
- }
32
- collection(s) {
33
- this.collectionName = s;
34
- return this;
35
- }
36
- // Simple field condition (equivalent to Rust's where_field)
37
- whereField(fieldName) {
38
- return new WhereClause(this, fieldName);
39
- }
40
- // Build selections using a builder function
41
- select(builderFn) {
42
- const selectionBuilder = new SelectionBuilder_1.SelectionBuilder();
43
- builderFn(selectionBuilder);
44
- this.selections = selectionBuilder.build();
45
- return this;
46
- }
47
- // Select specific fields by name
48
- selectFields(fields) {
49
- const selectionBuilder = new SelectionBuilder_1.SelectionBuilder();
50
- selectionBuilder.fields(fields);
51
- this.selections = selectionBuilder.build();
52
- return this;
53
- }
54
- // Select all fields (no field filtering)
55
- selectAll() {
56
- this.selections = SelectionBuilder_1.SelectionBuilder.all();
57
- return this;
58
- }
59
- // Set field mapping for the query
60
- withFieldMap(fieldMap) {
61
- this.fieldMap = fieldMap;
62
- return this;
63
- }
64
- // Set limit for results
65
- limit(limit) {
66
- this.limitValue = limit;
67
- return this;
68
- }
69
- // Set offset for results
70
- offset(offset) {
71
- this.offsetValue = offset;
72
- return this;
73
- }
74
- // Set sorting fields
75
- orderBy(fields) {
76
- this.sortBy = fields;
77
- return this;
78
- }
79
- // Execute the query via HTTP
80
- async execute() {
81
- if (!this.httpClient) {
82
- throw new Error('HTTP client is required for query execution');
83
- }
84
- if (!this.serverUrl) {
85
- throw new Error('Server URL is required for query execution');
86
- }
87
- const queryValue = this.buildQueryValue();
88
- const request = {
89
- ...queryValue,
90
- limit: this.limitValue,
91
- offset: this.offsetValue,
92
- sortBy: this.sortBy,
93
- root: `${this.app}::${this.collectionName}`
94
- };
95
- try {
96
- const response = await this.httpClient.post(`${this.serverUrl}/list`, request, { 'Content-Type': 'application/json' });
97
- return response?.data || {
98
- records: [],
99
- limit: 0,
100
- page: 0,
101
- total: 0,
102
- };
103
- }
104
- catch (error) {
105
- throw new Error(`Query execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
106
- }
107
- }
108
- // Check if the query is valid (has required components)
109
- isValid() {
110
- // A query is valid if it has either find conditions or selections
111
- return this.findConditions !== undefined || this.selections !== undefined;
112
- }
113
- // Build raw query JSON (useful for debugging)
114
- buildRawQuery() {
115
- return {
116
- ...this.buildQueryValue(),
117
- limit: this.limitValue,
118
- offset: this.offsetValue,
119
- sortBy: this.sortBy
120
- };
121
- }
122
- // Clone the query builder
123
- clone() {
124
- const cloned = new QueryBuilder(this.httpClient, this.serverUrl);
125
- cloned.findConditions = this.findConditions;
126
- cloned.selections = this.selections ? { ...this.selections } : undefined;
127
- cloned.fieldMap = this.fieldMap ? { ...this.fieldMap } : undefined;
128
- cloned.limitValue = this.limitValue;
129
- cloned.offsetValue = this.offsetValue;
130
- cloned.sortBy = this.sortBy;
131
- return cloned;
132
- }
133
- // Build the query value object for HTTP requests
134
- buildQueryValue() {
135
- const find = this.findConditions ? this.findConditions.toComposable() : {};
136
- const select = this.selections || SelectionBuilder_1.SelectionBuilder.all();
137
- return {
138
- find,
139
- select
140
- };
141
- }
142
- }
143
- exports.QueryBuilder = QueryBuilder;
144
- // Helper class for building where clauses with method chaining
145
- class WhereClause {
146
- constructor(queryBuilder, fieldName) {
147
- this.queryBuilder = queryBuilder;
148
- this.fieldName = fieldName;
149
- }
150
- equals(value) {
151
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).equals(value);
152
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
153
- return this.queryBuilder;
154
- }
155
- notEquals(value) {
156
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).notEquals(value);
157
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
158
- return this.queryBuilder;
159
- }
160
- greaterThan(value) {
161
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).greaterThan(value);
162
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
163
- return this.queryBuilder;
164
- }
165
- greaterThanOrEqual(value) {
166
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).greaterThanOrEqual(value);
167
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
168
- return this.queryBuilder;
169
- }
170
- lessThan(value) {
171
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).lessThan(value);
172
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
173
- return this.queryBuilder;
174
- }
175
- lessThanOrEqual(value) {
176
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).lessThanOrEqual(value);
177
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
178
- return this.queryBuilder;
179
- }
180
- contains(value) {
181
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).contains(value);
182
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
183
- return this.queryBuilder;
184
- }
185
- startsWith(value) {
186
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).startsWith(value);
187
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
188
- return this.queryBuilder;
189
- }
190
- endsWith(value) {
191
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).endsWith(value);
192
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
193
- return this.queryBuilder;
194
- }
195
- in(values) {
196
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).in(values);
197
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
198
- return this.queryBuilder;
199
- }
200
- notIn(values) {
201
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).notIn(values);
202
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
203
- return this.queryBuilder;
204
- }
205
- exists() {
206
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).exists();
207
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
208
- return this.queryBuilder;
209
- }
210
- notExists() {
211
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).notExists();
212
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
213
- return this.queryBuilder;
214
- }
215
- isNull() {
216
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).isNull();
217
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
218
- return this.queryBuilder;
219
- }
220
- isNotNull() {
221
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).isNotNull();
222
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
223
- return this.queryBuilder;
224
- }
225
- regExpMatches(pattern) {
226
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).regExpMatches(pattern);
227
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
228
- return this.queryBuilder;
229
- }
230
- includesCaseInsensitive(value) {
231
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).includesCaseInsensitive(value);
232
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
233
- return this.queryBuilder;
234
- }
235
- startsWithCaseInsensitive(value) {
236
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).startsWithCaseInsensitive(value);
237
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
238
- return this.queryBuilder;
239
- }
240
- endsWithCaseInsensitive(value) {
241
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).endsWithCaseInsensitive(value);
242
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
243
- return this.queryBuilder;
244
- }
245
- // ===== IP OPERATORS =====
246
- isLocalIp() {
247
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).isLocalIp();
248
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
249
- return this.queryBuilder;
250
- }
251
- isExternalIp() {
252
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).isExternalIp();
253
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
254
- return this.queryBuilder;
255
- }
256
- // ===== MISC OPERATORS =====
257
- b64(value) {
258
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).b64(value);
259
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
260
- return this.queryBuilder;
261
- }
262
- inDataset(dataset) {
263
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).inDataset(dataset);
264
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
265
- return this.queryBuilder;
266
- }
267
- inCountry(countryCode) {
268
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).inCountry(countryCode);
269
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
270
- return this.queryBuilder;
271
- }
272
- cidr(cidr) {
273
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).cidr(cidr);
274
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
275
- return this.queryBuilder;
276
- }
277
- // ===== BETWEEN OPERATOR =====
278
- between(min, max) {
279
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).between(min, max);
280
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
281
- return this.queryBuilder;
282
- }
283
- // ===== CONVENIENCE METHODS =====
284
- isTrue() {
285
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).isTrue();
286
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
287
- return this.queryBuilder;
288
- }
289
- isFalse() {
290
- const condition = new operators_1.FieldConditionBuilder(this.fieldName).isFalse();
291
- this.queryBuilder.findConditions = operators_1.LogicalOperator.Condition(condition);
292
- return this.queryBuilder;
293
- }
294
- }
295
- exports.WhereClause = WhereClause;
@@ -1,52 +0,0 @@
1
- export declare class QueryResult<T = any> {
2
- data: T[];
3
- constructor(data: T[]);
4
- len(): number;
5
- length(): number;
6
- isEmpty(): boolean;
7
- first(): T | undefined;
8
- last(): T | undefined;
9
- get(index: number): T | undefined;
10
- any(predicate: (item: T) => boolean): boolean;
11
- all(predicate: (item: T) => boolean): boolean;
12
- find(predicate: (item: T) => boolean): T | undefined;
13
- filter(predicate: (item: T) => boolean): T[];
14
- map<U>(transform: (item: T) => U): U[];
15
- forEach(callback: (item: T, index: number) => void): void;
16
- reduce<U>(callback: (accumulator: U, item: T, index: number) => U, initialValue: U): U;
17
- groupBy(field: string): Record<string, T[]>;
18
- pluck(field: string): any[];
19
- pluckStrings(field: string): (string | null)[];
20
- pluckNumbers(field: string): (number | null)[];
21
- summarizeNumeric(field: string): NumericSummary | null;
22
- sortBy(field: string, ascending?: boolean): T[];
23
- sortByMultiple(fields: Array<{
24
- field: string;
25
- ascending?: boolean;
26
- }>): T[];
27
- paginate(page: number, pageSize: number): T[];
28
- chunk(size: number): T[][];
29
- distinctBy(field: string): T[];
30
- unique(): T[];
31
- count(predicate?: (item: T) => boolean): number;
32
- countBy(field: string): Record<string, number>;
33
- private getNestedValue;
34
- toArray(): T[];
35
- toJSON(): string;
36
- cast<U>(): QueryResult<U>;
37
- innerJoin<U>(other: QueryResult<U>, thisKey: string, otherKey: string): Array<T & U>;
38
- leftJoin<U>(other: QueryResult<U>, thisKey: string, otherKey: string): Array<T & Partial<U>>;
39
- toCsv(delimiter?: string): string;
40
- inspect(limit?: number): void;
41
- }
42
- export interface NumericSummary {
43
- count: number;
44
- sum: number;
45
- mean: number;
46
- median: number;
47
- min: number;
48
- max: number;
49
- standardDeviation: number;
50
- variance: number;
51
- }
52
- export declare function createQueryResult<T>(data: T[]): QueryResult<T>;
@@ -1,293 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.QueryResult = void 0;
4
- exports.createQueryResult = createQueryResult;
5
- // Query result utilities class matching Rust SDK functionality
6
- class QueryResult {
7
- constructor(data) {
8
- this.data = Array.isArray(data) ? data : [data];
9
- }
10
- // ===== BASIC UTILITIES =====
11
- len() {
12
- return this.data.length;
13
- }
14
- length() {
15
- return this.len();
16
- }
17
- isEmpty() {
18
- return this.data.length === 0;
19
- }
20
- first() {
21
- return this.data[0];
22
- }
23
- last() {
24
- return this.data[this.data.length - 1];
25
- }
26
- get(index) {
27
- return this.data[index];
28
- }
29
- // ===== ITERATION UTILITIES =====
30
- any(predicate) {
31
- return this.data.some(predicate);
32
- }
33
- all(predicate) {
34
- return this.data.every(predicate);
35
- }
36
- find(predicate) {
37
- return this.data.find(predicate);
38
- }
39
- filter(predicate) {
40
- return this.data.filter(predicate);
41
- }
42
- map(transform) {
43
- return this.data.map(transform);
44
- }
45
- forEach(callback) {
46
- this.data.forEach(callback);
47
- }
48
- reduce(callback, initialValue) {
49
- return this.data.reduce(callback, initialValue);
50
- }
51
- // ===== AGGREGATION UTILITIES =====
52
- groupBy(field) {
53
- const groups = {};
54
- this.data.forEach(item => {
55
- const key = this.getNestedValue(item, field);
56
- const keyString = String(key ?? 'null');
57
- if (!groups[keyString]) {
58
- groups[keyString] = [];
59
- }
60
- groups[keyString].push(item);
61
- });
62
- return groups;
63
- }
64
- // Pluck values from a specific field across all records
65
- pluck(field) {
66
- return this.data.map(item => this.getNestedValue(item, field));
67
- }
68
- pluckStrings(field) {
69
- return this.data.map(item => {
70
- const value = this.getNestedValue(item, field);
71
- return typeof value === 'string' ? value : (value != null ? String(value) : null);
72
- });
73
- }
74
- pluckNumbers(field) {
75
- return this.data.map(item => {
76
- const value = this.getNestedValue(item, field);
77
- if (typeof value === 'number' && !isNaN(value)) {
78
- return value;
79
- }
80
- const parsed = Number(value);
81
- return !isNaN(parsed) ? parsed : null;
82
- });
83
- }
84
- // ===== NUMERIC SUMMARY =====
85
- summarizeNumeric(field) {
86
- const numbers = this.pluckNumbers(field).filter(n => n !== null);
87
- if (numbers.length === 0) {
88
- return null;
89
- }
90
- const sum = numbers.reduce((acc, n) => acc + n, 0);
91
- const mean = sum / numbers.length;
92
- const min = Math.min(...numbers);
93
- const max = Math.max(...numbers);
94
- // Calculate median
95
- const sortedNumbers = [...numbers].sort((a, b) => a - b);
96
- const mid = Math.floor(sortedNumbers.length / 2);
97
- const median = sortedNumbers.length % 2 !== 0
98
- ? sortedNumbers[mid]
99
- : (sortedNumbers[mid - 1] + sortedNumbers[mid]) / 2;
100
- // Calculate standard deviation
101
- const variance = numbers.reduce((acc, n) => acc + Math.pow(n - mean, 2), 0) / numbers.length;
102
- const standardDeviation = Math.sqrt(variance);
103
- return {
104
- count: numbers.length,
105
- sum,
106
- mean,
107
- median,
108
- min,
109
- max,
110
- standardDeviation,
111
- variance
112
- };
113
- }
114
- // ===== SORTING =====
115
- sortBy(field, ascending = true) {
116
- const sorted = [...this.data].sort((a, b) => {
117
- const valueA = this.getNestedValue(a, field);
118
- const valueB = this.getNestedValue(b, field);
119
- // Handle null/undefined values
120
- if (valueA == null && valueB == null)
121
- return 0;
122
- if (valueA == null)
123
- return ascending ? -1 : 1;
124
- if (valueB == null)
125
- return ascending ? 1 : -1;
126
- // Compare values
127
- let comparison = 0;
128
- if (valueA < valueB)
129
- comparison = -1;
130
- else if (valueA > valueB)
131
- comparison = 1;
132
- return ascending ? comparison : -comparison;
133
- });
134
- return sorted;
135
- }
136
- // Multiple field sorting
137
- sortByMultiple(fields) {
138
- const sorted = [...this.data].sort((a, b) => {
139
- for (const { field, ascending = true } of fields) {
140
- const valueA = this.getNestedValue(a, field);
141
- const valueB = this.getNestedValue(b, field);
142
- // Handle null/undefined values
143
- if (valueA == null && valueB == null)
144
- continue;
145
- if (valueA == null)
146
- return ascending ? -1 : 1;
147
- if (valueB == null)
148
- return ascending ? 1 : -1;
149
- // Compare values
150
- let comparison = 0;
151
- if (valueA < valueB)
152
- comparison = -1;
153
- else if (valueA > valueB)
154
- comparison = 1;
155
- if (comparison !== 0) {
156
- return ascending ? comparison : -comparison;
157
- }
158
- }
159
- return 0;
160
- });
161
- return sorted;
162
- }
163
- // ===== PAGINATION =====
164
- paginate(page, pageSize) {
165
- const startIndex = (page - 1) * pageSize;
166
- const endIndex = startIndex + pageSize;
167
- return this.data.slice(startIndex, endIndex);
168
- }
169
- chunk(size) {
170
- const chunks = [];
171
- for (let i = 0; i < this.data.length; i += size) {
172
- chunks.push(this.data.slice(i, i + size));
173
- }
174
- return chunks;
175
- }
176
- // ===== DISTINCT/UNIQUE =====
177
- distinctBy(field) {
178
- const seen = new Set();
179
- return this.data.filter(item => {
180
- const value = this.getNestedValue(item, field);
181
- const key = String(value);
182
- if (seen.has(key)) {
183
- return false;
184
- }
185
- seen.add(key);
186
- return true;
187
- });
188
- }
189
- unique() {
190
- return [...new Set(this.data)];
191
- }
192
- // ===== STATISTICAL FUNCTIONS =====
193
- count(predicate) {
194
- if (predicate) {
195
- return this.data.filter(predicate).length;
196
- }
197
- return this.data.length;
198
- }
199
- countBy(field) {
200
- const counts = {};
201
- this.data.forEach(item => {
202
- const key = String(this.getNestedValue(item, field) ?? 'null');
203
- counts[key] = (counts[key] || 0) + 1;
204
- });
205
- return counts;
206
- }
207
- // ===== UTILITY METHODS =====
208
- // Get nested field value using dot notation
209
- getNestedValue(obj, path) {
210
- return path.split('.').reduce((current, key) => {
211
- return current && typeof current === 'object' ? current[key] : undefined;
212
- }, obj);
213
- }
214
- // ===== TRANSFORMATION =====
215
- toArray() {
216
- return [...this.data];
217
- }
218
- toJSON() {
219
- return JSON.stringify(this.data);
220
- }
221
- // Convert to QueryResult with different type
222
- cast() {
223
- return new QueryResult(this.data);
224
- }
225
- // ===== JOINING (similar to SQL joins) =====
226
- innerJoin(other, thisKey, otherKey) {
227
- const results = [];
228
- this.data.forEach(thisItem => {
229
- const thisValue = this.getNestedValue(thisItem, thisKey);
230
- other.data.forEach(otherItem => {
231
- const otherValue = this.getNestedValue(otherItem, otherKey);
232
- if (thisValue === otherValue) {
233
- results.push({ ...thisItem, ...otherItem });
234
- }
235
- });
236
- });
237
- return results;
238
- }
239
- leftJoin(other, thisKey, otherKey) {
240
- const results = [];
241
- this.data.forEach(thisItem => {
242
- const thisValue = this.getNestedValue(thisItem, thisKey);
243
- const matches = other.data.filter(otherItem => this.getNestedValue(otherItem, otherKey) === thisValue);
244
- if (matches.length > 0) {
245
- matches.forEach(match => {
246
- results.push({ ...thisItem, ...match });
247
- });
248
- }
249
- else {
250
- results.push({ ...thisItem });
251
- }
252
- });
253
- return results;
254
- }
255
- // ===== EXPORT/FORMATTING =====
256
- toCsv(delimiter = ',') {
257
- if (this.data.length === 0)
258
- return '';
259
- // Get all unique keys from all objects
260
- const allKeys = new Set();
261
- this.data.forEach(item => {
262
- if (typeof item === 'object' && item !== null) {
263
- Object.keys(item).forEach(key => allKeys.add(key));
264
- }
265
- });
266
- const headers = Array.from(allKeys);
267
- const csvRows = [headers.join(delimiter)];
268
- this.data.forEach(item => {
269
- const row = headers.map(header => {
270
- const value = typeof item === 'object' && item !== null ? item[header] : '';
271
- // Escape values that contain the delimiter
272
- const stringValue = String(value ?? '');
273
- return stringValue.includes(delimiter) ? `"${stringValue}"` : stringValue;
274
- });
275
- csvRows.push(row.join(delimiter));
276
- });
277
- return csvRows.join('\n');
278
- }
279
- // ===== DEBUGGING =====
280
- inspect(limit) {
281
- const itemsToShow = limit ? this.data.slice(0, limit) : this.data;
282
- console.log('QueryResult:', {
283
- count: this.data.length,
284
- showing: itemsToShow.length,
285
- data: itemsToShow
286
- });
287
- }
288
- }
289
- exports.QueryResult = QueryResult;
290
- // Utility function to create QueryResult
291
- function createQueryResult(data) {
292
- return new QueryResult(data);
293
- }
@@ -1,20 +0,0 @@
1
- import { SelectionMap } from '../index';
2
- export declare class SelectionBuilder {
3
- private selections;
4
- constructor();
5
- static new(): SelectionBuilder;
6
- static all(): SelectionMap;
7
- field(fieldName: string): SelectionBuilder;
8
- fields(fieldNames: string[]): SelectionBuilder;
9
- nested<T>(fieldName: string, builderFn: (nested: SelectionBuilder) => T): SelectionBuilder;
10
- exclude(fieldName: string): SelectionBuilder;
11
- excludeFields(fieldNames: string[]): SelectionBuilder;
12
- build(): SelectionMap;
13
- clear(): SelectionBuilder;
14
- isEmpty(): boolean;
15
- getSelectionCount(): number;
16
- hasField(fieldName: string): boolean;
17
- isFieldExcluded(fieldName: string): boolean;
18
- getSelectedFields(): string[];
19
- getExcludedFields(): string[];
20
- }