@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.
Files changed (98) hide show
  1. package/.DS_Store +0 -0
  2. package/.claude/settings.local.json +8 -0
  3. package/.gitignore +5 -0
  4. package/.idea/.gitignore +5 -0
  5. package/.idea/compiler.xml +6 -0
  6. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  7. package/.idea/jsLinters/eslint.xml +6 -0
  8. package/.idea/modules.xml +8 -0
  9. package/.idea/prettier.xml +7 -0
  10. package/.idea/sdk.iml +12 -0
  11. package/.idea/vcs.xml +6 -0
  12. package/.idea/workspace.xml +257 -0
  13. package/dist/client.d.ts.map +1 -1
  14. package/dist/client.js +11 -3
  15. package/dist/client.js.map +1 -1
  16. package/dist/database.d.ts +0 -20
  17. package/dist/database.d.ts.map +1 -1
  18. package/dist/database.js +0 -40
  19. package/dist/database.js.map +1 -1
  20. package/dist/query-sdk/tests/setup.d.ts +16 -0
  21. package/dist/query-sdk/tests/setup.d.ts.map +1 -0
  22. package/dist/query-sdk/tests/setup.js +49 -0
  23. package/dist/query-sdk/tests/setup.js.map +1 -0
  24. package/examples/basic-usage.ts +136 -0
  25. package/examples/blob-upload-example.ts +140 -0
  26. package/examples/collection-schema-example.ts +304 -0
  27. package/examples/server-side-joins.ts +201 -0
  28. package/examples/tweet-self-joins-example.ts +352 -0
  29. package/package-lock.json +3823 -0
  30. package/package.json +1 -1
  31. package/skills.md +1096 -0
  32. package/src/.env +1 -0
  33. package/src/batch.d.ts +121 -0
  34. package/src/batch.js +205 -0
  35. package/src/batch.ts +257 -0
  36. package/src/client.ts +1856 -0
  37. package/src/database.d.ts +268 -0
  38. package/src/database.js +294 -0
  39. package/src/database.ts +695 -0
  40. package/src/index.d.ts +160 -0
  41. package/src/index.js +186 -0
  42. package/src/index.ts +253 -0
  43. package/src/query-sdk/ConditionBuilder.ts +103 -0
  44. package/src/query-sdk/FieldConditionBuilder.ts +2 -0
  45. package/src/query-sdk/NestedBuilders.ts +186 -0
  46. package/src/query-sdk/OnChainDB.ts +294 -0
  47. package/src/query-sdk/QueryBuilder.ts +1191 -0
  48. package/src/query-sdk/QueryResult.ts +375 -0
  49. package/src/query-sdk/README.md +866 -0
  50. package/src/query-sdk/SelectionBuilder.ts +94 -0
  51. package/src/query-sdk/adapters/HttpClientAdapter.ts +249 -0
  52. package/src/query-sdk/dist/ConditionBuilder.d.ts +22 -0
  53. package/src/query-sdk/dist/ConditionBuilder.js +90 -0
  54. package/src/query-sdk/dist/FieldConditionBuilder.d.ts +1 -0
  55. package/src/query-sdk/dist/FieldConditionBuilder.js +6 -0
  56. package/src/query-sdk/dist/NestedBuilders.d.ts +43 -0
  57. package/src/query-sdk/dist/NestedBuilders.js +144 -0
  58. package/src/query-sdk/dist/OnChainDB.d.ts +19 -0
  59. package/src/query-sdk/dist/OnChainDB.js +123 -0
  60. package/src/query-sdk/dist/QueryBuilder.d.ts +70 -0
  61. package/src/query-sdk/dist/QueryBuilder.js +295 -0
  62. package/src/query-sdk/dist/QueryResult.d.ts +52 -0
  63. package/src/query-sdk/dist/QueryResult.js +293 -0
  64. package/src/query-sdk/dist/SelectionBuilder.d.ts +20 -0
  65. package/src/query-sdk/dist/SelectionBuilder.js +80 -0
  66. package/src/query-sdk/dist/adapters/HttpClientAdapter.d.ts +27 -0
  67. package/src/query-sdk/dist/adapters/HttpClientAdapter.js +170 -0
  68. package/src/query-sdk/dist/index.d.ts +36 -0
  69. package/src/query-sdk/dist/index.js +27 -0
  70. package/src/query-sdk/dist/operators.d.ts +56 -0
  71. package/src/query-sdk/dist/operators.js +289 -0
  72. package/src/query-sdk/dist/tests/setup.d.ts +15 -0
  73. package/src/query-sdk/dist/tests/setup.js +46 -0
  74. package/src/query-sdk/index.ts +59 -0
  75. package/src/query-sdk/jest.config.js +25 -0
  76. package/src/query-sdk/operators.ts +335 -0
  77. package/src/query-sdk/package.json +46 -0
  78. package/src/query-sdk/tests/FieldConditionBuilder.test.ts +84 -0
  79. package/src/query-sdk/tests/LogicalOperator.test.ts +85 -0
  80. package/src/query-sdk/tests/NestedBuilders.test.ts +321 -0
  81. package/src/query-sdk/tests/QueryBuilder.test.ts +348 -0
  82. package/src/query-sdk/tests/QueryResult.test.ts +464 -0
  83. package/src/query-sdk/tests/aggregations.test.ts +653 -0
  84. package/src/query-sdk/tests/comprehensive.test.ts +279 -0
  85. package/src/query-sdk/tests/integration.test.ts +608 -0
  86. package/src/query-sdk/tests/operators.test.ts +327 -0
  87. package/src/query-sdk/tests/setup.ts +59 -0
  88. package/src/query-sdk/tests/unit.test.ts +794 -0
  89. package/src/query-sdk/tsconfig.json +26 -0
  90. package/src/query-sdk/yarn.lock +3092 -0
  91. package/src/types.d.ts +131 -0
  92. package/src/types.js +46 -0
  93. package/src/types.ts +534 -0
  94. package/src/x402/index.ts +12 -0
  95. package/src/x402/types.ts +250 -0
  96. package/src/x402/utils.ts +332 -0
  97. package/tsconfig.json +20 -0
  98. package/yarn.lock +2309 -0
