@livequery/mongodb 2.0.153 → 2.0.154

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 CHANGED
@@ -4,17 +4,14 @@ Native MongoDB datasource adapter for the `@livequery` ecosystem.
4
4
 
5
5
  This package translates Livequery request shapes into MongoDB native driver operations. It is intended for projects that want to use `@livequery/core` with plain `mongodb` collections, without Mongoose models or schema introspection.
6
6
 
7
- The adapter supports two integration styles:
8
-
9
- - Core style: `new MongoDatasource(config)`, `init(routes)`, then `handle(ctx)`.
10
- - Legacy style: `new MongoDatasource()`, `init(config, routes)`, then direct `query(req, options)`.
7
+ Integration with `@livequery/core`: `new MongoDatasource(config)`, `init(routes)`, then `handle(ctx)`. For imperative use you can also call `query(req, options)` directly.
11
8
 
12
9
  Reads are executed with MongoDB aggregation pipelines through `Collection.aggregate(...).toArray()`. Writes use native collection methods such as `insertOne`, `updateOne`, and `deleteOne`.
13
10
 
14
11
  ## Installation
15
12
 
16
13
  ```sh
17
- bun add @livequery/mongodb mongodb bson rxjs
14
+ bun add @livequery/mongodb mongodb rxjs
18
15
  ```
19
16
 
20
17
  For local development in this workspace, `@livequery/core` is installed as a dev dependency from `file:../core`. Runtime JavaScript does not import `@livequery/core`; the generated declaration files use core types.
@@ -26,7 +23,6 @@ export * from './MongoDatasource.js'
26
23
  export * from './DataChangePayload.js'
27
24
  export * from './MongodbRealtime.js'
28
25
  export * from './MongodbCollection.js'
29
- export * from './types.js'
30
26
  ```
31
27
 
32
28
  ## Project Meaning
@@ -40,7 +36,7 @@ Typical request flow with `@livequery/core`:
40
36
  1. A framework adapter creates a `LivequeryContext`.
41
37
  2. `LivequeryRequestParser` reads `ctx.request` and writes `ctx.livequery`.
42
38
  3. `MongoDatasource.handle(ctx)` resolves route options from `ctx.request.method` and `ctx.request.ref`.
43
- 4. `MongoDatasource` converts `ctx.livequery.query` into adapter `req.options`.
39
+ 4. `MongoDatasource` reads `ctx.livequery` (keys, query, body, method) as the adapter request.
44
40
  5. Reads are delegated to `MongoQuery`; writes go directly to the native collection.
45
41
  6. The result is assigned to `ctx.response`.
46
42
 
@@ -51,13 +47,13 @@ Typical request flow with `@livequery/core`:
51
47
  Main adapter class.
52
48
 
53
49
  ```ts
54
- class MongoDatasource extends Subject<WebsocketSyncPayload<LivequeryBaseEntity>>
50
+ class MongoDatasource extends Subject<UpdatedData<LivequeryBaseEntity>>
55
51
  ```
56
52
 
57
53
  Responsibilities:
58
54
 
59
55
  - Store datasource config and route options.
60
- - Support core-style and legacy-style initialization.
56
+ - Initialize from a list of routes.
61
57
  - Resolve connection, database, and collection for each request.
62
58
  - Normalize configured ObjectId fields.
63
59
  - Execute reads, inserts, updates, and deletes.
@@ -80,7 +76,7 @@ const datasource = new MongoDatasource({
80
76
  })
81
77
  ```
82
78
 
83
- If `config` is omitted, call `init(config, routes)` later.
79
+ `config` is required before any request runs. Omit it here only if you assign `datasource.config` before the first `handle` / `query` call.
84
80
 
85
81
  #### `init(routes)`
86
82
 
