@airoom/nextmin-node 1.4.6 → 2.0.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.
Files changed (40) hide show
  1. package/README.md +48 -5
  2. package/dist/api/apiRouter.d.ts +2 -0
  3. package/dist/api/apiRouter.js +67 -21
  4. package/dist/api/router/mountCrudRoutes.js +207 -220
  5. package/dist/api/router/mountFindRoutes.js +2 -49
  6. package/dist/api/router/mountSearchRoutes.js +10 -52
  7. package/dist/api/router/mountSearchRoutes_extended.js +7 -48
  8. package/dist/api/router/utils.js +20 -7
  9. package/dist/cli.d.ts +1 -0
  10. package/dist/cli.js +83 -0
  11. package/dist/database/DatabaseAdapter.d.ts +7 -0
  12. package/dist/database/NMAdapter.d.ts +41 -0
  13. package/dist/database/NMAdapter.js +979 -0
  14. package/dist/database/QueryEngine.d.ts +14 -0
  15. package/dist/database/QueryEngine.js +215 -0
  16. package/dist/database/utils.d.ts +2 -0
  17. package/dist/database/utils.js +21 -0
  18. package/dist/index.d.ts +4 -1
  19. package/dist/index.js +11 -5
  20. package/dist/models/BaseModel.d.ts +16 -0
  21. package/dist/models/BaseModel.js +32 -4
  22. package/dist/policy/authorize.js +95 -38
  23. package/dist/schemas/Users.json +66 -30
  24. package/dist/services/RealtimeService.d.ts +20 -0
  25. package/dist/services/RealtimeService.js +93 -0
  26. package/dist/services/SchemaService.d.ts +3 -0
  27. package/dist/services/SchemaService.js +6 -2
  28. package/dist/utils/DefaultDataInitializer.js +10 -2
  29. package/dist/utils/Events.d.ts +34 -0
  30. package/dist/utils/Events.js +55 -0
  31. package/dist/utils/Logger.js +12 -10
  32. package/dist/utils/QueryCache.d.ts +16 -0
  33. package/dist/utils/QueryCache.js +106 -0
  34. package/dist/utils/SchemaLoader.d.ts +5 -0
  35. package/dist/utils/SchemaLoader.js +45 -3
  36. package/package.json +19 -4
  37. package/dist/database/InMemoryAdapter.d.ts +0 -15
  38. package/dist/database/InMemoryAdapter.js +0 -71
  39. package/dist/database/MongoAdapter.d.ts +0 -52
  40. package/dist/database/MongoAdapter.js +0 -410
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Events = exports.events = void 0;
7
+ exports.getModelEvent = getModelEvent;
8
+ const events_1 = require("events");
9
+ const Logger_1 = __importDefault(require("./Logger"));
10
+ /**
11
+ * NextMinEvents is a central event emitter for the NextMin ecosystem.
12
+ * It allows components to hook into CRUD and system events.
13
+ */
14
+ class NextMinEvents extends events_1.EventEmitter {
15
+ constructor() {
16
+ super();
17
+ // Increase max listeners to avoid warnings in complex apps
18
+ this.setMaxListeners(100);
19
+ }
20
+ /**
21
+ * Typed emit to provide better DX (Developer Experience)
22
+ */
23
+ emitEvent(event, payload) {
24
+ Logger_1.default.info('NextMinEvents', `Emitting event: ${event}`);
25
+ this.emit(event, payload);
26
+ }
27
+ }
28
+ // Singleton instance
29
+ exports.events = new NextMinEvents();
30
+ // Standard event constants
31
+ exports.Events = {
32
+ // Document events
33
+ BEFORE_CREATE: 'before:doc:create',
34
+ AFTER_CREATE: 'after:doc:create',
35
+ BEFORE_UPDATE: 'before:doc:update',
36
+ AFTER_UPDATE: 'after:doc:update',
37
+ BEFORE_DELETE: 'before:doc:delete',
38
+ AFTER_DELETE: 'after:doc:delete',
39
+ BEFORE_READ: 'before:doc:read',
40
+ AFTER_READ: 'after:doc:read',
41
+ // Auth events
42
+ AUTH_LOGIN: 'auth:login',
43
+ AUTH_LOGOUT: 'auth:logout',
44
+ AUTH_SIGNUP: 'auth:signup',
45
+ // System events
46
+ SCHEMA_UPDATE: 'schema:update',
47
+ SERVER_START: 'server:start',
48
+ SERVER_STOP: 'server:stop',
49
+ };
50
+ /**
51
+ * Helper to generate model-specific event names
52
+ */
53
+ function getModelEvent(modelName, action, phase = 'after') {
54
+ return `${modelName.toLowerCase()}:${phase}:${action}`;
55
+ }
@@ -9,8 +9,7 @@ const util_1 = require("util");
9
9
  const path_1 = __importDefault(require("path"));
