@livequery/mongoose 2.0.27 → 2.0.48

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