@livequery/mongoose 2.0.25 → 2.0.47

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.
@@ -334,6 +334,8 @@ export class MongoQuery {
334
334
  ];
335
335
  }
336
336
  static #build_cursor_paging($sort, req) {
337
+ if (req.options[':after'] || req.options[':before'] || req.options[':around']) {
338
+ }
337
339
  const { pipelines, summary } = this.#parse_summary(req);
338
340
  const limit = this.#get_limit(req);
339
341
  return [
@@ -1,23 +1,12 @@
1
1
  import { RouteOptions } from "./RouteOptions.js";
2
- import { LivequeryRequest, LivequeryBaseEntity, WebsocketSyncPayload, DatabaseEvent } from '@livequery/types';
3
- import { Observable } from "rxjs";
4
- import { Connection } from 'mongoose';
5
- export type MongooseDatasourceOptions<T> = Array<T & {
6
- refs: string[];
7
- }>;
8
- export type LivequeryDatasource<Options = {}, StreamPayload = {}, Connection = any> = {
9
- init(routes: MongooseDatasourceOptions<Options>, connections: {
10
- [name: string]: Connection;
11
- }): Promise<void>;
12
- query(query: LivequeryRequest): any;
13
- enable_realtime?: (stream: Observable<StreamPayload>) => Observable<WebsocketSyncPayload>;
2
+ import { LivequeryRequest, LivequeryBaseEntity } from '@livequery/types';
3
+ import mongoose, { Connection } from 'mongoose';
4
+ export type LivequeryDatasource<T> = {
5
+ query(query: LivequeryRequest, options: T, connection: any): any;
14
6
  };
15
- export declare class MongooseDatasource implements LivequeryDatasource<RouteOptions, DatabaseEvent, Connection> {
7
+ export declare class MongooseDatasource implements LivequeryDatasource<RouteOptions> {
16
8
  #private;
17
- init(routes: MongooseDatasourceOptions<RouteOptions>, connections: {
18
- [name: string]: Connection;
19
- }): Promise<void>;
20
- query(query: LivequeryRequest): Promise<import("mongodb").DeleteResult | import("mongoose").UpdateWriteOpResult | {
9
+ query(_: LivequeryRequest, config: RouteOptions, connection: Connection): Promise<mongoose.mongo.DeleteResult | mongoose.UpdateWriteOpResult | {
21
10
  items: any[];
22
11
  summary: any;
23
12
  has: {
@@ -41,12 +30,15 @@ export declare class MongooseDatasource implements LivequeryDatasource<RouteOpti
41
30
  } | {
42
31
  item: any;
43
32
  }>;
44
- enable_realtime<T extends LivequeryBaseEntity = LivequeryBaseEntity>(d: Observable<DatabaseEvent>): Observable<{
45
- new_data: LivequeryBaseEntity;
46
- old_data: LivequeryBaseEntity;
47
- table: string;
48
- type: "added" | "removed" | "modified";
49
- old_ref: string;
50
- new_ref: string;
33
+ normalizeRef(req: LivequeryRequest, schema: mongoose.Schema): Promise<LivequeryRequest | {
34
+ keys: any;
35
+ body: any;
36
+ ref: string;
37
+ is_collection: boolean;
38
+ collection_ref: string;
39
+ schema_collection_ref: string;
40
+ doc_id?: string;
41
+ options: import("@livequery/types").QueryOption<LivequeryBaseEntity>;
42
+ method?: string;
51
43
  }>;
52
44
  }
@@ -1,44 +1,19 @@
1
1
  import { Cursor } from './Cursor.js';
2
- import { map, mergeAll } from "rxjs";
3
2
  import { MongoQuery } from "./MongoQuery.js";
3
+ import mongoose from 'mongoose';
4
4
  import { ObjectId } from 'bson';
5
+ import { SmartCache } from './SmartCache.js';
5
6
  export class MongooseDatasource {
6
- #refs = new Map();
7
- #routes = new Map();
8
- #realtime_collections = new Map();
9
- #conections = {};
10
- async init(routes, connections) {
11
- this.#conections = { ...connections };
12
- for (const { refs, ...options } of routes) {
13
- for (const ref of refs) {
14
- const schema_ref = ref.replaceAll(':', '');
15
- this.#routes.set(schema_ref, options);
16
- this.#refs.set(options.schema, new Set([
17
- ...this.#refs.get(options.schema) || [],
18
- ref
19
- ]));
20
- if (options.realtime) {
21
- const table_name = options.schema.options.collection;
22
- const $ = schema_ref.split('/');
23
- const is_collection_ref = $.length % 2 == 1;
24
- this.#realtime_collections.set(table_name, new Set([
25
- ...this.#realtime_collections.get(table_name) || [],
26
- is_collection_ref ? schema_ref : $.slice(0, -1).join('/'),
27
- schema_ref
28
- ]));
29
- }
30
- }
31
- }
32
- }
33
- async query(query) {
34
- const config = this.#routes.get(query.schema_ref);
35
- if (!config)
36
- throw { status: 500, code: 'REF_NOT_FOUND', message: 'Missing ref config in livequery system' };
37
- const db = await config.db?.(query) || process.env.DB_NAME;
38
- const connection = config.connection ? this.#conections[await config.connection(query)] : Object.values(this.#conections)[0];
7
+ #schemas = new SmartCache();
8
+ #models = new SmartCache();
9
+ async query(_, config, connection) {
10
+ const db = typeof config.db == 'function' ? await config.db(_) : config.db || process.env.DB_NAME || 'main';
39
11
  const schema = config.schema;
40
12
  const collection_name = schema.options.collection;
41
- const model = connection.useDb(db).model(collection_name, schema, collection_name, schema.options);
13
+ const model = await this.#models.get(`${db}::${collection_name}`, async () => {
14
+ return connection.model(collection_name, schema, collection_name);
15
+ });
16
+ const query = await this.normalizeRef(_, schema);
42
17
  if (query.method == 'get')
43
18
  return await this.#get(query, model);
44
19
  if (query.method == 'post')
@@ -153,64 +128,32 @@ export class MongooseDatasource {
153
128
  }, {});