10
10
  class Logger {
11
11
  constructor() {
12
- const env = process.env.NODE_ENV || 'development';
13
- this.isDevelopment = env === 'development';
12
+ this.isDevelopment = process.env.APP_MODE !== 'production' && process.env.NODE_ENV !== 'production';
14
13
  }
15
14
  getCallerInfo() {
16
15
  const originalPrepareStackTrace = Error.prepareStackTrace;
@@ -24,12 +23,11 @@ class Logger {
24
23
  !frame.getFileName()?.includes('Logger.ts') &&
25
24
  !frame.getFunctionName()?.includes('getCallerInfo'));
26
25
  if (!callerFrame) {
27
- return 'unknown:0:0';
26
+ return 'unknown:0';
28
27
  }
29
- const fileName = path_1.default.relative(process.cwd(), callerFrame.getFileName() || 'unknown');
28
+ const fileName = path_1.default.basename(callerFrame.getFileName() || 'unknown');
30
29
  const lineNumber = callerFrame.getLineNumber() || 0;
31
- const columnNumber = callerFrame.getColumnNumber() || 0;
32
- return `${fileName}:${lineNumber}:${columnNumber}`;
30
+ return `${fileName}:${lineNumber}`;
33
31
  }
34
32
  formatMessage(level, label, messages) {
35
33
  const callerInfo = this.getCallerInfo();
@@ -66,12 +64,16 @@ class Logger {
66
64
  }
67
65
  }
68
66
  warn(label, ...messages) {
69
- const formatted = this.formatMessage('WARN', label, messages);
70
- console.warn(formatted);
67
+ if (this.isDevelopment) {
68
+ const formatted = this.formatMessage('WARN', label, messages);
69
+ console.warn(formatted);
70
+ }
71
71
  }
72
72
  error(label, ...messages) {
73
- const formatted = this.formatMessage('ERROR', label, messages);
74
- console.error(formatted);
73
+ if (this.isDevelopment) {
74
+ const formatted = this.formatMessage('ERROR', label, messages);
75
+ console.error(formatted);
76
+ }
75
77
  }
76
78
  }
77
79
  exports.Logger = Logger;