@@ -104,35 +100,6 @@ await datasource.init([
104
100
 
105
101
  Route lookup uses `METHOD path`, for example `GET /products`. A path-only fallback is also stored for compatibility.
106
102
 
107
- #### `init(config, routes)`
108
-
109
- Legacy-style initialization.
110
-
111
- Parameters:
112
-
113
- - `config: MongoDatasourceConfig`: MongoDB connection configuration.
114
- - `routes: Array<{ method; path; options }>`: legacy route entries. The datasource options are nested under `options`.
115
-
116
- Example:
117
-
118
- ```ts
119
- await datasource.init(
120
- {
121
- connections: { default: client },
122
- databases: ['main'],
123
- },
124
- [
125
- {
126
- method: 'GET',
127
- path: '/products',
128
- options: {
129
- collection: 'products',
130
- },
131
- },
132
- ]
133
- )
134
- ```
135
-
136
103
  #### `handle(ctx)`
137
104
 
138
105
  Core handler entry point.
@@ -165,7 +132,7 @@ Executes a parsed Livequery request against one MongoDB collection.
165
132
 
166
133
  Parameters:
167
134
 
168
- - `req: LivequeryRequest`: adapter request. Core requests use `query`; this adapter normalizes it to `options`. Legacy callers can pass `options` directly.
135
+ - `req: LivequeryRequest`: parsed Livequery request. Reads `req.keys`, `req.query`, `req.method`, and `req.body`.
169
136
  - `options: RouteOptions`: route configuration that tells the adapter which collection, database, connection, and ObjectId fields to use.
170
137
 
171
138
  Supported `req.method` values:
@@ -193,7 +160,7 @@ const response = await datasource.query(
193
160
  ref: 'products',
194
161
  is_collection: true,
195
162
  keys: {},
196
- options: { ':limit': 10 },
163
+ query: { ':limit': 10 },
197
164
  },
198
165
  {
199
166
  collection: 'products',
@@ -218,7 +185,7 @@ Responsibilities:
218
185
 
219
186
  Parameters:
220
187
 
221
- - `req: LivequeryRequest`: normalized adapter request. Reads `req.keys`, `req.options`, and `req.is_collection`.
188
+ - `req: LivequeryRequest`: parsed adapter request. Reads `req.keys`, `req.query`, and `req.is_collection` (`req.query` is normalized to `{}` when absent).
222
189
  - `collection: Collection<T>`: native MongoDB collection.
223
190
 
224
191
  Behavior:
@@ -231,8 +198,8 @@ Known behavior:
231
198
  - `:limit` defaults to `10`.
232
199
  - Minimum `:limit` is `1`.
233
200
  - Maximum `:limit` is `100`.
234
- - Cursor paging is implemented.
235
- - Offset paging with `page` is not implemented yet.
201
+ - Cursor paging (`:after` / `:before` / `:around`) is the default.
202
+ - Offset paging is used when `:page` is provided.
236
203
 
237
204
  Filter examples:
238
205
 
@@ -268,7 +235,7 @@ Builds a cursor from a response item and active sort options.
268
235
  Parameters:
269
236
 
270
237
  - `item: LivequeryBaseEntity`: response item. Must contain `id`.
271
- - `options: QueryOption`: request options. Sort options ending with `:sort` are included in the cursor.
238
+ - `options: Record<string, any>`: the request query (`req.query`). Sort options ending with `:sort` are included in the cursor.
272
239
 
273
240
  Returns:
274
241
 
@@ -405,30 +372,45 @@ Responsibilities:
405
372
  - Bump `updated_at` on every update.
406
373
  - Accept a `string` id, an `ObjectId`, or a filter object for single-document operations.
407
374
 
408
- #### `constructor(db, collectionName, resolveDefaults?)`
375
+ #### `defineCollection<T>(config)` and `constructor(db, config)`
409
376
 
410
- Parameters:
377
+ A collection is described once with `defineCollection`, then bound to a `Db` instance.
378
+
379
+ `defineCollection<T>({ collection, defaults? })` returns a typed `CollectionDef<T>`:
380
+
381
+ - `collection: string`: collection name. The handle is resolved lazily via `db.collection(name)`.
382
+ - `defaults?: (input: Partial<T>) => Partial<T>`: optional default-field resolver, a replacement for Mongoose `@Prop({ default })`. It runs on every `create` / `insertMany` with the input document; the input always overrides the returned defaults.
383
+
384
+ `new MongodbCollection<T>(db, config)`:
411
385
 
412
386
  - `db: Db`: a connected `mongodb` `Db`. It is passed in explicitly (no hidden module singleton), so one class works across databases and connections.
413
- - `collectionName: string`: collection name. The handle is resolved lazily via `db.collection(name)`.
414
- - `resolveDefaults?: (input: Partial<T>) => Partial<T>`: optional default-field resolver, a replacement for Mongoose `@Prop({ default })`. It runs on every `create` / `insertMany` with the input document; the input always overrides the returned defaults.
387
+ - `config: CollectionDef<T>`: the definition returned by `defineCollection`. The generic `T` is inferred from it, so the instance is fully typed.
415
388
 
416
389
  Example:
417
390
 
418
391
  ```ts
419
392
  import { MongoClient } from 'mongodb'
420
- import { MongodbCollection } from '@livequery/mongodb'
393
+ import { MongodbCollection, defineCollection } from '@livequery/mongodb'
421
394
 
422
395
  const client = new MongoClient(process.env.MONGO_URL!)
423
396
  await client.connect()
424
397
  const db = client.db('main')
425
398
 
426
399
  type Order = { video_id: string; amount: number; started: boolean; running: boolean }
400
+ type Video = { title: string }
401
+
402
+ // With a defaults resolver (replaces Mongoose @Prop({ default })):
403
+ const Orders = new MongodbCollection(db, defineCollection<Order>({
404
+ collection: 'orders',
405
+ defaults: () => ({ started: false, running: true }),
406
+ }))
427
407
 
428
- const Orders = new MongodbCollection<Order>(db, 'orders', () => ({ started: false, running: true }))
429
- const Videos = new MongodbCollection<Video>(db, 'videos') // no defaults
408
+ // Without defaults:
409
+ const Videos = new MongodbCollection(db, defineCollection<Video>({ collection: 'videos' }))
430
410
  ```
431
411
 
412
+ Define each collection once at composition time and reuse the instance across the app.
413
+
432
414
  #### Document shape: `MongoDoc<T>`
433
415
 
434
416
  ```ts
@@ -468,17 +450,38 @@ Behavior:
468
450
  Example:
469
451
 
470
452
  ```ts
453
+ // create — applies defaults (started/running) + created_at/updated_at; strips any client id/_id
471
454
  const order = await Orders.create({ video_id: 'v1', amount: 50 })
472
455
  order.id // '507f1f77bcf86cd799439011'
456
+ order.started // false — from the defaults resolver
473
457
  order._id // ObjectId — still readable internally
474
458
  JSON.stringify(order) // contains "id", not "_id"
475
459
 
476
- await Orders.findOne('507f1f77bcf86cd799439011') // by string id
460
+ // insertMany same preparation as create, returns hydrated docs
461
+ const [a, b] = await Orders.insertMany([{ video_id: 'v2', amount: 10 }, { video_id: 'v3', amount: 20 }])
462
+
463
+ // reads — single-doc helpers accept a string id, an ObjectId, or a filter object
464
+ await Orders.findOne('507f1f77bcf86cd799439011') // by string id (24-hex → _id)
477
465
  await Orders.findById(order._id) // by ObjectId
478
466
  await Orders.findOne({ video_id: 'v1' }) // by filter
467
+ await Orders.find({ started: false }) // many
468
+
469
+ // updates — plain bodies are wrapped in $set; operator bodies pass through; updated_at always bumped
470
+ await Orders.updateOne(order.id, { amount: 80 }) // → { $set: { amount: 80, updated_at } }
471
+ await Orders.updateOne(order.id, { $inc: { amount: 5 } }) // → { $inc, $set: { updated_at } }
472
+ await Orders.updateMany({ started: false }, { running: true })
479
473
 
480
- await Orders.updateOne(order.id, { amount: 80 }) // wrapped in $set, bumps updated_at
481
- await Orders.updateOne(order.id, { $inc: { amount: 5 } }) // operator preserved, still bumps updated_at
474
+ // existence / counting
475
+ await Orders.exists(order.id) // boolean
476
+ await Orders.countDocuments({ video_id: 'v1' }) // number
477
+
478
+ // delete
479
+ await Orders.deleteOne(order.id)
480
+ await Orders.deleteMany({ video_id: 'v3' })
481
+
482
+ // escape hatches
483
+ await Orders.aggregate([{ $group: { _id: '$video_id', total: { $sum: '$amount' } } }])
484
+ Orders.collection // raw native Collection
482
485
  ```
483
486
 
484
487
  ### `DataChangePayload<T>`
@@ -609,7 +612,9 @@ await datasource.handle(ctx)
609
612
 
610
613
  `LivequeryRequestParser` will set `ctx.livequery.document_id` and `ctx.livequery.keys.id`. The datasource converts `id` to Mongo `_id` for document reads and writes.
611
614
 
612
- ## Legacy Usage Example
615
+ ## Direct Query Example
616
+
617
+ For imperative use, call `query(req, options)` directly without going through `handle(ctx)`. Pass the config to the constructor; `init(routes)` is not required for this path since the collection is given in `options`.
613
618
 
614
619
  ```ts
615
620
  import { MongoClient } from 'mongodb'
@@ -618,33 +623,18 @@ import { MongoDatasource } from '@livequery/mongodb'
618
623
  const client = new MongoClient(process.env.MONGO_URL!)
619
624
  await client.connect()
620
625
 
621
- const datasource = new MongoDatasource()
622
-
623
- await datasource.init(
624
- {
625
- connections: { default: client },
626
- databases: ['main'],
627
- },
628
- [
629
- {
630
- method: 'GET',
631
- path: '/products',
632
- options: {
633
- collection: 'products',
634
- },
635
- },
636
- ]
637
- )
626
+ const datasource = new MongoDatasource({
627
+ connections: { default: client },
628
+ databases: ['main'],
629
+ })
638
630
 
639
631
  const response = await datasource.query(
640
632
  {
641
633
  method: 'get',
642
634
  ref: 'products',
643
635
  is_collection: true,
644
- collection_ref: 'products',
645
- schema_collection_ref: 'products',
646
636
  keys: {},
647
- options: { ':limit': 10 },
637
+ query: { ':limit': 10 },
648
638
  },
649
639
  {
650
640
  collection: 'products',
@@ -1,4 +1,4 @@
1
1
  export declare class Cursor {
2
- static caculate(item: Record<string, any>, options: Record<string, any>): string;
2
+ static caculate(item: Record<string, any>, options: Record<string, any>): string | null;
3
3
  static parse(cursor: string): any;
4
4
  }
@@ -46,6 +46,27 @@ export declare class MongoDatasource extends Subject<UpdatedData<LivequeryBaseEn
46
46
  total: number;
47
47
  };
48
48
  } | {
49
+ has: {
50
+ prev: boolean;
51
+ next: boolean;
52
+ };
53
+ count: {
54
+ prev: number;
55
+ next: number;
56
+ current: number;
57
+ total: number;
58
+ };
59
+ page: {
60
+ current: number;
61
+ total: number;
62
+ };
49
63
  item: any;
64
+ cursor: {
65
+ last: string | null;
66
+ first: string | null;
67
+ };
68
+ summary: any;
69
+ } | {
70
+ item: Record<string, any>;
50
71
  }>;
51
72
  }
@@ -111,8 +111,8 @@ export class MongoDatasource extends Subject {
111
111
  const total = current + count.next + count.prev;
112
112
  const paging = {
113
113
  cursor: {
114
- last: Cursor.caculate(items[items.length - 1], req.query),
115
- first: Cursor.caculate(items[0], req.query)
114
+ last: Cursor.caculate(items[items.length - 1], req.query || {}),
115
+ first: Cursor.caculate(items[0], req.query || {})
116
116
  },
117
117
  has,
118
118
  count: {
@@ -162,11 +162,11 @@ export class MongoDatasource extends Subject {
162
162
  };
163
163
  const result = await collection.insertOne(merged);
164
164
  return {
165
- item: {
165
+ item: this.#stringifyOids({
166
166
  ...merged,
167
167
  _id: undefined,
168
168
  id: result.insertedId.toString()
169
- }
169
+ })
170
170
  };
171
171
  }
172
172
  async #put(req, collection) {
@@ -186,11 +186,16 @@ export class MongoDatasource extends Subject {
186
186
  const isPlainBody = req.body && typeof req.body === 'object'
187
187
  && !Object.keys(req.body).some(k => k.startsWith('$'));
188
188
  const id = keys.id ?? req.document_id;
189
- return {
189
+ return this.#stringifyOids({
190
190
  ...keys,
191
191
  ...isPlainBody ? req.body : {},
192
192
  ...id ? { id } : {}
193
- };
193
+ });
194
+ }
195
+ #stringifyOids(item) {
196
+ return Object.entries(item).reduce((p, [k, v]) => {
197
+ return { ...p, [k]: v instanceof ObjectId ? v.toString() : v };
198
+ }, {});
194
199
  }