@@ -0,0 +1,186 @@
1
+ import { LogicalOperator, FieldConditionBuilder, Condition } from './operators';
2
+
3
+ // Builder for creating nested field conditions with ORM-like syntax
4
+ export class NestedConditionBuilder {
5
+ private path: string[];
6
+
7
+ constructor(rootField: string) {
8
+ this.path = [rootField];
9
+ }
10
+
11
+ // Add another level to the path and create field conditions
12
+ field(fieldName: string): NestedFieldConditionBuilder {
13
+ const newPath = [...this.path, fieldName];
14
+ return new NestedFieldConditionBuilder(newPath);
15
+ }
16
+
17
+ // Create nested structure with callback
18
+ nested(fieldName: string, builderFn: (builder: NestedConditionBuilder) => LogicalOperator): LogicalOperator {
19
+ const nestedPath = [...this.path, fieldName];
20
+ const nestedBuilder = new NestedConditionBuilder('');
21
+ nestedBuilder.path = nestedPath;
22
+ return builderFn(nestedBuilder);
23
+ }
24
+
25
+ // Create logical groups
26
+ andGroup(builderFn: (builder: NestedConditionBuilder) => LogicalOperator[]): LogicalOperator {
27
+ const conditions = builderFn(this);
28
+ return LogicalOperator.And(conditions);
29
+ }
30
+
31
+ orGroup(builderFn: (builder: NestedConditionBuilder) => LogicalOperator[]): LogicalOperator {
32
+ const conditions = builderFn(this);
33
+ return LogicalOperator.Or(conditions);
34
+ }
35
+
36
+ notGroup(builderFn: (builder: NestedConditionBuilder) => LogicalOperator[]): LogicalOperator {
37
+ const conditions = builderFn(this);
38
+ return LogicalOperator.Not(conditions);
39
+ }
40
+ }
41
+
42
+ // Builder for field conditions within nested structures
43
+ // Only includes operators that actually exist in the Rust implementation
44
+ export class NestedFieldConditionBuilder {
45
+ private fieldPath: string[];
46
+
47
+ constructor(fieldPath: string[]) {
48
+ this.fieldPath = fieldPath;
49
+ }
50
+
51
+ private createCondition(operator: string, value: any): Condition {
52
+ const path = this.fieldPath.join('.');
53
+ return {
54
+ field: path,
55
+ operator,
56
+ value
57
+ };
58
+ }
59
+
60
+ // ===== BASE OPERATORS (BaseOperator) =====
61
+
62
+ equals(value: any): Condition {
63
+ return this.createCondition('is', value);
64
+ }
65
+
66
+ notEquals(value: any): Condition {
67
+ return this.createCondition('isNot', value);
68
+ }
69
+
70
+ in(values: any[]): Condition {
71
+ return this.createCondition('in', values);
72
+ }
73
+
74
+ notIn(values: any[]): Condition {
75
+ return this.createCondition('notIn', values);
76
+ }
77
+
78
+ isNull(): Condition {
79
+ return this.createCondition('isNull', true);
80
+ }
81
+
82
+ isNotNull(): Condition {
83
+ return this.createCondition('isNull', false);
84
+ }
85
+
86
+ exists(): Condition {
87
+ return this.createCondition('exists', true);
88
+ }
89
+
90
+ notExists(): Condition {
91
+ return this.createCondition('exists', false);
92
+ }
93
+
94
+ // ===== STRING OPERATORS (StringOperator) =====
95
+
96
+ startsWith(value: string): Condition {
97
+ return this.createCondition('startsWith', value);
98
+ }
99
+
100
+ endsWith(value: string): Condition {
101
+ return this.createCondition('endsWith', value);
102
+ }
103
+
104
+ contains(value: string): Condition {
105
+ return this.createCondition('includes', value);
106
+ }
107
+
108
+ regExpMatches(pattern: string): Condition {
109
+ return this.createCondition('regExpMatches', pattern);
110
+ }
111
+
112
+ includesCaseInsensitive(value: string): Condition {
113
+ return this.createCondition('includesCaseInsensitive', value);
114
+ }
115
+
116
+ startsWithCaseInsensitive(value: string): Condition {
117
+ return this.createCondition('startsWithCaseInsensitive', value);
118
+ }
119
+
120
+ endsWithCaseInsensitive(value: string): Condition {
121
+ return this.createCondition('endsWithCaseInsensitive', value);
122
+ }
123
+
124
+ // ===== NUMBER OPERATORS (NumberOperator) =====
125
+
126
+ greaterThan(value: any): Condition {
127
+ return this.createCondition('greaterThan', value);
128
+ }
129
+
130
+ lessThan(value: any): Condition {
131
+ return this.createCondition('lessThan', value);
132
+ }
133
+
134
+ greaterThanOrEqual(value: any): Condition {
135
+ return this.createCondition('greaterThanOrEqual', value);
136
+ }
137
+
138
+ lessThanOrEqual(value: any): Condition {
139
+ return this.createCondition('lessThanOrEqual', value);
140
+ }
141
+
142
+ // ===== IP OPERATORS (IpOperator) =====
143
+
144
+ isLocalIp(): Condition {
145
+ return this.createCondition('isLocalIp', true);
146
+ }
147
+
148
+ isExternalIp(): Condition {
149
+ return this.createCondition('isExternalIp', true);
150
+ }
151
+
152
+ // ===== MISC OPERATORS (MiscOperator) =====
153
+
154
+ b64(value: string): Condition {
155
+ return this.createCondition('b64', value);
156
+ }
157
+
158
+ inDataset(dataset: string): Condition {
159
+ return this.createCondition('inDataset', dataset);
160
+ }
161
+
162
+ inCountry(countryCode: string): Condition {
163
+ return this.createCondition('inCountry', countryCode);
164
+ }
165
+
166
+ cidr(cidr: string): Condition {
167
+ return this.createCondition('CIDR', cidr);
168
+ }
169
+
170
+ // ===== BETWEEN OPERATOR =====
171
+
172
+ between(min: any, max: any): Condition {
173
+ return this.createCondition('between', { from: min, to: max });
174
+ }
175
+
176
+ // ===== CONVENIENCE METHODS =====
177
+
178
+ // Boolean checks (using base operators)
179
+ isTrue(): Condition {
180
+ return this.equals(true);
181
+ }
182
+
183
+ isFalse(): Condition {
184
+ return this.equals(false);
185
+ }
186
+ }
@@ -0,0 +1,294 @@
1
+ import {QueryBuilder} from './QueryBuilder';
2
+ import {SelectionBuilder} from './SelectionBuilder';
3
+ import {FieldMap, HttpClient, QueryRequest, QueryResponse, QueryValue} from "./index";
4
+
5
+ // Main SDK class providing static methods for query building
6
+ export class OnChainDB {
7
+ private static httpClient?: HttpClient;
8
+ private static serverUrl?: string;
9
+ private static apiKey?: string;
10
+
11
+ // Configure the SDK with HTTP client and server URL
12
+ static configure(httpClient: HttpClient, serverUrl: string, apiKey?: string): void {
13
+ this.httpClient = httpClient;
14
+ this.serverUrl = serverUrl;
15
+ this.apiKey = apiKey;
16
+ }
17
+
18
+ // Get the configured HTTP client
19
+ static getHttpClient(): HttpClient | undefined {
20
+ return this.httpClient;
21
+ }
22
+
23
+ // Get the configured server URL
24
+ static getServerUrl(): string | undefined {
25
+ return this.serverUrl;
26
+ }
27
+
28
+ // Start building a new query
29
+ static query(): QueryBuilder {
30
+ return new QueryBuilder(this.httpClient, this.serverUrl);
31
+ }
32
+
33
+ // Create a query builder with specific HTTP client and server URL (one-time use)
34
+ static queryWith(httpClient: HttpClient, serverUrl: string): QueryBuilder {
35
+ return new QueryBuilder(httpClient, serverUrl);
36
+ }
37
+
38
+ // Create a simple query with just field selection (no filtering)
39
+ static select(builderFn: (builder: SelectionBuilder) => SelectionBuilder): QueryBuilder {
40
+ const query = new QueryBuilder(this.httpClient, this.serverUrl);
41
+ query.select(builderFn);
42
+ return query;
43
+ }
44
+
45
+ // Execute a raw query using HTTP
46
+ static async rawQuery(
47
+ queryJson: string,
48
+ httpClient?: HttpClient,
49
+ serverUrl?: string,
50
+ fieldMap?: FieldMap
51
+ ): Promise<QueryResponse> {
52
+ const client = httpClient || this.httpClient;
53
+ const url = serverUrl || this.serverUrl;
54
+
55
+ if (!client) {
56
+ throw new Error('HTTP client is required for raw query execution');
57
+ }
58
+ if (!url) {
59
+ throw new Error('Server URL is required for raw query execution');
60
+ }
61
+
62
+ try {
63
+ const queryValue: QueryValue = JSON.parse(queryJson);
64
+ const request: QueryRequest = {
65
+ ...queryValue,
66
+ // Include fieldMap if provided (for server-side field mapping)
67
+ ...(fieldMap && {fieldMap})
68
+ };
69
+
70
+ const response = await client.post(
71
+ `${url}/list`,
72
+ request,
73
+ {'Content-Type': 'application/json'}
74
+ );
75
+
76
+ return response as QueryResponse;
77
+ } catch (error) {
78
+ if (error instanceof SyntaxError) {
79
+ throw new Error(`Invalid query JSON: ${error.message}`);
80
+ }
81
+ throw new Error(`Raw query execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
82
+ }
83
+ }
84
+
85
+ // Execute a query from a JSON object (useful for dynamic queries)
86
+ static async queryFromJson(
87
+ queryObject: any,
88
+ httpClient?: HttpClient,
89
+ serverUrl?: string
90
+ ): Promise<QueryResponse> {
91
+ const client = httpClient || this.httpClient;
92
+ const url = serverUrl || this.serverUrl;
93
+
94
+ if (!client) {
95
+ throw new Error('HTTP client is required for JSON query execution');
96
+ }
97
+ if (!url) {
98
+ throw new Error('Server URL is required for JSON query execution');
99
+ }
100
+
101
+ try {
102
+ const request: QueryRequest = queryObject
103
+
104
+ const response = await client.post(
105
+ `${url}/list`,
106
+ request,
107
+ {'Content-Type': 'application/json'}
108
+ );
109
+
110
+ return response as QueryResponse;
111
+ } catch (error) {
112
+ throw new Error(`JSON query execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
113
+ }
114
+ }
115
+
116
+ // Health check for the server
117
+ static async healthCheck(httpClient?: HttpClient, serverUrl?: string): Promise<boolean> {
118
+ const client = httpClient || this.httpClient;
119
+ const url = serverUrl || this.serverUrl;
120
+
121
+ if (!client || !url) {
122
+ return false;
123
+ }
124
+
125
+ try {
126
+ await client.post(`${url}/health`, {}, {'Content-Type': 'application/json'});
127
+ return true;
128
+ } catch {
129
+ return false;
130
+ }
131
+ }
132
+
133
+ // Get server information
134
+ static async serverInfo(httpClient?: HttpClient, serverUrl?: string): Promise<any> {
135
+ const client = httpClient || this.httpClient;
136
+ const url = serverUrl || this.serverUrl;
137
+
138
+ if (!client) {
139
+ throw new Error('HTTP client is required for server info');
140
+ }
141
+ if (!url) {
142
+ throw new Error('Server URL is required for server info');
143
+ }
144
+
145
+ try {
146
+ const response = await client.post(
147
+ `${url}/info`,
148
+ {},
149
+ {'Content-Type': 'application/json'}
150
+ );
151
+ return response;
152
+ } catch (error) {
153
+ throw new Error(`Failed to get server info: ${error instanceof Error ? error.message : 'Unknown error'}`);
154
+ }
155
+ }
156
+
157
+ // Reset SDK configuration
158
+ static reset(): void {
159
+ this.httpClient = undefined;
160
+ this.serverUrl = undefined;
161
+ }
162
+
163
+ // Check if SDK is configured
164
+ static isConfigured(): boolean {
165
+ return this.httpClient !== undefined && this.serverUrl !== undefined;
166
+ }
167
+
168
+ // ===== INDEX MANAGEMENT =====
169
+
170
+ /**
171
+ * Create a regular index on a field for query optimization
172
+ * @param appId - Application ID
173
+ * @param collection - Collection name
174
+ * @param fieldName - Field to index
175
+ * @param options - Optional: store values for fast retrieval
176
+ */
177
+ static async createIndex(
178
+ appId: string,
179
+ collection: string,
180
+ fieldName: string,
181
+ options?: {
182
+ storeValues?: boolean;
183
+ }
184
+ ): Promise<any> {
185
+ const client = this.httpClient;
186
+ const url = this.serverUrl;
187
+
188
+ if (!client) {
189
+ throw new Error('HTTP client is required for index creation');
190
+ }
191
+ if (!url) {
192
+ throw new Error('Server URL is required for index creation');
193
+ }
194
+
195
+ const request = {
196
+ app_id: appId,
197
+ collection_name: collection,
198
+ field_name: fieldName,
199
+ index_config: {
200
+ index_type: "Secondary",
201
+ store_values: options?.storeValues !== undefined ? options?.storeValues : true,
202
+ compression: "None",
203
+ cache_priority: "Medium",
204
+ relationship_hints: [],
205
+ performance_tuning: {
206
+ memory_limit_mb: null,
207
+ cache_size_entries: null,
208
+ prefetch_depth: null,
209
+ update_batch_size: null,
210
+ background_optimization: true
211
+ }
212
+ }
213
+ };
214
+
215
+ const headers: Record<string, string> = {'Content-Type': 'application/json'};
216
+ if (this.apiKey) {
217
+ headers['X-API-Key'] = this.apiKey;
218
+ }
219
+
220
+ try {
221
+ const response = await client.post(
222
+ `${url}/api/apps/${appId}/collections/${collection}/indexes`,
223
+ request,
224
+ headers
225
+ );
226
+ return response;
227
+ } catch (error) {
228
+ throw new Error(`Index creation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Create a unique index on a field (acts as PRIMARY KEY)
234
+ * Ensures no duplicate values for this field and enables automatic version deduplication
235
+ * @param appId - Application ID
236
+ * @param collection - Collection name
237
+ * @param fieldName - Field to index with unique constraint
238
+ * @param options - Optional: store values for fast retrieval
239
+ */
240
+ static async createUniqueIndex(
241
+ appId: string,
242
+ collection: string,
243
+ fieldName: string,
244
+ options?: {
245
+ storeValues?: boolean;
246
+ }
247
+ ): Promise<any> {
248
+ const client = this.httpClient;
249
+ const url = this.serverUrl;
250
+
251
+ if (!client) {
252
+ throw new Error('HTTP client is required for index creation');
253
+ }
254
+ if (!url) {
255
+ throw new Error('Server URL is required for index creation');
256
+ }
257
+
258
+ const request = {
259
+ app_id: appId,
260
+ collection_name: collection,
261
+ field_name: fieldName,
262
+ index_config: {
263
+ index_type: "Primary", // Primary = unique constraint
264
+ store_values: options?.storeValues !== undefined ? options?.storeValues : true,
265
+ compression: "None",
266
+ cache_priority: "Medium",
267
+ relationship_hints: [],
268
+ performance_tuning: {
269
+ memory_limit_mb: null,
270
+ cache_size_entries: null,
271
+ prefetch_depth: null,
272
+ update_batch_size: null,
273
+ background_optimization: true
274
+ }
275
+ }
276
+ };
277
+
278
+ const headers: Record<string, string> = {'Content-Type': 'application/json'};
279
+ if (this.apiKey) {
280
+ headers['X-API-Key'] = this.apiKey;
281
+ }
282
+
283
+ try {
284
+ const response = await client.post(
285
+ `${url}/api/apps/${appId}/collections/${collection}/indexes`,
286
+ request,
287
+ headers
288
+ );
289
+ return response;
290
+ } catch (error) {
291
+ throw new Error(`Index creation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
292
+ }
293
+ }
294
+ }