@@ -0,0 +1,16 @@
1
+ export interface CacheConfig {
2
+ ttl?: number;
3
+ enabled?: boolean;
4
+ }
5
+ export declare class QueryCache {
6
+ private cache;
7
+ private enabled;
8
+ private defaultTtl;
9
+ constructor(config?: CacheConfig);
10
+ generateKey(collection: string, operation: string, args: any): Promise<string>;
11
+ private sortObjectKeys;
12
+ get<T>(key: string): Promise<T | null>;
13
+ set(key: string, value: any, ttl?: number): Promise<void>;
14
+ invalidateCollection(collection: string): Promise<void>;
15
+ private getCollectionVersion;
16
+ }
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.QueryCache = void 0;
7
+ const keyv_1 = __importDefault(require("keyv"));
8
+ const redis_1 = __importDefault(require("@keyv/redis"));
9
+ const Logger_1 = __importDefault(require("./Logger"));
10
+ class QueryCache {
11
+ constructor(config = {}) {
12
+ this.enabled = config.enabled !== false; // Enabled by default
13
+ this.defaultTtl = config.ttl || 60000; // 60 seconds default
14
+ const redisUrl = process.env.REDIS_URL;
15
+ if (redisUrl) {
16
+ try {
17
+ const store = new redis_1.default(redisUrl);
18
+ this.cache = new keyv_1.default({ store });
19
+ Logger_1.default.info('QueryCache', `Initialized with Redis store at ${redisUrl}`);
20
+ }
21
+ catch (err) {
22
+ Logger_1.default.error('QueryCache', 'Failed to initialize Redis store, falling back to basic map', err);
23
+ this.cache = new keyv_1.default();
24
+ }
25
+ }
26
+ else {
27
+ // Falls back to in-memory map
28
+ this.cache = new keyv_1.default();
29
+ Logger_1.default.info('QueryCache', 'Initialized with in-memory store (no REDIS_URL provided)');
30
+ }
31
+ this.cache.on('error', (err) => Logger_1.default.warn('QueryCache', 'Connection Error', err));
32
+ }
33
+ async generateKey(collection, operation, args) {
34
+ try {
35
+ const version = await this.getCollectionVersion(collection);
36
+ const sortedArgs = this.sortObjectKeys(args);
37
+ const strArgs = JSON.stringify(sortedArgs);
38
+ return `nm:cache:${collection}:v${version}:${operation}:${strArgs}`;
39
+ }
40
+ catch (e) {
41
+ // Fallback if JSON.stringify fails (e.g. circular refs, though unlikely in simple queries)
42
+ const v = await this.getCollectionVersion(collection);
43
+ return `nm:cache:${collection}:v${v}:${operation}:${Date.now()}`;
44
+ }
45
+ }
46
+ sortObjectKeys(obj) {
47
+ if (obj === null || typeof obj !== 'object') {
48
+ return obj;
49
+ }
50
+ if (Array.isArray(obj)) {
51
+ return obj.map(item => this.sortObjectKeys(item));
52
+ }
53
+ const sortedObj = {};
54
+ Object.keys(obj).sort().forEach(key => {
55
+ sortedObj[key] = this.sortObjectKeys(obj[key]);
56
+ });
57
+ return sortedObj;
58
+ }
59
+ async get(key) {
60
+ if (!this.enabled)
61
+ return null;
62
+ try {
63
+ const data = await this.cache.get(key);
64
+ if (data) {
65
+ // Return a deep clone to prevent external mutation of cached objects
66
+ return JSON.parse(JSON.stringify(data));
67
+ }
68
+ return null;
69
+ }
70
+ catch (err) {
71
+ Logger_1.default.warn('QueryCache', `Failed to get key ${key}`, err);
72
+ return null;
73
+ }
74
+ }
75
+ async set(key, value, ttl) {
76
+ if (!this.enabled || value === undefined)
77
+ return;
78
+ try {
79
+ // Store a clean copy
80
+ const cleanValue = JSON.parse(JSON.stringify(value));
81
+ await this.cache.set(key, cleanValue, ttl || this.defaultTtl);
82
+ }
83
+ catch (err) {
84
+ Logger_1.default.warn('QueryCache', `Failed to set key ${key}`, err);
85
+ }
86
+ }
87
+ async invalidateCollection(collection) {
88
+ if (!this.enabled)
89
+ return;
90
+ try {
91
+ // Increment collection version:
92
+ const vKey = `nm:collection:version:${collection}`;
93
+ let currentVersion = await this.cache.get(vKey) || 0;
94
+ await this.cache.set(vKey, currentVersion + 1, 0); // never expire the version
95
+ Logger_1.default.info('QueryCache', `Invalidated cache for collection: ${collection} (version bumped)`);
96
+ }
97
+ catch (err) {
98
+ Logger_1.default.warn('QueryCache', `Failed to invalidate collection ${collection}`, err);
99
+ }
100
+ }
101
+ async getCollectionVersion(collection) {
102
+ const vKey = `nm:collection:version:${collection}`;
103
+ return (await this.cache.get(vKey)) || 0;
104
+ }
105
+ }
106
+ exports.QueryCache = QueryCache;
@@ -6,6 +6,11 @@ type PublicSchema = Omit<Schema, 'attributes'> & {
6
6
  showCount: boolean;
7
7
  attributes: PublicAttributes;
8
8
  allowedMethods: Schema['allowedMethods'];
9
+ extends?: string;
10
+ group?: string;
11
+ schemaType?: string;
12
+ columnsSelector?: string[];
13
+ actions?: Schema['actions'];
9
14
  };
