@ekodb/ekodb-client 0.1.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.
- package/README.md +329 -0
- package/dist/client.d.ts +404 -0
- package/dist/client.js +553 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +20 -0
- package/dist/join.d.ts +68 -0
- package/dist/join.js +71 -0
- package/dist/query-builder.d.ts +141 -0
- package/dist/query-builder.js +370 -0
- package/dist/schema.d.ts +189 -0
- package/dist/schema.js +186 -0
- package/dist/search.d.ts +172 -0
- package/dist/search.js +183 -0
- package/package.json +27 -0
- package/src/client.ts +757 -0
- package/src/index.ts +29 -0
- package/src/join.ts +102 -0
- package/src/query-builder.ts +419 -0
- package/src/schema.ts +285 -0
- package/src/search.ts +275 -0
- package/tsconfig.json +18 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export { EkoDBClient, WebSocketClient, MergeStrategy, RateLimitError } from './client';
|
|
2
|
+
export { QueryBuilder, SortOrder } from './query-builder';
|
|
3
|
+
export { SearchQueryBuilder } from './search';
|
|
4
|
+
export { SchemaBuilder, FieldTypeSchemaBuilder, VectorIndexAlgorithm, DistanceMetric } from './schema';
|
|
5
|
+
export { JoinBuilder } from './join';
|
|
6
|
+
export type { SearchQuery, SearchResult, SearchResponse } from './search';
|
|
7
|
+
export type { Schema, FieldTypeSchema, IndexConfig, CollectionMetadata } from './schema';
|
|
8
|
+
export type { JoinConfig } from './join';
|
|
9
|
+
export type {
|
|
10
|
+
Record,
|
|
11
|
+
Query,
|
|
12
|
+
BatchOperationResult,
|
|
13
|
+
ClientConfig,
|
|
14
|
+
RateLimitInfo,
|
|
15
|
+
CollectionConfig,
|
|
16
|
+
ChatRequest,
|
|
17
|
+
CreateChatSessionRequest,
|
|
18
|
+
ChatMessageRequest,
|
|
19
|
+
TokenUsage,
|
|
20
|
+
ChatResponse,
|
|
21
|
+
ChatSession,
|
|
22
|
+
ChatSessionResponse,
|
|
23
|
+
ListSessionsQuery,
|
|
24
|
+
ListSessionsResponse,
|
|
25
|
+
GetMessagesQuery,
|
|
26
|
+
GetMessagesResponse,
|
|
27
|
+
UpdateSessionRequest,
|
|
28
|
+
MergeSessionsRequest
|
|
29
|
+
} from './client';
|
package/src/join.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Join support for multi-collection queries
|
|
3
|
+
*
|
|
4
|
+
* This module provides support for joining data across multiple collections,
|
|
5
|
+
* similar to SQL joins but with document-oriented semantics.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for joining collections
|
|
10
|
+
*/
|
|
11
|
+
export interface JoinConfig {
|
|
12
|
+
/** Target collections to join with */
|
|
13
|
+
collections: string[];
|
|
14
|
+
/** Field in the current collection */
|
|
15
|
+
local_field: string;
|
|
16
|
+
/** Field in the target collection(s) */
|
|
17
|
+
foreign_field: string;
|
|
18
|
+
/** Name of the field to store joined data */
|
|
19
|
+
as_field: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Builder for constructing join configurations
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* // Single collection join
|
|
28
|
+
* const join = JoinBuilder.single("users", "user_id", "id", "user");
|
|
29
|
+
*
|
|
30
|
+
* // Multi-collection join
|
|
31
|
+
* const join = JoinBuilder.multi(
|
|
32
|
+
* ["users", "profiles", "settings"],
|
|
33
|
+
* "user_id",
|
|
34
|
+
* "id",
|
|
35
|
+
* "user_info"
|
|
36
|
+
* );
|
|
37
|
+
*
|
|
38
|
+
* // Use in query
|
|
39
|
+
* const query = new QueryBuilder()
|
|
40
|
+
* .eq("status", "active")
|
|
41
|
+
* .join(join)
|
|
42
|
+
* .build();
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export class JoinBuilder {
|
|
46
|
+
private config: JoinConfig;
|
|
47
|
+
|
|
48
|
+
private constructor(
|
|
49
|
+
collections: string[],
|
|
50
|
+
localField: string,
|
|
51
|
+
foreignField: string,
|
|
52
|
+
asField: string
|
|
53
|
+
) {
|
|
54
|
+
this.config = {
|
|
55
|
+
collections,
|
|
56
|
+
local_field: localField,
|
|
57
|
+
foreign_field: foreignField,
|
|
58
|
+
as_field: asField,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Create a join with a single collection
|
|
64
|
+
*
|
|
65
|
+
* @param collection - Target collection name
|
|
66
|
+
* @param localField - Field in the current collection
|
|
67
|
+
* @param foreignField - Field in the target collection
|
|
68
|
+
* @param asField - Name of the field to store joined data
|
|
69
|
+
*/
|
|
70
|
+
static single(
|
|
71
|
+
collection: string,
|
|
72
|
+
localField: string,
|
|
73
|
+
foreignField: string,
|
|
74
|
+
asField: string
|
|
75
|
+
): JoinConfig {
|
|
76
|
+
return new JoinBuilder([collection], localField, foreignField, asField).build();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Create a join with multiple collections
|
|
81
|
+
*
|
|
82
|
+
* @param collections - Array of target collection names
|
|
83
|
+
* @param localField - Field in the current collection
|
|
84
|
+
* @param foreignField - Field in the target collections
|
|
85
|
+
* @param asField - Name of the field to store joined data
|
|
86
|
+
*/
|
|
87
|
+
static multi(
|
|
88
|
+
collections: string[],
|
|
89
|
+
localField: string,
|
|
90
|
+
foreignField: string,
|
|
91
|
+
asField: string
|
|
92
|
+
): JoinConfig {
|
|
93
|
+
return new JoinBuilder(collections, localField, foreignField, asField).build();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Build the final JoinConfig
|
|
98
|
+
*/
|
|
99
|
+
build(): JoinConfig {
|
|
100
|
+
return this.config;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query Builder for constructing complex queries with fluent API
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export enum SortOrder {
|
|
6
|
+
Asc = "asc",
|
|
7
|
+
Desc = "desc",
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface Query {
|
|
11
|
+
filter?: any;
|
|
12
|
+
sort?: Array<{ field: string; ascending: boolean }>;
|
|
13
|
+
limit?: number;
|
|
14
|
+
skip?: number;
|
|
15
|
+
join?: any;
|
|
16
|
+
bypass_cache?: boolean;
|
|
17
|
+
bypass_ripple?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Fluent API for building complex database queries
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const query = new QueryBuilder()
|
|
26
|
+
* .eq("status", "active")
|
|
27
|
+
* .gt("age", 18)
|
|
28
|
+
* .sortDesc("created_at")
|
|
29
|
+
* .limit(10)
|
|
30
|
+
* .build();
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export class QueryBuilder {
|
|
34
|
+
private filters: any[] = [];
|
|
35
|
+
private sortFields: Array<{ field: string; order: SortOrder }> = [];
|
|
36
|
+
private _limit?: number;
|
|
37
|
+
private _skip?: number;
|
|
38
|
+
private _join?: any;
|
|
39
|
+
private _bypassCache: boolean = false;
|
|
40
|
+
private _bypassRipple: boolean = false;
|
|
41
|
+
|
|
42
|
+
// ========================================================================
|
|
43
|
+
// Comparison Operators
|
|
44
|
+
// ========================================================================
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Add an equality filter ($eq)
|
|
48
|
+
*/
|
|
49
|
+
eq(field: string, value: any): this {
|
|
50
|
+
this.filters.push({
|
|
51
|
+
type: "Condition",
|
|
52
|
+
content: {
|
|
53
|
+
field,
|
|
54
|
+
operator: "Eq",
|
|
55
|
+
value,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Add a not-equal filter ($ne)
|
|
63
|
+
*/
|
|
64
|
+
ne(field: string, value: any): this {
|
|
65
|
+
this.filters.push({
|
|
66
|
+
type: "Condition",
|
|
67
|
+
content: {
|
|
68
|
+
field,
|
|
69
|
+
operator: "Ne",
|
|
70
|
+
value,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Add a greater-than filter ($gt)
|
|
78
|
+
*/
|
|
79
|
+
gt(field: string, value: any): this {
|
|
80
|
+
this.filters.push({
|
|
81
|
+
type: "Condition",
|
|
82
|
+
content: {
|
|
83
|
+
field,
|
|
84
|
+
operator: "Gt",
|
|
85
|
+
value,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Add a greater-than-or-equal filter ($gte)
|
|
93
|
+
*/
|
|
94
|
+
gte(field: string, value: any): this {
|
|
95
|
+
this.filters.push({
|
|
96
|
+
type: "Condition",
|
|
97
|
+
content: {
|
|
98
|
+
field,
|
|
99
|
+
operator: "Gte",
|
|
100
|
+
value,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Add a less-than filter ($lt)
|
|
108
|
+
*/
|
|
109
|
+
lt(field: string, value: any): this {
|
|
110
|
+
this.filters.push({
|
|
111
|
+
type: "Condition",
|
|
112
|
+
content: {
|
|
113
|
+
field,
|
|
114
|
+
operator: "Lt",
|
|
115
|
+
value,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
return this;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Add a less-than-or-equal filter ($lte)
|
|
123
|
+
*/
|
|
124
|
+
lte(field: string, value: any): this {
|
|
125
|
+
this.filters.push({
|
|
126
|
+
type: "Condition",
|
|
127
|
+
content: {
|
|
128
|
+
field,
|
|
129
|
+
operator: "Lte",
|
|
130
|
+
value,
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Add an in-array filter ($in)
|
|
138
|
+
*/
|
|
139
|
+
in(field: string, values: any[]): this {
|
|
140
|
+
this.filters.push({
|
|
141
|
+
type: "Condition",
|
|
142
|
+
content: {
|
|
143
|
+
field,
|
|
144
|
+
operator: "In",
|
|
145
|
+
value: values,
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
return this;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Add a not-in-array filter ($nin)
|
|
153
|
+
*/
|
|
154
|
+
nin(field: string, values: any[]): this {
|
|
155
|
+
this.filters.push({
|
|
156
|
+
type: "Condition",
|
|
157
|
+
content: {
|
|
158
|
+
field,
|
|
159
|
+
operator: "NotIn",
|
|
160
|
+
value: values,
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
return this;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ========================================================================
|
|
167
|
+
// String Operators
|
|
168
|
+
// ========================================================================
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Add a contains filter (substring match)
|
|
172
|
+
*/
|
|
173
|
+
contains(field: string, substring: string): this {
|
|
174
|
+
this.filters.push({
|
|
175
|
+
type: "Condition",
|
|
176
|
+
content: {
|
|
177
|
+
field,
|
|
178
|
+
operator: "Contains",
|
|
179
|
+
value: substring,
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
return this;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Add a starts-with filter
|
|
187
|
+
*/
|
|
188
|
+
startsWith(field: string, prefix: string): this {
|
|
189
|
+
this.filters.push({
|
|
190
|
+
type: "Condition",
|
|
191
|
+
content: {
|
|
192
|
+
field,
|
|
193
|
+
operator: "StartsWith",
|
|
194
|
+
value: prefix,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
return this;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Add an ends-with filter
|
|
202
|
+
*/
|
|
203
|
+
endsWith(field: string, suffix: string): this {
|
|
204
|
+
this.filters.push({
|
|
205
|
+
type: "Condition",
|
|
206
|
+
content: {
|
|
207
|
+
field,
|
|
208
|
+
operator: "EndsWith",
|
|
209
|
+
value: suffix,
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
return this;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Add a regex filter
|
|
217
|
+
*/
|
|
218
|
+
regex(field: string, pattern: string): this {
|
|
219
|
+
this.filters.push({
|
|
220
|
+
type: "Condition",
|
|
221
|
+
content: {
|
|
222
|
+
field,
|
|
223
|
+
operator: "Regex",
|
|
224
|
+
value: pattern,
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
return this;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// ========================================================================
|
|
231
|
+
// Logical Operators
|
|
232
|
+
// ========================================================================
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Combine filters with AND logic
|
|
236
|
+
*/
|
|
237
|
+
and(conditions: any[]): this {
|
|
238
|
+
this.filters.push({
|
|
239
|
+
type: "Logical",
|
|
240
|
+
content: {
|
|
241
|
+
operator: "And",
|
|
242
|
+
expressions: conditions,
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
return this;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Combine filters with OR logic
|
|
250
|
+
*/
|
|
251
|
+
or(conditions: any[]): this {
|
|
252
|
+
this.filters.push({
|
|
253
|
+
type: "Logical",
|
|
254
|
+
content: {
|
|
255
|
+
operator: "Or",
|
|
256
|
+
expressions: conditions,
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Negate a filter
|
|
264
|
+
*/
|
|
265
|
+
not(condition: any): this {
|
|
266
|
+
this.filters.push({
|
|
267
|
+
type: "Logical",
|
|
268
|
+
content: {
|
|
269
|
+
operator: "Not",
|
|
270
|
+
expressions: [condition],
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
return this;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Add a raw filter expression
|
|
278
|
+
*/
|
|
279
|
+
rawFilter(filter: any): this {
|
|
280
|
+
this.filters.push(filter);
|
|
281
|
+
return this;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// ========================================================================
|
|
285
|
+
// Sorting
|
|
286
|
+
// ========================================================================
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Add a sort field in ascending order
|
|
290
|
+
*/
|
|
291
|
+
sortAsc(field: string): this {
|
|
292
|
+
this.sortFields.push({ field, order: SortOrder.Asc });
|
|
293
|
+
return this;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Add a sort field in descending order
|
|
298
|
+
*/
|
|
299
|
+
sortDesc(field: string): this {
|
|
300
|
+
this.sortFields.push({ field, order: SortOrder.Desc });
|
|
301
|
+
return this;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// ========================================================================
|
|
305
|
+
// Pagination
|
|
306
|
+
// ========================================================================
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Set the maximum number of results
|
|
310
|
+
*/
|
|
311
|
+
limit(limit: number): this {
|
|
312
|
+
this._limit = limit;
|
|
313
|
+
return this;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Set the number of results to skip (for pagination)
|
|
318
|
+
*/
|
|
319
|
+
skip(skip: number): this {
|
|
320
|
+
this._skip = skip;
|
|
321
|
+
return this;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Set page number and page size (convenience method)
|
|
326
|
+
*/
|
|
327
|
+
page(page: number, pageSize: number): this {
|
|
328
|
+
this._skip = page * pageSize;
|
|
329
|
+
this._limit = pageSize;
|
|
330
|
+
return this;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// ========================================================================
|
|
334
|
+
// Joins
|
|
335
|
+
// ========================================================================
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Add a join configuration
|
|
339
|
+
*/
|
|
340
|
+
join(joinConfig: any): this {
|
|
341
|
+
this._join = joinConfig;
|
|
342
|
+
return this;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// ========================================================================
|
|
346
|
+
// Performance Flags
|
|
347
|
+
// ========================================================================
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Bypass cache for this query
|
|
351
|
+
*/
|
|
352
|
+
bypassCache(bypass: boolean = true): this {
|
|
353
|
+
this._bypassCache = bypass;
|
|
354
|
+
return this;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Bypass ripple for this query
|
|
359
|
+
*/
|
|
360
|
+
bypassRipple(bypass: boolean = true): this {
|
|
361
|
+
this._bypassRipple = bypass;
|
|
362
|
+
return this;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// ========================================================================
|
|
366
|
+
// Build
|
|
367
|
+
// ========================================================================
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Build the final Query object
|
|
371
|
+
*/
|
|
372
|
+
build(): Query {
|
|
373
|
+
const query: Query = {};
|
|
374
|
+
|
|
375
|
+
// Combine all filters with AND logic if multiple filters exist
|
|
376
|
+
if (this.filters.length > 0) {
|
|
377
|
+
query.filter =
|
|
378
|
+
this.filters.length === 1
|
|
379
|
+
? this.filters[0]
|
|
380
|
+
: {
|
|
381
|
+
type: "Logical",
|
|
382
|
+
content: {
|
|
383
|
+
operator: "And",
|
|
384
|
+
expressions: this.filters,
|
|
385
|
+
},
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Build sort expression
|
|
390
|
+
if (this.sortFields.length > 0) {
|
|
391
|
+
query.sort = this.sortFields.map(({ field, order }) => ({
|
|
392
|
+
field,
|
|
393
|
+
ascending: order === SortOrder.Asc,
|
|
394
|
+
}));
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (this._limit !== undefined) {
|
|
398
|
+
query.limit = this._limit;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (this._skip !== undefined) {
|
|
402
|
+
query.skip = this._skip;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (this._join !== undefined) {
|
|
406
|
+
query.join = this._join;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (this._bypassCache) {
|
|
410
|
+
query.bypass_cache = true;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (this._bypassRipple) {
|
|
414
|
+
query.bypass_ripple = true;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return query;
|
|
418
|
+
}
|
|
419
|
+
}
|