@ekodb/ekodb-client 0.6.1 → 0.7.1
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/dist/client.d.ts +56 -3
- package/dist/client.js +78 -5
- package/dist/functions.d.ts +25 -0
- package/dist/functions.js +26 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/query-builder.test.d.ts +4 -0
- package/dist/query-builder.test.js +318 -0
- package/dist/utils.d.ts +88 -3
- package/dist/utils.js +130 -3
- package/dist/utils.test.d.ts +4 -0
- package/dist/utils.test.js +411 -0
- package/package.json +7 -4
- package/src/client.ts +125 -5
- package/src/functions.ts +59 -0
- package/src/index.ts +2 -0
- package/src/query-builder.test.ts +404 -0
- package/src/utils.test.ts +506 -0
- package/src/utils.ts +165 -3
package/dist/client.d.ts
CHANGED
|
@@ -206,6 +206,9 @@ export declare class EkoDBClient {
|
|
|
206
206
|
private makeRequest;
|
|
207
207
|
/**
|
|
208
208
|
* Insert a document into a collection
|
|
209
|
+
* @param collection - Collection name
|
|
210
|
+
* @param record - Document to insert
|
|
211
|
+
* @param ttl - Optional TTL: duration string ("1h", "30m"), seconds ("3600"), or ISO8601 timestamp
|
|
209
212
|
*/
|
|
210
213
|
insert(collection: string, record: Record, ttl?: string): Promise<Record>;
|
|
211
214
|
/**
|
|
@@ -234,7 +237,7 @@ export declare class EkoDBClient {
|
|
|
234
237
|
/**
|
|
235
238
|
* Find a document by ID
|
|
236
239
|
*/
|
|
237
|
-
|
|
240
|
+
findById(collection: string, id: string): Promise<Record>;
|
|
238
241
|
/**
|
|
239
242
|
* Update a document
|
|
240
243
|
*/
|
|
@@ -260,9 +263,12 @@ export declare class EkoDBClient {
|
|
|
260
263
|
*/
|
|
261
264
|
batchDelete(collection: string, ids: string[], bypassRipple?: boolean): Promise<BatchOperationResult>;
|
|
262
265
|
/**
|
|
263
|
-
* Set a key-value pair
|
|
266
|
+
* Set a key-value pair with optional TTL
|
|
267
|
+
* @param key - The key to set
|
|
268
|
+
* @param value - The value to store
|
|
269
|
+
* @param ttl - Optional TTL in seconds
|
|
264
270
|
*/
|
|
265
|
-
kvSet(key: string, value: any): Promise<void>;
|
|
271
|
+
kvSet(key: string, value: any, ttl?: number): Promise<void>;
|
|
266
272
|
/**
|
|
267
273
|
* Get a value by key
|
|
268
274
|
*/
|
|
@@ -271,6 +277,53 @@ export declare class EkoDBClient {
|
|
|
271
277
|
* Delete a key
|
|
272
278
|
*/
|
|
273
279
|
kvDelete(key: string): Promise<void>;
|
|
280
|
+
/**
|
|
281
|
+
* Check if a key exists
|
|
282
|
+
* @param key - The key to check
|
|
283
|
+
* @returns true if the key exists, false otherwise
|
|
284
|
+
*/
|
|
285
|
+
kvExists(key: string): Promise<boolean>;
|
|
286
|
+
/**
|
|
287
|
+
* Query/find KV entries with pattern matching
|
|
288
|
+
* @param options - Query options including pattern and include_expired
|
|
289
|
+
* @returns Array of matching records
|
|
290
|
+
*/
|
|
291
|
+
kvFind(options?: {
|
|
292
|
+
pattern?: string;
|
|
293
|
+
include_expired?: boolean;
|
|
294
|
+
}): Promise<any[]>;
|
|
295
|
+
/**
|
|
296
|
+
* Alias for kvFind - query KV store with pattern
|
|
297
|
+
*/
|
|
298
|
+
kvQuery(options?: {
|
|
299
|
+
pattern?: string;
|
|
300
|
+
include_expired?: boolean;
|
|
301
|
+
}): Promise<any[]>;
|
|
302
|
+
/**
|
|
303
|
+
* Begin a new transaction
|
|
304
|
+
* @param isolationLevel - Transaction isolation level (default: "ReadCommitted")
|
|
305
|
+
* @returns Transaction ID
|
|
306
|
+
*/
|
|
307
|
+
beginTransaction(isolationLevel?: string): Promise<string>;
|
|
308
|
+
/**
|
|
309
|
+
* Get transaction status
|
|
310
|
+
* @param transactionId - The transaction ID
|
|
311
|
+
* @returns Transaction status object
|
|
312
|
+
*/
|
|
313
|
+
getTransactionStatus(transactionId: string): Promise<{
|
|
314
|
+
state: string;
|
|
315
|
+
operations_count: number;
|
|
316
|
+
}>;
|
|
317
|
+
/**
|
|
318
|
+
* Commit a transaction
|
|
319
|
+
* @param transactionId - The transaction ID to commit
|
|
320
|
+
*/
|
|
321
|
+
commitTransaction(transactionId: string): Promise<void>;
|
|
322
|
+
/**
|
|
323
|
+
* Rollback a transaction
|
|
324
|
+
* @param transactionId - The transaction ID to rollback
|
|
325
|
+
*/
|
|
326
|
+
rollbackTransaction(transactionId: string): Promise<void>;
|
|
274
327
|
/**
|
|
275
328
|
* List all collections
|
|
276
329
|
*/
|
package/dist/client.js
CHANGED
|
@@ -263,11 +263,14 @@ class EkoDBClient {
|
|
|
263
263
|
}
|
|
264
264
|
/**
|
|
265
265
|
* Insert a document into a collection
|
|
266
|
+
* @param collection - Collection name
|
|
267
|
+
* @param record - Document to insert
|
|
268
|
+
* @param ttl - Optional TTL: duration string ("1h", "30m"), seconds ("3600"), or ISO8601 timestamp
|
|
266
269
|
*/
|
|
267
270
|
async insert(collection, record, ttl) {
|
|
268
271
|
const data = { ...record };
|
|
269
272
|
if (ttl) {
|
|
270
|
-
data.
|
|
273
|
+
data.ttl = ttl;
|
|
271
274
|
}
|
|
272
275
|
return this.makeRequest("POST", `/api/insert/${collection}`, data);
|
|
273
276
|
}
|
|
@@ -300,7 +303,7 @@ class EkoDBClient {
|
|
|
300
303
|
/**
|
|
301
304
|
* Find a document by ID
|
|
302
305
|
*/
|
|
303
|
-
async
|
|
306
|
+
async findById(collection, id) {
|
|
304
307
|
return this.makeRequest("GET", `/api/find/${collection}/${id}`);
|
|
305
308
|
}
|
|
306
309
|
/**
|
|
@@ -347,10 +350,17 @@ class EkoDBClient {
|
|
|
347
350
|
return this.makeRequest("DELETE", `/api/batch/delete/${collection}`, { deletes });
|
|
348
351
|
}
|
|
349
352
|
/**
|
|
350
|
-
* Set a key-value pair
|
|
353
|
+
* Set a key-value pair with optional TTL
|
|
354
|
+
* @param key - The key to set
|
|
355
|
+
* @param value - The value to store
|
|
356
|
+
* @param ttl - Optional TTL in seconds
|
|
351
357
|
*/
|
|
352
|
-
async kvSet(key, value) {
|
|
353
|
-
|
|
358
|
+
async kvSet(key, value, ttl) {
|
|
359
|
+
const body = { value };
|
|
360
|
+
if (ttl !== undefined) {
|
|
361
|
+
body.ttl = ttl;
|
|
362
|
+
}
|
|
363
|
+
await this.makeRequest("POST", `/api/kv/set/${encodeURIComponent(key)}`, body, 0, true);
|
|
354
364
|
}
|
|
355
365
|
/**
|
|
356
366
|
* Get a value by key
|
|
@@ -365,6 +375,69 @@ class EkoDBClient {
|
|
|
365
375
|
async kvDelete(key) {
|
|
366
376
|
await this.makeRequest("DELETE", `/api/kv/delete/${encodeURIComponent(key)}`, undefined, 0, true);
|
|
367
377
|
}
|
|
378
|
+
/**
|
|
379
|
+
* Check if a key exists
|
|
380
|
+
* @param key - The key to check
|
|
381
|
+
* @returns true if the key exists, false otherwise
|
|
382
|
+
*/
|
|
383
|
+
async kvExists(key) {
|
|
384
|
+
try {
|
|
385
|
+
const result = await this.kvGet(key);
|
|
386
|
+
return result !== null && result !== undefined;
|
|
387
|
+
}
|
|
388
|
+
catch {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Query/find KV entries with pattern matching
|
|
394
|
+
* @param options - Query options including pattern and include_expired
|
|
395
|
+
* @returns Array of matching records
|
|
396
|
+
*/
|
|
397
|
+
async kvFind(options) {
|
|
398
|
+
const result = await this.makeRequest("POST", "/api/kv/find", options || {}, 0, true);
|
|
399
|
+
return result;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Alias for kvFind - query KV store with pattern
|
|
403
|
+
*/
|
|
404
|
+
async kvQuery(options) {
|
|
405
|
+
return this.kvFind(options);
|
|
406
|
+
}
|
|
407
|
+
// ============================================================================
|
|
408
|
+
// Transaction Operations
|
|
409
|
+
// ============================================================================
|
|
410
|
+
/**
|
|
411
|
+
* Begin a new transaction
|
|
412
|
+
* @param isolationLevel - Transaction isolation level (default: "ReadCommitted")
|
|
413
|
+
* @returns Transaction ID
|
|
414
|
+
*/
|
|
415
|
+
async beginTransaction(isolationLevel = "ReadCommitted") {
|
|
416
|
+
const result = await this.makeRequest("POST", "/api/transactions", { isolation_level: isolationLevel }, 0, true);
|
|
417
|
+
return result.transaction_id;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Get transaction status
|
|
421
|
+
* @param transactionId - The transaction ID
|
|
422
|
+
* @returns Transaction status object
|
|
423
|
+
*/
|
|
424
|
+
async getTransactionStatus(transactionId) {
|
|
425
|
+
return this.makeRequest("GET", `/api/transactions/${encodeURIComponent(transactionId)}`, undefined, 0, true);
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Commit a transaction
|
|
429
|
+
* @param transactionId - The transaction ID to commit
|
|
430
|
+
*/
|
|
431
|
+
async commitTransaction(transactionId) {
|
|
432
|
+
await this.makeRequest("POST", `/api/transactions/${encodeURIComponent(transactionId)}/commit`, undefined, 0, true);
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Rollback a transaction
|
|
436
|
+
* @param transactionId - The transaction ID to rollback
|
|
437
|
+
*/
|
|
438
|
+
async rollbackTransaction(transactionId) {
|
|
439
|
+
await this.makeRequest("POST", `/api/transactions/${encodeURIComponent(transactionId)}/rollback`, undefined, 0, true);
|
|
440
|
+
}
|
|
368
441
|
/**
|
|
369
442
|
* List all collections
|
|
370
443
|
*/
|
package/dist/functions.d.ts
CHANGED
|
@@ -174,6 +174,26 @@ export type FunctionStageConfig = {
|
|
|
174
174
|
} | {
|
|
175
175
|
type: "ReleaseSavepoint";
|
|
176
176
|
name: string;
|
|
177
|
+
} | {
|
|
178
|
+
type: "KvGet";
|
|
179
|
+
key: string;
|
|
180
|
+
output_field?: string;
|
|
181
|
+
} | {
|
|
182
|
+
type: "KvSet";
|
|
183
|
+
key: string;
|
|
184
|
+
value: any;
|
|
185
|
+
ttl?: number;
|
|
186
|
+
} | {
|
|
187
|
+
type: "KvDelete";
|
|
188
|
+
key: string;
|
|
189
|
+
} | {
|
|
190
|
+
type: "KvExists";
|
|
191
|
+
key: string;
|
|
192
|
+
output_field?: string;
|
|
193
|
+
} | {
|
|
194
|
+
type: "KvQuery";
|
|
195
|
+
pattern?: string;
|
|
196
|
+
include_expired?: boolean;
|
|
177
197
|
};
|
|
178
198
|
export interface ChatMessage {
|
|
179
199
|
role: string;
|
|
@@ -275,4 +295,9 @@ export declare const Stage: {
|
|
|
275
295
|
createSavepoint: (name: string) => FunctionStageConfig;
|
|
276
296
|
rollbackToSavepoint: (name: string) => FunctionStageConfig;
|
|
277
297
|
releaseSavepoint: (name: string) => FunctionStageConfig;
|
|
298
|
+
kvGet: (key: string, output_field?: string) => FunctionStageConfig;
|
|
299
|
+
kvSet: (key: string, value: any, ttl?: number) => FunctionStageConfig;
|
|
300
|
+
kvDelete: (key: string) => FunctionStageConfig;
|
|
301
|
+
kvExists: (key: string, output_field?: string) => FunctionStageConfig;
|
|
302
|
+
kvQuery: (pattern?: string, include_expired?: boolean) => FunctionStageConfig;
|
|
278
303
|
};
|
package/dist/functions.js
CHANGED
|
@@ -206,4 +206,30 @@ exports.Stage = {
|
|
|
206
206
|
type: "ReleaseSavepoint",
|
|
207
207
|
name,
|
|
208
208
|
}),
|
|
209
|
+
// KV Store operations - faster than collection lookups for simple key-value data
|
|
210
|
+
kvGet: (key, output_field) => ({
|
|
211
|
+
type: "KvGet",
|
|
212
|
+
key,
|
|
213
|
+
output_field,
|
|
214
|
+
}),
|
|
215
|
+
kvSet: (key, value, ttl) => ({
|
|
216
|
+
type: "KvSet",
|
|
217
|
+
key,
|
|
218
|
+
value,
|
|
219
|
+
ttl,
|
|
220
|
+
}),
|
|
221
|
+
kvDelete: (key) => ({
|
|
222
|
+
type: "KvDelete",
|
|
223
|
+
key,
|
|
224
|
+
}),
|
|
225
|
+
kvExists: (key, output_field) => ({
|
|
226
|
+
type: "KvExists",
|
|
227
|
+
key,
|
|
228
|
+
output_field,
|
|
229
|
+
}),
|
|
230
|
+
kvQuery: (pattern, include_expired) => ({
|
|
231
|
+
type: "KvQuery",
|
|
232
|
+
pattern,
|
|
233
|
+
include_expired,
|
|
234
|
+
}),
|
|
209
235
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,8 @@ export { SearchQueryBuilder } from "./search";
|
|
|
4
4
|
export { SchemaBuilder, FieldTypeSchemaBuilder, VectorIndexAlgorithm, DistanceMetric, } from "./schema";
|
|
5
5
|
export { JoinBuilder } from "./join";
|
|
6
6
|
export { Stage, ChatMessage } from "./functions";
|
|
7
|
-
export { getValue, getValues, extractRecord, getDateTimeValue, getUUIDValue, getDecimalValue, getDurationValue, getBytesValue, getBinaryValue, getArrayValue, getSetValue, getVectorValue, getObjectValue, } from "./utils";
|
|
7
|
+
export { getValue, getValues, extractRecord, getDateTimeValue, getUUIDValue, getDecimalValue, getDurationValue, getBytesValue, getBinaryValue, getArrayValue, getSetValue, getVectorValue, getObjectValue, Field, } from "./utils";
|
|
8
|
+
export type { WrappedFieldValue } from "./utils";
|
|
8
9
|
export type { SearchQuery, SearchResult, SearchResponse } from "./search";
|
|
9
10
|
export type { Schema, FieldTypeSchema, IndexConfig, CollectionMetadata, } from "./schema";
|
|
10
11
|
export type { JoinConfig } from "./join";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getObjectValue = exports.getVectorValue = exports.getSetValue = exports.getArrayValue = exports.getBinaryValue = exports.getBytesValue = exports.getDurationValue = exports.getDecimalValue = exports.getUUIDValue = exports.getDateTimeValue = exports.extractRecord = exports.getValues = exports.getValue = exports.ChatMessage = exports.Stage = exports.JoinBuilder = exports.DistanceMetric = exports.VectorIndexAlgorithm = exports.FieldTypeSchemaBuilder = exports.SchemaBuilder = exports.SearchQueryBuilder = exports.SortOrder = exports.QueryBuilder = exports.RateLimitError = exports.MergeStrategy = exports.SerializationFormat = exports.WebSocketClient = exports.EkoDBClient = void 0;
|
|
3
|
+
exports.Field = exports.getObjectValue = exports.getVectorValue = exports.getSetValue = exports.getArrayValue = exports.getBinaryValue = exports.getBytesValue = exports.getDurationValue = exports.getDecimalValue = exports.getUUIDValue = exports.getDateTimeValue = exports.extractRecord = exports.getValues = exports.getValue = exports.ChatMessage = exports.Stage = exports.JoinBuilder = exports.DistanceMetric = exports.VectorIndexAlgorithm = exports.FieldTypeSchemaBuilder = exports.SchemaBuilder = exports.SearchQueryBuilder = exports.SortOrder = exports.QueryBuilder = exports.RateLimitError = exports.MergeStrategy = exports.SerializationFormat = exports.WebSocketClient = exports.EkoDBClient = void 0;
|
|
4
4
|
var client_1 = require("./client");
|
|
5
5
|
Object.defineProperty(exports, "EkoDBClient", { enumerable: true, get: function () { return client_1.EkoDBClient; } });
|
|
6
6
|
Object.defineProperty(exports, "WebSocketClient", { enumerable: true, get: function () { return client_1.WebSocketClient; } });
|
|
@@ -36,3 +36,4 @@ Object.defineProperty(exports, "getArrayValue", { enumerable: true, get: functio
|
|
|
36
36
|
Object.defineProperty(exports, "getSetValue", { enumerable: true, get: function () { return utils_1.getSetValue; } });
|
|
37
37
|
Object.defineProperty(exports, "getVectorValue", { enumerable: true, get: function () { return utils_1.getVectorValue; } });
|
|
38
38
|
Object.defineProperty(exports, "getObjectValue", { enumerable: true, get: function () { return utils_1.getObjectValue; } });
|
|
39
|
+
Object.defineProperty(exports, "Field", { enumerable: true, get: function () { return utils_1.Field; } });
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Unit tests for ekoDB TypeScript client QueryBuilder
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const vitest_1 = require("vitest");
|
|
7
|
+
const query_builder_1 = require("./query-builder");
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Basic Tests
|
|
10
|
+
// ============================================================================
|
|
11
|
+
(0, vitest_1.describe)("QueryBuilder basics", () => {
|
|
12
|
+
(0, vitest_1.it)("creates empty query builder", () => {
|
|
13
|
+
const qb = new query_builder_1.QueryBuilder();
|
|
14
|
+
(0, vitest_1.expect)(qb).toBeInstanceOf(query_builder_1.QueryBuilder);
|
|
15
|
+
});
|
|
16
|
+
(0, vitest_1.it)("builds empty query", () => {
|
|
17
|
+
const query = new query_builder_1.QueryBuilder().build();
|
|
18
|
+
(0, vitest_1.expect)(query).toEqual({});
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// Equality Operators Tests
|
|
23
|
+
// ============================================================================
|
|
24
|
+
(0, vitest_1.describe)("QueryBuilder equality operators", () => {
|
|
25
|
+
(0, vitest_1.it)("builds eq filter", () => {
|
|
26
|
+
const query = new query_builder_1.QueryBuilder().eq("status", "active").build();
|
|
27
|
+
(0, vitest_1.expect)(query.filter).toEqual({
|
|
28
|
+
type: "Condition",
|
|
29
|
+
content: {
|
|
30
|
+
field: "status",
|
|
31
|
+
operator: "Eq",
|
|
32
|
+
value: "active",
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
(0, vitest_1.it)("builds ne filter", () => {
|
|
37
|
+
const query = new query_builder_1.QueryBuilder().ne("status", "deleted").build();
|
|
38
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("Ne");
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Comparison Operators Tests
|
|
43
|
+
// ============================================================================
|
|
44
|
+
(0, vitest_1.describe)("QueryBuilder comparison operators", () => {
|
|
45
|
+
(0, vitest_1.it)("builds gt filter", () => {
|
|
46
|
+
const query = new query_builder_1.QueryBuilder().gt("age", 18).build();
|
|
47
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("Gt");
|
|
48
|
+
(0, vitest_1.expect)(query.filter.content.value).toBe(18);
|
|
49
|
+
});
|
|
50
|
+
(0, vitest_1.it)("builds gte filter", () => {
|
|
51
|
+
const query = new query_builder_1.QueryBuilder().gte("score", 80).build();
|
|
52
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("Gte");
|
|
53
|
+
});
|
|
54
|
+
(0, vitest_1.it)("builds lt filter", () => {
|
|
55
|
+
const query = new query_builder_1.QueryBuilder().lt("price", 100.5).build();
|
|
56
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("Lt");
|
|
57
|
+
});
|
|
58
|
+
(0, vitest_1.it)("builds lte filter", () => {
|
|
59
|
+
const query = new query_builder_1.QueryBuilder().lte("count", 1000).build();
|
|
60
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("Lte");
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
// ============================================================================
|
|
64
|
+
// Array Operators Tests
|
|
65
|
+
// ============================================================================
|
|
66
|
+
(0, vitest_1.describe)("QueryBuilder array operators", () => {
|
|
67
|
+
(0, vitest_1.it)("builds in filter", () => {
|
|
68
|
+
const query = new query_builder_1.QueryBuilder()
|
|
69
|
+
.in("status", ["active", "pending"])
|
|
70
|
+
.build();
|
|
71
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("In");
|
|
72
|
+
(0, vitest_1.expect)(query.filter.content.value).toEqual(["active", "pending"]);
|
|
73
|
+
});
|
|
74
|
+
(0, vitest_1.it)("builds nin filter", () => {
|
|
75
|
+
const query = new query_builder_1.QueryBuilder()
|
|
76
|
+
.nin("role", ["blocked", "deleted"])
|
|
77
|
+
.build();
|
|
78
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("NotIn");
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// String Operators Tests
|
|
83
|
+
// ============================================================================
|
|
84
|
+
(0, vitest_1.describe)("QueryBuilder string operators", () => {
|
|
85
|
+
(0, vitest_1.it)("builds contains filter", () => {
|
|
86
|
+
const query = new query_builder_1.QueryBuilder().contains("email", "@example.com").build();
|
|
87
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("Contains");
|
|
88
|
+
(0, vitest_1.expect)(query.filter.content.value).toBe("@example.com");
|
|
89
|
+
});
|
|
90
|
+
(0, vitest_1.it)("builds startsWith filter", () => {
|
|
91
|
+
const query = new query_builder_1.QueryBuilder().startsWith("name", "John").build();
|
|
92
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("StartsWith");
|
|
93
|
+
});
|
|
94
|
+
(0, vitest_1.it)("builds endsWith filter", () => {
|
|
95
|
+
const query = new query_builder_1.QueryBuilder().endsWith("filename", ".pdf").build();
|
|
96
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("EndsWith");
|
|
97
|
+
});
|
|
98
|
+
(0, vitest_1.it)("builds regex filter", () => {
|
|
99
|
+
const query = new query_builder_1.QueryBuilder().regex("phone", "^\\+1").build();
|
|
100
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("Regex");
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
// ============================================================================
|
|
104
|
+
// Logical Operators Tests
|
|
105
|
+
// ============================================================================
|
|
106
|
+
(0, vitest_1.describe)("QueryBuilder logical operators", () => {
|
|
107
|
+
(0, vitest_1.it)("builds and filter", () => {
|
|
108
|
+
const conditions = [
|
|
109
|
+
{
|
|
110
|
+
type: "Condition",
|
|
111
|
+
content: { field: "status", operator: "Eq", value: "active" },
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
type: "Condition",
|
|
115
|
+
content: { field: "age", operator: "Gt", value: 18 },
|
|
116
|
+
},
|
|
117
|
+
];
|
|
118
|
+
const query = new query_builder_1.QueryBuilder().and(conditions).build();
|
|
119
|
+
(0, vitest_1.expect)(query.filter.type).toBe("Logical");
|
|
120
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("And");
|
|
121
|
+
(0, vitest_1.expect)(query.filter.content.expressions).toHaveLength(2);
|
|
122
|
+
});
|
|
123
|
+
(0, vitest_1.it)("builds or filter", () => {
|
|
124
|
+
const conditions = [
|
|
125
|
+
{
|
|
126
|
+
type: "Condition",
|
|
127
|
+
content: { field: "role", operator: "Eq", value: "admin" },
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
type: "Condition",
|
|
131
|
+
content: { field: "role", operator: "Eq", value: "super_admin" },
|
|
132
|
+
},
|
|
133
|
+
];
|
|
134
|
+
const query = new query_builder_1.QueryBuilder().or(conditions).build();
|
|
135
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("Or");
|
|
136
|
+
});
|
|
137
|
+
(0, vitest_1.it)("builds not filter", () => {
|
|
138
|
+
const condition = {
|
|
139
|
+
type: "Condition",
|
|
140
|
+
content: { field: "deleted", operator: "Eq", value: true },
|
|
141
|
+
};
|
|
142
|
+
const query = new query_builder_1.QueryBuilder().not(condition).build();
|
|
143
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("Not");
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
// ============================================================================
|
|
147
|
+
// Multiple Filters (Auto AND) Tests
|
|
148
|
+
// ============================================================================
|
|
149
|
+
(0, vitest_1.describe)("QueryBuilder multiple filters", () => {
|
|
150
|
+
(0, vitest_1.it)("combines multiple filters with AND logic", () => {
|
|
151
|
+
const query = new query_builder_1.QueryBuilder()
|
|
152
|
+
.eq("status", "active")
|
|
153
|
+
.gt("age", 18)
|
|
154
|
+
.contains("email", "@company.com")
|
|
155
|
+
.build();
|
|
156
|
+
(0, vitest_1.expect)(query.filter.type).toBe("Logical");
|
|
157
|
+
(0, vitest_1.expect)(query.filter.content.operator).toBe("And");
|
|
158
|
+
(0, vitest_1.expect)(query.filter.content.expressions).toHaveLength(3);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
// ============================================================================
|
|
162
|
+
// Sorting Tests
|
|
163
|
+
// ============================================================================
|
|
164
|
+
(0, vitest_1.describe)("QueryBuilder sorting", () => {
|
|
165
|
+
(0, vitest_1.it)("builds ascending sort", () => {
|
|
166
|
+
const query = new query_builder_1.QueryBuilder().sortAsc("name").build();
|
|
167
|
+
(0, vitest_1.expect)(query.sort).toHaveLength(1);
|
|
168
|
+
(0, vitest_1.expect)(query.sort[0].field).toBe("name");
|
|
169
|
+
(0, vitest_1.expect)(query.sort[0].ascending).toBe(true);
|
|
170
|
+
});
|
|
171
|
+
(0, vitest_1.it)("builds descending sort", () => {
|
|
172
|
+
const query = new query_builder_1.QueryBuilder().sortDesc("created_at").build();
|
|
173
|
+
(0, vitest_1.expect)(query.sort[0].ascending).toBe(false);
|
|
174
|
+
});
|
|
175
|
+
(0, vitest_1.it)("builds multiple sorts", () => {
|
|
176
|
+
const query = new query_builder_1.QueryBuilder()
|
|
177
|
+
.sortDesc("created_at")
|
|
178
|
+
.sortAsc("name")
|
|
179
|
+
.build();
|
|
180
|
+
(0, vitest_1.expect)(query.sort).toHaveLength(2);
|
|
181
|
+
(0, vitest_1.expect)(query.sort[0].field).toBe("created_at");
|
|
182
|
+
(0, vitest_1.expect)(query.sort[0].ascending).toBe(false);
|
|
183
|
+
(0, vitest_1.expect)(query.sort[1].field).toBe("name");
|
|
184
|
+
(0, vitest_1.expect)(query.sort[1].ascending).toBe(true);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
// ============================================================================
|
|
188
|
+
// Pagination Tests
|
|
189
|
+
// ============================================================================
|
|
190
|
+
(0, vitest_1.describe)("QueryBuilder pagination", () => {
|
|
191
|
+
(0, vitest_1.it)("builds limit", () => {
|
|
192
|
+
const query = new query_builder_1.QueryBuilder().limit(10).build();
|
|
193
|
+
(0, vitest_1.expect)(query.limit).toBe(10);
|
|
194
|
+
});
|
|
195
|
+
(0, vitest_1.it)("builds skip", () => {
|
|
196
|
+
const query = new query_builder_1.QueryBuilder().skip(20).build();
|
|
197
|
+
(0, vitest_1.expect)(query.skip).toBe(20);
|
|
198
|
+
});
|
|
199
|
+
(0, vitest_1.it)("builds page (convenience method)", () => {
|
|
200
|
+
// Page 2 with 20 items per page = skip 40
|
|
201
|
+
const query = new query_builder_1.QueryBuilder().page(2, 20).build();
|
|
202
|
+
(0, vitest_1.expect)(query.limit).toBe(20);
|
|
203
|
+
(0, vitest_1.expect)(query.skip).toBe(40);
|
|
204
|
+
});
|
|
205
|
+
(0, vitest_1.it)("builds page 0", () => {
|
|
206
|
+
const query = new query_builder_1.QueryBuilder().page(0, 10).build();
|
|
207
|
+
(0, vitest_1.expect)(query.skip).toBe(0);
|
|
208
|
+
(0, vitest_1.expect)(query.limit).toBe(10);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
// ============================================================================
|
|
212
|
+
// Join Tests
|
|
213
|
+
// ============================================================================
|
|
214
|
+
(0, vitest_1.describe)("QueryBuilder join", () => {
|
|
215
|
+
(0, vitest_1.it)("builds join configuration", () => {
|
|
216
|
+
const joinConfig = {
|
|
217
|
+
collections: ["users"],
|
|
218
|
+
local_field: "user_id",
|
|
219
|
+
foreign_field: "id",
|
|
220
|
+
as_field: "user",
|
|
221
|
+
};
|
|
222
|
+
const query = new query_builder_1.QueryBuilder().join(joinConfig).build();
|
|
223
|
+
(0, vitest_1.expect)(query.join).toEqual(joinConfig);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
// ============================================================================
|
|
227
|
+
// Bypass Flags Tests
|
|
228
|
+
// ============================================================================
|
|
229
|
+
(0, vitest_1.describe)("QueryBuilder bypass flags", () => {
|
|
230
|
+
(0, vitest_1.it)("builds bypass_cache true", () => {
|
|
231
|
+
const query = new query_builder_1.QueryBuilder().bypassCache(true).build();
|
|
232
|
+
(0, vitest_1.expect)(query.bypass_cache).toBe(true);
|
|
233
|
+
});
|
|
234
|
+
(0, vitest_1.it)("builds bypass_cache false (not included)", () => {
|
|
235
|
+
const query = new query_builder_1.QueryBuilder().bypassCache(false).build();
|
|
236
|
+
(0, vitest_1.expect)(query.bypass_cache).toBeUndefined();
|
|
237
|
+
});
|
|
238
|
+
(0, vitest_1.it)("builds bypass_cache default (true)", () => {
|
|
239
|
+
const query = new query_builder_1.QueryBuilder().bypassCache().build();
|
|
240
|
+
(0, vitest_1.expect)(query.bypass_cache).toBe(true);
|
|
241
|
+
});
|
|
242
|
+
(0, vitest_1.it)("builds bypass_ripple", () => {
|
|
243
|
+
const query = new query_builder_1.QueryBuilder().bypassRipple(true).build();
|
|
244
|
+
(0, vitest_1.expect)(query.bypass_ripple).toBe(true);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
// ============================================================================
|
|
248
|
+
// Chaining Tests
|
|
249
|
+
// ============================================================================
|
|
250
|
+
(0, vitest_1.describe)("QueryBuilder chaining", () => {
|
|
251
|
+
(0, vitest_1.it)("supports full method chaining", () => {
|
|
252
|
+
const query = new query_builder_1.QueryBuilder()
|
|
253
|
+
.eq("status", "active")
|
|
254
|
+
.gt("age", 18)
|
|
255
|
+
.sortDesc("created_at")
|
|
256
|
+
.sortAsc("name")
|
|
257
|
+
.limit(10)
|
|
258
|
+
.skip(20)
|
|
259
|
+
.bypassCache(true)
|
|
260
|
+
.build();
|
|
261
|
+
// Check filter exists
|
|
262
|
+
(0, vitest_1.expect)(query.filter).toBeDefined();
|
|
263
|
+
// Check sort exists
|
|
264
|
+
(0, vitest_1.expect)(query.sort).toHaveLength(2);
|
|
265
|
+
// Check pagination
|
|
266
|
+
(0, vitest_1.expect)(query.limit).toBe(10);
|
|
267
|
+
(0, vitest_1.expect)(query.skip).toBe(20);
|
|
268
|
+
// Check bypass flag
|
|
269
|
+
(0, vitest_1.expect)(query.bypass_cache).toBe(true);
|
|
270
|
+
});
|
|
271
|
+
(0, vitest_1.it)("returns this for method chaining", () => {
|
|
272
|
+
const qb = new query_builder_1.QueryBuilder();
|
|
273
|
+
(0, vitest_1.expect)(qb.eq("a", 1)).toBe(qb);
|
|
274
|
+
(0, vitest_1.expect)(qb.ne("b", 2)).toBe(qb);
|
|
275
|
+
(0, vitest_1.expect)(qb.gt("c", 3)).toBe(qb);
|
|
276
|
+
(0, vitest_1.expect)(qb.gte("d", 4)).toBe(qb);
|
|
277
|
+
(0, vitest_1.expect)(qb.lt("e", 5)).toBe(qb);
|
|
278
|
+
(0, vitest_1.expect)(qb.lte("f", 6)).toBe(qb);
|
|
279
|
+
(0, vitest_1.expect)(qb.in("g", [7])).toBe(qb);
|
|
280
|
+
(0, vitest_1.expect)(qb.nin("h", [8])).toBe(qb);
|
|
281
|
+
(0, vitest_1.expect)(qb.contains("i", "j")).toBe(qb);
|
|
282
|
+
(0, vitest_1.expect)(qb.startsWith("k", "l")).toBe(qb);
|
|
283
|
+
(0, vitest_1.expect)(qb.endsWith("m", "n")).toBe(qb);
|
|
284
|
+
(0, vitest_1.expect)(qb.regex("o", "p")).toBe(qb);
|
|
285
|
+
(0, vitest_1.expect)(qb.sortAsc("q")).toBe(qb);
|
|
286
|
+
(0, vitest_1.expect)(qb.sortDesc("r")).toBe(qb);
|
|
287
|
+
(0, vitest_1.expect)(qb.limit(1)).toBe(qb);
|
|
288
|
+
(0, vitest_1.expect)(qb.skip(0)).toBe(qb);
|
|
289
|
+
(0, vitest_1.expect)(qb.bypassCache()).toBe(qb);
|
|
290
|
+
(0, vitest_1.expect)(qb.bypassRipple()).toBe(qb);
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
// ============================================================================
|
|
294
|
+
// Raw Filter Tests
|
|
295
|
+
// ============================================================================
|
|
296
|
+
(0, vitest_1.describe)("QueryBuilder rawFilter", () => {
|
|
297
|
+
(0, vitest_1.it)("adds raw filter expression", () => {
|
|
298
|
+
const rawFilter = {
|
|
299
|
+
type: "Condition",
|
|
300
|
+
content: {
|
|
301
|
+
field: "custom",
|
|
302
|
+
operator: "CustomOp",
|
|
303
|
+
value: "custom_value",
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
const query = new query_builder_1.QueryBuilder().rawFilter(rawFilter).build();
|
|
307
|
+
(0, vitest_1.expect)(query.filter).toEqual(rawFilter);
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
// ============================================================================
|
|
311
|
+
// SortOrder Enum Tests
|
|
312
|
+
// ============================================================================
|
|
313
|
+
(0, vitest_1.describe)("SortOrder enum", () => {
|
|
314
|
+
(0, vitest_1.it)("has correct values", () => {
|
|
315
|
+
(0, vitest_1.expect)(query_builder_1.SortOrder.Asc).toBe("asc");
|
|
316
|
+
(0, vitest_1.expect)(query_builder_1.SortOrder.Desc).toBe("desc");
|
|
317
|
+
});
|
|
318
|
+
});
|