10
15
  export declare class SchemaLoader {
11
16
  private emitter;
@@ -138,13 +138,14 @@ class SchemaLoader {
138
138
  continue;
139
139
  if (Object.prototype.hasOwnProperty.call(mergedAttrs, key)) {
140
140
  const val = mergedAttrs[key];
141
+ const isInherited = !Object.prototype.hasOwnProperty.call(schema.attributes, key);
141
142
  if (Array.isArray(val) && val[0] && typeof val[0] === 'object') {
142
143
  const { unique: _u, index: _i, ...rest } = val[0];
143
- mergedAttrs[key] = [{ ...rest }];
144
+ mergedAttrs[key] = [{ ...rest, inherited: isInherited }];
144
145
  }
145
146
  else if (val && typeof val === 'object') {
146
147
  const { unique: _u, index: _i, ...rest } = val;
147
- mergedAttrs[key] = { ...rest };
148
+ mergedAttrs[key] = { ...rest, inherited: isInherited };
148
149
  }
149
150
  }
150
151
  }
@@ -153,14 +154,50 @@ class SchemaLoader {
153
154
  ...baseSchema.allowedMethods,
154
155
  ...schema.allowedMethods,
155
156
  };
157
+ // Merge access (policies/masks/reachability)
158
+ if (baseSchema.access) {
159
+ const baseAccess = baseSchema.access;
160
+ if (!schema.access)
161
+ schema.access = {};
162
+ // 1. Selective Merge for bypassPrivacy (combine roles)
163
+ if (baseAccess.bypassPrivacy?.roles) {
164
+ if (!schema.access.bypassPrivacy)
165
+ schema.access.bypassPrivacy = {};
166
+ const baseRoles = baseAccess.bypassPrivacy.roles;
167
+ const currentRoles = schema.access.bypassPrivacy.roles || [];
168
+ schema.access.bypassPrivacy.roles = Array.from(new Set([...baseRoles, ...currentRoles]));
169
+ }
170
+ // 2. Inherit masks/filters/restrictions ONLY if not defined in child
171
+ // Note: We DO NOT inherit public/authenticated/roles reachability here.
172
+ // Child schemas should manage their own reachability.
173
+ if (!schema.access.readMask)
174
+ schema.access.readMask = baseAccess.readMask;
175
+ if (!schema.access.writeDeny)
176
+ schema.access.writeDeny = baseAccess.writeDeny;
177
+ if (!schema.access.queryFilter)
178
+ schema.access.queryFilter = baseAccess.queryFilter;
179
+ if (!schema.access.createDefaults)
180
+ schema.access.createDefaults = baseAccess.createDefaults;
181
+ if (!schema.access.restrictions)
182
+ schema.access.restrictions = baseAccess.restrictions;
183
+ if (!schema.access.conditions)
184
+ schema.access.conditions = baseAccess.conditions;
185
+ }
156
186
  // Inject hidden link field to base (used for storage join)
157
187
  // Ensure hidden link field
158
188
  const linkField = 'baseId';
159
189
  if (!schema.attributes[linkField]) {
190
+ const isUserExt = baseName.toLowerCase() === 'users';
160
191
  schema.attributes[linkField] = {
161
192
  type: 'ObjectId',
162
193
  ref: baseName,
163
- private: true,
194
+ private: !isUserExt,
195
+ required: false,
196
+ label: isUserExt ? 'Associate User Account (Optional)' : 'Base Record',
197
+ show: isUserExt ? 'username' : 'id',
198
+ index: true,
199
+ unique: isUserExt,
200
+ sparse: isUserExt,
164
201
  };
165
202
  }
166
203
  }
@@ -303,6 +340,11 @@ class SchemaLoader {
303
340
  showCount: s.showCount,
304
341
  allowedMethods: s.allowedMethods,
305
342
  attributes: attributesWithTimestamps,
343
+ extends: s.extends,
344
+ group: s.group,
345
+ schemaType: s.schemaType,
346
+ columnsSelector: s.columnsSelector,
347
+ actions: s.actions,
306
348
  };
307
349
  }
308
350
  return out;
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@airoom/nextmin-node",
3
- "version": "1.4.6",
3
+ "version": "2.0.1",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "rm -rf dist && tsc --project tsconfig.json && copyfiles -u 2 \"src/schemas/**/*\" dist/schemas",
9
9
  "watch": "tsc --project tsconfig.json --watch",
