@ekodb/ekodb-client 0.7.0 → 0.8.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.
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Unit tests for ekoDB TypeScript client QueryBuilder
3
+ */
4
+ export {};
@@ -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
+ });
package/dist/search.d.ts CHANGED
@@ -48,6 +48,10 @@ export interface SearchQuery {
48
48
  text_weight?: number;
49
49
  /** Weight for vector search (0.0-1.0) */
50
50
  vector_weight?: number;
51
+ /** Only return these fields (plus 'id') */
52
+ select_fields?: string[];
53
+ /** Exclude these fields from results */
54
+ exclude_fields?: string[];
51
55
  }
52
56
  /**
53
57
  * Search result with score and matched fields
@@ -165,6 +169,14 @@ export declare class SearchQueryBuilder {
165
169
  * Set maximum number of results to return
166
170
  */
167
171
  limit(limit: number): this;
172
+ /**
173
+ * Select specific fields to return
174
+ */
175
+ selectFields(fields: string[]): this;
176
+ /**
177
+ * Exclude specific fields from results
178
+ */
179
+ excludeFields(fields: string[]): this;
168
180
  /**
169
181
  * Build the final SearchQuery object
170
182
  */
package/dist/search.js CHANGED
@@ -162,6 +162,20 @@ class SearchQueryBuilder {
162
162
  this.query.limit = limit;
163
163
  return this;
164
164
  }
165
+ /**
166
+ * Select specific fields to return
167
+ */
168
+ selectFields(fields) {
169
+ this.query.select_fields = fields;
170
+ return this;
171
+ }
172
+ /**
173
+ * Exclude specific fields from results
174
+ */
175
+ excludeFields(fields) {
176
+ this.query.exclude_fields = fields;
177
+ return this;
178
+ }
165
179
  /**
166
180
  * Build the final SearchQuery object
167
181
  */
package/dist/utils.d.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * @example
13
13
  * ```typescript
14
- * const user = await client.findByID('users', userId);
14
+ * const user = await client.findById('users', userId);
15
15
  * const email = getValue(user.email); // Extracts string from { type: 'String', value: 'user@example.com' }
16
16
  * const age = getValue(user.age); // Extracts number from { type: 'Integer', value: 25 }
17
17
  * ```
@@ -27,7 +27,7 @@ export declare function getValue<T = any>(field: any): T;
27
27
  *
28
28
  * @example
29
29
  * ```typescript
30
- * const user = await client.findByID('users', userId);
30
+ * const user = await client.findById('users', userId);
31
31
  * const { email, first_name, status } = getValues(user, ['email', 'first_name', 'status']);
32
32
  * ```
33
33
  */
@@ -81,7 +81,7 @@ export declare function getObjectValue<T = any>(field: any): T | null;
81
81
  *
82
82
  * @example
83
83
  * ```typescript
84
- * const user = await client.findByID('users', userId);
84
+ * const user = await client.findById('users', userId);
85
85
  * const plainUser = extractRecord(user);
86
86
  * // { id: '123', email: 'user@example.com', first_name: 'John', ... }
87
87
  * ```
package/dist/utils.js CHANGED
@@ -27,7 +27,7 @@ exports.extractRecord = extractRecord;
27
27
  *
28
28
  * @example
29
29
  * ```typescript
30
- * const user = await client.findByID('users', userId);
30
+ * const user = await client.findById('users', userId);
31
31
  * const email = getValue(user.email); // Extracts string from { type: 'String', value: 'user@example.com' }
32
32
  * const age = getValue(user.age); // Extracts number from { type: 'Integer', value: 25 }
33
33
  * ```
@@ -48,7 +48,7 @@ function getValue(field) {
48
48
  *
49
49
  * @example
50
50
  * ```typescript
51
- * const user = await client.findByID('users', userId);
51
+ * const user = await client.findById('users', userId);
52
52
  * const { email, first_name, status } = getValues(user, ['email', 'first_name', 'status']);
53
53
  * ```
54
54
  */
@@ -177,7 +177,7 @@ function getObjectValue(field) {
177
177
  *
178
178
  * @example
179
179
  * ```typescript
180
- * const user = await client.findByID('users', userId);
180
+ * const user = await client.findById('users', userId);
181
181
  * const plainUser = extractRecord(user);
182
182
  * // { id: '123', email: 'user@example.com', first_name: 'John', ... }
183
183
  * ```
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Unit tests for ekoDB TypeScript client utility functions
3
+ */
4
+ export {};