195
200
  #keys(req) {
196
201
  return Object.entries(req.keys).reduce((p, [k, c]) => {
@@ -159,7 +159,7 @@ export class MongoQuery {
159
159
  }
160
160
  }).filter(Boolean);
161
161
  const is_distinc_count = `${v}`.includes('distinc');
162
- const simple = is_distinc_count ? key : (exprs.length == 1 ? fns[0].key : false);
162
+ const simple = is_distinc_count ? key : (exprs.length == 1 && fns[0] ? fns[0].key : false);
163
163
  const pipelines = [
164
164
  ...$match.length > 0 ? [{ $match }] : [],
165
165
  {
@@ -238,34 +238,14 @@ export class MongoQuery {
238
238
  if (k.endsWith(':like'))
239
239
  return p;
240
240
  const [key, expression] = k.split(':');
241
- const map = {
242
- eq: () => ({ $eq: value }),
243
- lt: () => ({ $lt: !isNaN(Number(value)) ? Number(value) : 0 }),
244
- lte: () => ({ $lte: !isNaN(Number(value)) ? Number(value) : 0 }),
245
- gt: () => ({ $gt: !isNaN(Number(value)) ? Number(value) : 0 }),
246
- gte: () => ({ $gte: !isNaN(Number(value)) ? Number(value) : 0 }),
247
- ne: () => {
248
- return { $ne: value };
249
- },
250
- in: () => ({ $in: this.#parse_array(value) }),
251
- nin: () => ({ $nin: this.#parse_array(value) }),
252
- 'eq-number': () => ({ $eq: !isNaN(Number(value)) ? Number(value) : 0 }),
253
- 'neq-number': () => ({ $ne: !isNaN(Number(value)) ? Number(value) : 0 }),
254
- 'eq-boolean': () => ({ $eq: `${value}`.toLowerCase() == 'true' ? true : false }),
255
- 'neq-boolean': () => ({ $ne: `${value}`.toLowerCase() == 'false' ? false : true }),
256
- 'eq-null': () => ({ $eq: null }),
257
- 'neq-null': () => ({ $ne: null }),
258
- 'eq-oid': () => ({ $eq: ObjectId.isValid(value) ? new ObjectId(value) : value }),
259
- 'neq-oid': () => ({ $ne: ObjectId.isValid(value) ? new ObjectId(value) : value }),
260
- };
261
- const fn = map[expression || 'eq'];
262
- if (!fn)
241
+ const clause = this.#operator_clause(expression, value);
242
+ if (!clause)
263
243
  return p;
264
244
  return {
265
245
  ...p,
266
246
  [key]: {
267
247
  ...p[key] || {},
268
- ...fn()
248
+ ...clause
269
249
  }
270
250
  };
271
251
  }, {});
@@ -277,20 +257,75 @@ export class MongoQuery {
277
257
  const andMatch = and ? this.#build_match(and) : {};
278
258
  if (Object.keys(andMatch).length > 0)
279
259
  clauses.push(andMatch);
280
- const orMatch = or ? this.#build_match(or) : {};
281
- if (Object.keys(orMatch).length > 0) {
282
- clauses.push({ $or: Object.entries(orMatch).map(([k, v]) => ({ [k]: v })) });
283
- }
284
- const notMatch = not ? this.#build_match(not) : {};
285
- if (Object.keys(notMatch).length > 0) {
286
- clauses.push({ $nor: Object.entries(notMatch).map(([k, v]) => ({ [k]: v })) });
287
- }
260
+ const orBranches = or ? this.#branches(or) : [];
261
+ if (orBranches.length > 0)
262
+ clauses.push({ $or: orBranches });
263
+ const notBranches = not ? this.#branches(not) : [];
264
+ if (notBranches.length > 0)
265
+ clauses.push({ $nor: notBranches });
288
266
  if (clauses.length === 0)
289
267
  return {};
290
268
  if (clauses.length === 1)
291
269
  return clauses[0];
292
270
  return { $and: clauses };
293
271
  }
272
+ static #operator_clause(expression, value) {
273
+ const map = {
274
+ eq: () => ({ $eq: value }),
275
+ lt: () => ({ $lt: !isNaN(Number(value)) ? Number(value) : 0 }),
276
+ lte: () => ({ $lte: !isNaN(Number(value)) ? Number(value) : 0 }),
277
+ gt: () => ({ $gt: !isNaN(Number(value)) ? Number(value) : 0 }),
278
+ gte: () => ({ $gte: !isNaN(Number(value)) ? Number(value) : 0 }),
279
+ ne: () => ({ $ne: value }),
280
+ in: () => ({ $in: this.#parse_array(value) }),
281
+ nin: () => ({ $nin: this.#parse_array(value) }),
282
+ 'eq-number': () => ({ $eq: !isNaN(Number(value)) ? Number(value) : 0 }),
283
+ 'neq-number': () => ({ $ne: !isNaN(Number(value)) ? Number(value) : 0 }),
284
+ 'eq-boolean': () => ({ $eq: `${value}`.toLowerCase() == 'true' ? true : false }),
285
+ 'neq-boolean': () => ({ $ne: `${value}`.toLowerCase() == 'false' ? false : true }),
286
+ 'eq-null': () => ({ $eq: null }),
287
+ 'neq-null': () => ({ $ne: null }),
288
+ 'eq-oid': () => ({ $eq: ObjectId.isValid(value) ? new ObjectId(value) : value }),
289
+ 'neq-oid': () => ({ $ne: ObjectId.isValid(value) ? new ObjectId(value) : value }),
290
+ };
291
+ const fn = map[expression || 'eq'];
292
+ return fn ? fn() : null;
293
+ }
294
+ static #branches(filters) {
295
+ if (!filters)
296
+ return [];
297
+ const { ':and': and, ':or': or, ':not': not, ...rest } = filters;
298
+ const branches = [];
299
+ for (const [k, value] of Object.entries(rest)) {
300
+ if (k.startsWith('::'))
301
+ continue;
302
+ if (k.endsWith(':like')) {
303
+ const key = k.split(':like')[0];
304
+ branches.push({ [key]: { $regex: this.#escape_regex(`${value}`), $options: 'i' } });
305
+ continue;
306
+ }
307
+ const [key, expression] = k.split(':');
308
+ const clause = this.#operator_clause(expression, value);
309
+ if (clause)
310
+ branches.push({ [key]: clause });
311
+ }
312
+ if (and) {
313
+ const m = this.#build_match(and);
314
+ if (Object.keys(m).length > 0)
315
+ branches.push(m);
316
+ }
317
+ if (or) {
318
+ const m = this.#build_match({ ':or': or });
319
+ if (Object.keys(m).length > 0)
320
+ branches.push(m);
321
+ }
322
+ if (not) {
323
+ const m = this.#build_match({ ':not': not });
324
+ if (Object.keys(m).length > 0)
325
+ branches.push(m);
326
+ }
327
+ return branches;
328
+ }
294
329
  static #build_search_query(req) {
295
330
  const search = req.query[":search"];
296
331
  return search ? [{ $match: { $text: { $search: `${search}` } } }] : [];
@@ -489,8 +524,9 @@ export class MongoQuery {
489
524
  return $sort;
490
525
  }
491
526
  static async query(req, collection) {
492
- if (!req.is_collection) {
493
- const { id, _id: _rawId, ...keysWithoutId } = req.keys;
527
+ const request = { ...req, keys: req.keys ?? {}, query: req.query ?? {} };
528
+ if (!request.is_collection) {
529
+ const { id, _id: _rawId, ...keysWithoutId } = request.keys;
494
530
  const aggregates = [
495
531
  {
496
532
  $match: {
@@ -514,19 +550,19 @@ export class MongoQuery {
514
550
  summary: {}
515
551
  };
516
552
  }
517
- const is_cursor_paging = req.query[':after'] || req.query[':before'] || req.query[':around'] || !req.query[':page'];
518
- const $sort = this.#get_sorter(req);
553
+ const is_cursor_paging = request.query[':after'] || request.query[':before'] || request.query[':around'] || !request.query[':page'];
554
+ const $sort = this.#get_sorter(request);
519
555
  const pipelines = [
520
556
  { $sort },
521
- ...this.#build_query_filter(req),
522
- ...this.#build_search_query(req),
557
+ ...this.#build_query_filter(request),
558
+ ...this.#build_search_query(request),
523
559
  ...this.#rename_id(),
524
- ...is_cursor_paging ? this.#build_cursor_paging($sort, req) : this.#build_offset_paging(req)
560
+ ...is_cursor_paging ? this.#build_cursor_paging($sort, request) : this.#build_offset_paging(request)
525
561
  ];
526
562
  const response = await collection.aggregate(pipelines).toArray();
527
563
  return {
528
564
  ...response[0],
529
- limit: this.#get_limit(req)
565
+ limit: this.#get_limit(request)
530
566
  };
531
567
  }
532
568
  }
@@ -7,9 +7,9 @@ export type MongoDoc<T> = T & {
7
7
  export type DefaultsResolver<T> = (input: Partial<T>) => Partial<T>;
8
8
  export declare class CollectionDef<T> {
9
9
  readonly collection: string;
10
- readonly defaults?: DefaultsResolver<T>;
10
+ readonly defaults?: DefaultsResolver<T> | undefined;
11
11
  readonly _type: T;
12
- constructor(collection: string, defaults?: DefaultsResolver<T>);
12
+ constructor(collection: string, defaults?: DefaultsResolver<T> | undefined);
13
13
  }
14
14
  export declare function defineCollection<T>(config: {
15
15
  collection: string;
@@ -4,6 +4,9 @@ function hydrate(doc) {
4
4
  return null;
5
5
  const oid = doc._id;
6
6
  Object.defineProperty(doc, '_id', { value: oid, enumerable: false, configurable: true, writable: true });
7
+ if (Object.prototype.hasOwnProperty.call(doc, '__v')) {
8
+ Object.defineProperty(doc, '__v', { value: doc.__v, enumerable: false, configurable: true, writable: true });
9
+ }
7
10
  Object.defineProperty(doc, 'id', {
8
11
  value: oid ? oid.toString() : undefined,
9
12
  enumerable: true,
@@ -1 +1 @@
1
- {"root":["../src/cursor.ts","../src/datachangepayload.ts","../src/mongodatasource.ts","../src/mongoquery.ts","../src/mongodbcollection.ts","../src/mongodbrealtime.ts","../src/smartcache.ts","../src/index.ts"],"version":"5.9.3"}
1
+ {"root":["../src/cursor.ts","../src/datachangepayload.ts","../src/mongodatasource.ts","../src/mongoquery.ts","../src/mongodbcollection.ts","../src/mongodbrealtime.ts","../src/smartcache.ts","../src/index.ts"],"version":"6.0.3"}
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "repository": {
7
7
  "url": "git@github.com:livequery/mongodb.git"
8
8
  },
9
- "version": "2.0.153",
9
+ "version": "2.0.154",
10
10
  "description": "MongoDB datasource mapping for @livequery ecosystem",
11
11
  "main": "./build/src/index.js",
12
12
  "types": "./build/src/index.d.ts",
@@ -30,8 +30,8 @@
30
30
  },
31
31
  "scripts": {
32
32
  "test": "bun test",
33
- "build": "rm -rf build; tsc -b .",
34
- "deploy": "rm -rf build && yarn build; git add .; git commit -m \"Update\"; git push origin master; npm publish --access public"
33
+ "build": "rm -rf build && tsc -b .",
34
+ "deploy": "rm -rf build && yarn build && git add . && git commit -m \"Update\" && git push origin main && npm publish --access public"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "mongodb": "^6.20.0"