10
+ "test": "vitest run",
11
+ "test:watch": "vitest",
12
+ "test:coverage": "vitest run --coverage",
10
13
  "prepublishOnly": "npm run build && npm pack --dry-run | (! grep -E '\\bsrc/|\\.map$')"
11
14
  },
12
15
  "dependencies": {
@@ -17,19 +20,31 @@
17
20
  "chokidar": "^4.0.3",
18
21
  "fast-glob": "^3.3.1",
19
22
  "jsonwebtoken": "^9.0.2",
23
+ "keyv": "^5.2.3",
20
24
  "kleur": "^4.1.5",
21
- "mongoose": "^8.17.0",
25
+ "@keyv/redis": "^4.0.1",
26
+ "mongodb": "^6.21.0",
27
+ "mongoose": "^8.18.0",
22
28
  "mongoose-autopopulate": "^1.1.0",
29
+ "mssql": "^12.2.0",
23
30
  "multer": "^2.0.2",
24
- "socket.io": "^4.7.5"
31
+ "mysql2": "^3.16.1",
32
+ "pg": "^8.17.2",
33
+ "reflect-metadata": "^0.2.2",
34
+ "socket.io": "^4.7.5",
35
+ "sqlite3": "^5.1.7",
36
+ "typeorm": "^0.3.28"
25
37
  },
26
38
  "devDependencies": {
27
39
  "@types/bcrypt": "^6.0.0",
28
40
  "@types/chokidar": "^2.1.7",
29
41
  "@types/jsonwebtoken": "^9.0.10",
30
42
  "@types/multer": "^2.0.0",
43
+ "@vitest/coverage-v8": "^4.0.17",
31
44
  "copyfiles": "^2.4.1",
32
- "typescript": "^5.3.3"
45
+ "ts-node": "^10.9.2",
46
+ "typescript": "^5.3.3",
47
+ "vitest": "^4.0.17"
33
48
  },