154
129
  return await model.deleteOne(keys);
155
130
  }
156
- enable_realtime(d) {
157
- function parse_refs(ref, o, n) {
158
- const keys = ref.split('/').map((k, i) => {
159
- if (i % 2 == 0)
160
- return { v: { old_ref: k, new_ref: k } };
161
- if (Array.isArray(o[k]) || Array.isArray(n[k])) {
162
- return [
163
- ...Array.isArray(o[k]) ? o[k] : [],
164
- ...Array.isArray(n[k]) ? n[k] : []
165
- ].reduce((p, c) => {
166
- p.set(c, {
167
- old_ref: Array.isArray(o[k]) && o[k].includes(c) ? c : null,
168
- new_ref: Array.isArray(n[k]) && n[k].includes(c) ? c : null,
169
- });
170
- return p;
171
- }, new Map());
131
+ #convert(obj, fields) {
132
+ return {
133
+ ...obj,
134
+ ...[...fields].reduce((p, c) => {
135
+ if (obj[c] && typeof obj[c] == 'string' && mongoose.Types.ObjectId.isValid(obj[c])) {
136
+ return {
137
+ ...p,
138
+ [c]: new mongoose.Types.ObjectId(obj[c])
139
+ };
172
140
  }
173
- return {
174
- v: {
175
- old_ref: o[k],
176
- new_ref: n[k]
177
- }
178
- };
179
- });
180
- function parse(arr) {
181
- const v = arr[0];
182
- const x = v instanceof Map ? [...v] : Object.entries(v);
183
- return x.map(([k, w]) => {
184
- const { old_ref, new_ref } = w;
185
- const next = arr.slice(1);
186
- if (next.length == 0)
187
- return { old_ref, new_ref };
188
- const n = parse(next);
189
- return n.map(nn => {
190
- return {
191
- old_ref: `${old_ref}/${nn.old_ref}`,
192
- new_ref: `${new_ref}/${nn.new_ref}`
193
- };
194
- });
195
- }).flat(2);
196
- }
197
- return parse(keys);
198
- }
199
- return d.pipe(map((event) => {
200
- const refs = this.#realtime_collections.get(event.table);
201
- if (!refs)
202
- return [];
203
- return [...refs].map(ref => {
204
- const refs_list = parse_refs(ref, event.old_data, event.new_data);
205
- return refs_list.map(({ new_ref, old_ref }) => ({
206
- new_data: event.new_data,
207
- old_data: event.old_data,
208
- table: event.table,
209
- type: event.type,
210
- old_ref,
211
- new_ref
212
- }));
213
- });
214
- }), mergeAll(), mergeAll());
141
+ return p;
142
+ }, {})
143
+ };
144
+ }
145
+ async normalizeRef(req, schema) {
146
+ const fields = await this.#schemas.get(schema, async () => {
147
+ return new Set(Object.entries(schema.paths).filter(([k, v]) => {
148
+ return v.instance == 'ObjectID';
149
+ }).map(([k, v]) => k));
150
+ });
151
+ if (fields.size == 0)
152
+ return req;
153
+ return {
154
+ ...req,
155
+ keys: this.#convert(req.keys, fields),
156
+ body: this.#convert(req.body, fields)
157
+ };
215
158
  }
216
159
  }
@@ -3,6 +3,6 @@ import { Schema } from "mongoose";
3
3
  export type RouteOptions<T = any> = {
4
4
  realtime?: boolean;
5
5
  schema: Schema<T>;
6
- connection?: (req: LivequeryRequest) => Promise<string> | string;
7
- db?: (req: LivequeryRequest) => Promise<string> | string;
6
+ db?: string | ((req: LivequeryRequest) => Promise<string> | string);
7
+ object_ids_fields: string[];
8
8
  };
@@ -0,0 +1,4 @@
1
+ export declare class SmartCache {
2
+ #private;
3
+ get<T>(key: any, reslover: () => Promise<T>): Promise<any>;
4
+ }
@@ -0,0 +1,11 @@
1
+ export class SmartCache {
2
+ #storage = new Map();
3
+ async get(key, reslover) {
4
+ const cache = this.#storage.get(key);
5
+ if (cache)
6
+ return await cache;
7
+ const value = reslover();
8
+ this.#storage.set(key, value);
9
+ return await value;
10
+ }
11
+ }
@@ -1 +1 @@
1
- {"root":["../src/cursor.ts","../src/datachangepayload.ts","../src/mongoquery.ts","../src/mongoosedatasource.ts","../src/routeoptions.ts","../src/index.ts"],"version":"5.6.2"}
1
+ {"root":["../src/cursor.ts","../src/datachangepayload.ts","../src/mongoquery.ts","../src/mongoosedatasource.ts","../src/routeoptions.ts","../src/smartcache.ts","../src/index.ts"],"version":"5.9.3"}
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "repository": {
7
7
  "url": "git@github.com:livequery/mongoose.git"
8
8
  },
9
- "version": "2.0.25",
9
+ "version": "2.0.47",
10
10
  "description": "Mongoose datasource mapping for @livequery ecosystem",
11
11
  "main": "./build/src/index.js",
12
12
  "types": "./build/src/index.d.ts",