34
49
  "files": [
35
50
  "dist",
@@ -1,15 +0,0 @@
1
- import { DatabaseAdapter, FieldIndexSpec } from './DatabaseAdapter';
2
- import { ReadOptions, Schema } from '../models/BaseModel';
3
- export declare class InMemoryAdapter implements DatabaseAdapter {
4
- private data;
5
- connect(): Promise<void>;
6
- disconnect(): Promise<void>;
7
- registerSchemas(schemas: Record<string, Schema>): void;
8
- create(collection: string, data: any, schemaDefinition: Schema): Promise<any>;
9
- read(collection: string, query: any, limit?: number, skip?: number, schemaDefinition?: Schema, _includePrivateFields?: boolean, _options?: ReadOptions): Promise<any[]>;
10
- update(collection: string, id: string, data: any, schemaDefinition: Schema): Promise<any>;
11
- delete(collection: string, id: string, schemaDefinition: Schema): Promise<any>;
12
- count(collection: string, query: any, schemaDefinition: Schema): Promise<number>;
13
- syncIndexes(_modelName: string, _desired: FieldIndexSpec): Promise<void>;
14
- private generateId;
15
- }
@@ -1,71 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InMemoryAdapter = void 0;
4
- class InMemoryAdapter {
5
- constructor() {
6
- this.data = {};
7
- }
8
- async connect() {
9
- // No-op for in-memory
10
- }
11
- async disconnect() {
12
- // No-op for in-memory
13
- }
14
- registerSchemas(schemas) {
15
- // No-op for in-memory, but you could validate schemas here if needed
16
- }
17
- async create(collection, data, schemaDefinition) {
18
- if (!this.data[collection]) {
19
- this.data[collection] = [];
20
- }
21
- // Generate a simple id if not present
22
- if (!data.id) {
23
- data.id = `${Date.now()}_${Math.random()}`;
24
- }
25
- this.data[collection].push(data);
26
- return data;
27
- }
28
- async read(collection, query, limit, skip, schemaDefinition, _includePrivateFields, _options) {
29
- const allData = this.data[collection] || [];
30
- let results = allData.filter((item) => {
31
- return Object.entries(query).every(([key, value]) => item[key] === value);
32
- });
33
- if (limit !== undefined && skip !== undefined) {
34
- results = results.slice(skip, skip + limit);
35
- }
36
- return results;
37
- }
38
- async update(collection, id, data, schemaDefinition) {
39
- const allData = this.data[collection] || [];
40
- const index = allData.findIndex((item) => item.id === id);
41
- if (index === -1) {
42
- throw new Error(`Document with id ${id} not found in collection '${collection}'`);
43
- }
44
- this.data[collection][index] = { ...allData[index], ...data };
45
- return this.data[collection][index];
46
- }
47
- async delete(collection, id, schemaDefinition) {
48
- const allData = this.data[collection] || [];
49
- const index = allData.findIndex((item) => item.id === id);
50
- if (index === -1) {
51
- throw new Error(`Document with id ${id} not found in collection '${collection}'`);
52
- }
53
- const deleted = this.data[collection].splice(index, 1)[0];
54
- return deleted;
55
- }
56
- async count(collection, query, schemaDefinition) {
57
- const allData = this.data[collection] || [];
58
- // Count documents matching the query
59
- const results = allData.filter((item) => {
60
- return Object.entries(query).every(([key, value]) => item[key] === value);
61
- });
62
- return results.length;
63
- }
64
- async syncIndexes(_modelName, _desired) {
65
- // no-op for memory adapter
66
- }
67
- generateId() {
68
- return Math.random().toString(36).substr(2, 9);
69
- }
70
- }
71
- exports.InMemoryAdapter = InMemoryAdapter;
@@ -1,52 +0,0 @@
1
- import { DatabaseAdapter, FieldIndexSpec } from './DatabaseAdapter';
2
- import { ReadOptions, Schema as NextMinSchema } from '../models/BaseModel';
3
- export declare class MongoAdapter implements DatabaseAdapter {
4
- private url;
5
- private dbName;
6
- private connection;
7
- /** Map keyed by lowercased modelName (e.g., "users", "roles") → Mongoose Model */
8
- private models;
9
- constructor(url: string, dbName: string);
10
- connect(): Promise<void>;
11
- disconnect(): Promise<void>;
12
- /**
13
- * Register (and re-register) all schemas.
14
- * - Drops compiled models that no longer exist.
15
- * - Recompiles every current model so validators reflect latest schema.
16
- */
17
- registerSchemas(schemas: Record<string, NextMinSchema>): Promise<void>;
18
- /** Optional hook used by the router when schemas are removed. */
19
- unregisterSchemas(names: string[]): Promise<void>;
20
- /** Optional single-model drop hook. */
21
- dropModel(nameRaw: string): Promise<void>;
22
- /**
23
- * Delete a compiled model by case-insensitive match.
24
- * Works whether we compiled it as "Users" or "users".
25
- */
26
- private safeDeleteModel;
27
- private safeDropCollection;
28
- /** Build a fresh Mongoose schema from our NextMin schema definition. */
29
- private buildMongooseSchema;
30
- private mapAttribute;
31
- private mapScalar;
32
- /**
33
- * Resolve (or lazily create) the compiled model for a schema.
34
- * Uses schema.modelName as the Mongoose model name and
35
- * (schema.collection ?? modelName).toLowerCase() as the collection.
36
- */
37
- private getModel;
38
- private getSchema;
39
- private convertQueryFieldsToObjectId;
40
- private toAppObject;
41
- create(collection: string, data: any, schemaDefinition: NextMinSchema, includePrivateFields?: boolean): Promise<any>;
42
- read(collection: string, query: any, limit: number | undefined, skip: number | undefined, schemaDefinition: NextMinSchema, includePrivateFields?: boolean, options?: ReadOptions): Promise<any[]>;
43
- count(collection: string, query: any, schemaDefinition: NextMinSchema): Promise<number>;
44
- update(collection: string, id: string, data: any, schemaDefinition: NextMinSchema, includePrivateFields?: boolean): Promise<any>;
45
- delete(collection: string, id: string, schemaDefinition: NextMinSchema, includePrivateFields?: boolean): Promise<any>;
46
- private getNativeCollectionByModelName;
47
- /** Create/drop single-field indexes based on schema plan.
48
- * Only touches indexes named with the prefix below (won't touch user indexes).
49
- */
50
- private managedIndexName;
51
- syncIndexes(modelName: string, spec: FieldIndexSpec): Promise<void>;
52
- }