orange-dragonfly-model 0.12.1 → 0.13.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.
package/README.md CHANGED
@@ -7,6 +7,7 @@ An active-record model class for the Orange Dragonfly framework. Extends [`orang
7
7
  - [Installation](#installation)
8
8
  - [Quick start](#quick-start)
9
9
  - [Defining a model](#defining-a-model)
10
+ - [Typed data access](#typed-data-access)
10
11
  - [Field restrictions](#field-restrictions)
11
12
  - [CRUD operations](#crud-operations)
12
13
  - [Querying](#querying)
@@ -171,6 +172,65 @@ Default: `false` — unknown fields throw `OrangeDatabaseInputValidationError`.
171
172
 
172
173
  ---
173
174
 
175
+ ## Typed data access
176
+
177
+ By default `this.data` is typed as `Record<string, unknown>`, so accessing individual fields gives `unknown`. The exported `ModelData<S>` utility type derives a precise TypeScript type directly from a `validation_rules` schema, making field access fully type-safe.
178
+
179
+ **Three steps to opt in:**
180
+
181
+ 1. Declare the schema as a module-level `const` using `as const satisfies ODValidatorRulesSchema` to preserve literal type information.
182
+ 2. Return that const from `validation_rules` (drop the explicit `: ODValidatorRulesSchema` return-type annotation so TypeScript keeps the narrow type).
183
+ 3. Add `declare data: ModelData<typeof schema>` inside the subclass.
184
+
185
+ ```typescript
186
+ import Model, { type ModelData } from 'orange-dragonfly-model'
187
+ import type { ODValidatorRulesSchema } from 'orange-dragonfly-validator'
188
+
189
+ const articleSchema = {
190
+ id: { required: false, type: 'integer', min: 1 },
191
+ title: { required: true, type: 'string', min: 1, max: 255 },
192
+ body: { required: true, type: 'string', min: 1 },
193
+ author_id: { required: true, type: 'integer', min: 1 },
194
+ published: { required: false, type: 'boolean' },
195
+ created_at: { required: false, type: 'integer' },
196
+ updated_at: { required: false, type: 'integer' },
197
+ } as const satisfies ODValidatorRulesSchema
198
+
199
+ class Article extends Model {
200
+ static override get validation_rules() { return articleSchema }
201
+ declare data: ModelData<typeof articleSchema>
202
+ }
203
+
204
+ // Field access is now fully typed:
205
+ const article = await Article.find(1)
206
+ article.data.title // string
207
+ article.data.published // boolean
208
+ article.data.author_id // number
209
+ article.data.missing // TypeScript error — field not in schema
210
+ ```
211
+
212
+ **Schema type → TypeScript type mapping:**
213
+
214
+ | Validator type | TypeScript type |
215
+ |---|---|
216
+ | `'string'` | `string` |
217
+ | `'integer'`, `'number'` | `number` |
218
+ | `'boolean'` | `boolean` |
219
+ | `'null'` | `null` |
220
+ | `'object'` | `Record<string, unknown>` |
221
+ | `'array'` | `unknown[]` |
222
+ | `'function'` | `(...args: unknown[]) => unknown` |
223
+
224
+ When `type` is an array (e.g. `['string', 'null']`), the result is the union of the corresponding TypeScript types (`string | null`).
225
+
226
+ **Why `as const` is required.** Without it, TypeScript widens the string literal `'integer'` to the broad type `string`, and `ModelData` cannot resolve the mapping. `satisfies ODValidatorRulesSchema` validates the object against the schema without widening the inferred type.
227
+
228
+ **Why the schema lives outside the class.** `declare data: ModelData<typeof articleSchema>` inside the class body needs to reference a name that is already in scope. A static getter cannot be referenced this way without a circular reference.
229
+
230
+ The `declare data` line has no runtime cost — it is a type-only declaration that narrows the `Record<string, unknown>` inherited from `ActiveRecord`.
231
+
232
+ ---
233
+
174
234
  ## Field restrictions
175
235
 
176
236
  These getters return an array of field names that are blocked in specific operations. Attempting to pass a restricted field throws `OrangeDatabaseInputValidationError`.
package/dist/index.cjs CHANGED
@@ -138,28 +138,39 @@ var Model = class extends import_orange_dragonfly_orm2.ActiveRecord {
138
138
  * @param basicQuery Query to be used for adding conditions. By default a new SelectQuery is created.
139
139
  */
140
140
  static lookupQuery(data, basicQuery = null) {
141
- const rules = this.validation_rules;
142
- const q = basicQuery ?? this.selectQuery();
141
+ const cls = this;
142
+ const rules = cls.validation_rules;
143
+ const q = basicQuery ?? cls.selectQuery();
143
144
  const filtered_rules = {};
144
145
  for (const field of Object.keys(data)) {
145
146
  if (!Object.hasOwn(rules, field)) {
146
- if (this.ignore_extra_fields) {
147
+ if (cls.ignore_extra_fields) {
147
148
  continue;
148
149
  }
149
150
  const ex = new OrangeDatabaseInputValidationError("Parameters error");
150
- ex.info[field] = `Field "${field}" is not described for model ${this.name}`;
151
+ ex.info[field] = `Field "${field}" is not described for model ${cls.name}`;
151
152
  throw ex;
152
153
  }
153
- if (this.restricted_for_lookup.includes(field)) {
154
+ if (cls.restricted_for_lookup.includes(field)) {
154
155
  const ex = new OrangeDatabaseInputValidationError("Parameters error");
155
- ex.info[field] = `Field "${field}" is restricted for searching model ${this.name}`;
156
+ ex.info[field] = `Field "${field}" is restricted for searching model ${cls.name}`;
156
157
  throw ex;
157
158
  }
158
159
  q.where(field, data[field]);
159
160
  const rule = rules[field];
160
161
  filtered_rules[field] = Array.isArray(data[field]) ? { type: "array", children: { "*": rule } } : rule;
161
162
  }
162
- (0, import_orange_dragonfly_validator.parse)(filtered_rules, data, { strictMode: false });
163
+ try {
164
+ (0, import_orange_dragonfly_validator.parse)(filtered_rules, data, { strictMode: false });
165
+ } catch (e) {
166
+ if (e instanceof import_orange_dragonfly_validator.ODValidatorException) {
167
+ const message = `Model ${cls.name} lookup rules validation failed`;
168
+ console.error(message, e.info);
169
+ throw new OrangeDatabaseInputValidationError(message);
170
+ } else {
171
+ throw e;
172
+ }
173
+ }
163
174
  return q;
164
175
  }
165
176
  /**
@@ -167,20 +178,21 @@ var Model = class extends import_orange_dragonfly_orm2.ActiveRecord {
167
178
  * @param data
168
179
  */
169
180
  static async create(data) {
170
- const rules = this.validation_rules;
181
+ const cls = this;
182
+ const rules = cls.validation_rules;
171
183
  const new_data = {};
172
184
  for (const field of Object.keys(data)) {
173
185
  if (!Object.hasOwn(rules, field)) {
174
- if (this.ignore_extra_fields) {
186
+ if (cls.ignore_extra_fields) {
175
187
  continue;
176
188
  }
177
189
  const ex = new OrangeDatabaseInputValidationError("Parameters error");
178
- ex.info[field] = `Field "${field}" is not described for model ${this.name}`;
190
+ ex.info[field] = `Field "${field}" is not described for model ${cls.name}`;
179
191
  throw ex;
180
192
  }
181
- if (this.restricted_for_create.includes(field)) {
193
+ if (cls.restricted_for_create.includes(field)) {
182
194
  const ex = new OrangeDatabaseInputValidationError("Parameters error");
183
- ex.info[field] = `Field "${field}" is restricted for creating model ${this.name}`;
195
+ ex.info[field] = `Field "${field}" is restricted for creating model ${cls.name}`;
184
196
  throw ex;
185
197
  }
186
198
  new_data[field] = data[field];
@@ -276,7 +288,21 @@ var Model = class extends import_orange_dragonfly_orm2.ActiveRecord {
276
288
  }
277
289
  }
278
290
  }
279
- this.data = (0, import_orange_dragonfly_validator.parse)(rules, this.data, { strictMode: false });
291
+ try {
292
+ this.data = (0, import_orange_dragonfly_validator.parse)(rules, this.data, { strictMode: false });
293
+ } catch (e) {
294
+ if (e instanceof import_orange_dragonfly_validator.ODValidatorException) {
295
+ const message = `Model ${cls.name} rules validation failed`;
296
+ console.error(message, e.info);
297
+ const ex = new OrangeDatabaseInputValidationError(message);
298
+ for (const [key, msgs] of Object.entries(e.info)) {
299
+ ex.info[key] = Array.isArray(msgs) ? msgs[0] : msgs;
300
+ }
301
+ throw ex;
302
+ } else {
303
+ throw e;
304
+ }
305
+ }
280
306
  const custom_validation_errors = await this.custom_validation();
281
307
  if (custom_validation_errors && Object.keys(custom_validation_errors).length) {
282
308
  const ex = new OrangeDatabaseInputValidationError("Validation failed");
@@ -294,12 +320,18 @@ var Model = class extends import_orange_dragonfly_orm2.ActiveRecord {
294
320
  }
295
321
  }
296
322
  }
297
- if (relation_errors.length) {
298
- const ex = new OrangeDatabaseInputValidationError(`Some relations of the ${cls.name} are not found`);
299
- for (const param of relation_errors) ex.info[param] = "Parent object not found";
300
- throw ex;
301
- }
302
323
  }
324
+ if (relation_errors.length) {
325
+ const ex = new OrangeDatabaseInputValidationError(`Some relations of the ${cls.name} are not found`);
326
+ for (const param of relation_errors) ex.info[param] = "Parent object not found";
327
+ throw ex;
328
+ }
329
+ }
330
+ static model(class_name) {
331
+ return super.model(class_name);
332
+ }
333
+ static registerModel(model_class) {
334
+ return super.registerModel(model_class);
303
335
  }
304
336
  /**
305
337
  * Returns object by ID if it exists and accessible by user
@@ -308,12 +340,13 @@ var Model = class extends import_orange_dragonfly_orm2.ActiveRecord {
308
340
  * @param mode
309
341
  */
310
342
  static async findAndCheckAccessOrDie(id, user, mode = null) {
311
- const obj = await this.find(id);
343
+ const cls = this;
344
+ const obj = await cls.find(id);
312
345
  if (!obj) {
313
- throw new OrangeDatabaseModelRuntimeError(`${this.name} #${id} not found`);
346
+ throw new OrangeDatabaseModelRuntimeError(`${cls.name} #${id} not found`);
314
347
  }
315
348
  if (!await obj.accessible(user, mode)) {
316
- throw new OrangeDatabaseModelAccessError(`${this.name} #${id} is not accessible${mode ? ` for ${mode}` : ""}`);
349
+ throw new OrangeDatabaseModelAccessError(`${cls.name} #${id} is not accessible${mode ? ` for ${mode}` : ""}`);
317
350
  }
318
351
  return obj;
319
352
  }
@@ -322,7 +355,7 @@ var Model = class extends import_orange_dragonfly_orm2.ActiveRecord {
322
355
  * @param user
323
356
  * @param mode
324
357
  */
325
- async accessible(user, mode = null) {
358
+ async accessible(_user, mode = null) {
326
359
  return mode === null;
327
360
  }
328
361
  /**
@@ -337,8 +370,7 @@ var Model = class extends import_orange_dragonfly_orm2.ActiveRecord {
337
370
  * Format output
338
371
  * @param mode
339
372
  */
340
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
341
- formatOutput(mode = null) {
373
+ formatOutput(_mode = null) {
342
374
  return this.output;
343
375
  }
344
376
  /**
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/model.ts","../src/errors.ts"],"sourcesContent":["export { default } from './model'\nexport { default as Model } from './model'\nexport {\n OrangeDatabaseInputValidationError,\n OrangeDatabaseModelAccessError,\n OrangeDatabaseModelError,\n OrangeDatabaseModelRuntimeError,\n} from './errors'\n","import { ActiveRecord, Relation, SelectQuery } from 'orange-dragonfly-orm'\nimport { parse, type ODValidatorRuleSchema, type ODValidatorRulesSchema } from 'orange-dragonfly-validator'\nimport {\n OrangeDatabaseInputValidationError,\n OrangeDatabaseModelAccessError,\n OrangeDatabaseModelError,\n OrangeDatabaseModelRuntimeError,\n} from './errors'\n\nexport default class Model extends ActiveRecord {\n private get _mCls(): typeof Model {\n return this.constructor as typeof Model\n }\n\n static get ignore_extra_fields(): boolean {\n return false\n }\n\n /**\n * Returns list of unique keys\n * @returns List of unique keys\n */\n static get unique_keys(): string[][] {\n return []\n }\n\n /**\n * Returns list of fulltext indexes\n * @returns List of fulltext indexes\n */\n static get fulltext_indexes(): string[][] {\n return []\n }\n\n /** @deprecated Use `ignore_extra_fields` instead */\n static get IGNORE_EXTRA_FIELDS(): boolean {\n return this.ignore_extra_fields\n }\n\n /** @deprecated Use `unique_keys` instead */\n static get UNIQUE_KEYS(): string[][] {\n return this.unique_keys\n }\n\n /** @deprecated Use `fulltext_indexes` instead */\n static get FULLTEXT_INDEXES(): string[][] {\n return this.fulltext_indexes\n }\n\n /**\n * Returns schema for the model (Orange Dragonfly Validator format)\n */\n static get validation_rules(): ODValidatorRulesSchema {\n return {\n id: {\n required: false,\n type: 'integer',\n min: 1,\n },\n }\n }\n\n /**\n * Overridden method of ActiveRecord. Returns special fields list based on validation rules\n */\n static override get special_fields(): string[] {\n const rules = this.validation_rules\n const fields: string[] = []\n for (const field of ['created_at', 'updated_at', 'deleted_at']) {\n if (Object.hasOwn(rules, field)) fields.push(field)\n }\n return fields\n }\n\n /**\n * Returns list of relations restricted for extended output\n */\n static get restricted_for_output(): string[] {\n return []\n }\n\n /**\n * Returns list of fields restricted for lookup\n */\n static get restricted_for_lookup(): string[] {\n return []\n }\n\n /**\n * Returns list of fields restricted for create method\n */\n static get restricted_for_create(): string[] {\n return ['id'].concat(this.special_fields)\n }\n\n /**\n * Returns list of fields restricted for update method\n */\n static get restricted_for_update(): string[] {\n return ['id'].concat(this.special_fields)\n }\n\n /**\n * Lookup method\n * @param data\n * @param basicQuery Query to be used for adding conditions. By default a new SelectQuery is created.\n */\n static lookupQuery(data: Record<string, unknown>, basicQuery: SelectQuery | null = null): SelectQuery {\n const rules = this.validation_rules\n const q = basicQuery ?? this.selectQuery()\n const filtered_rules: ODValidatorRulesSchema = {}\n for (const field of Object.keys(data)) {\n if (!Object.hasOwn(rules, field)) {\n if (this.ignore_extra_fields) {\n continue\n }\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\n ex.info[field] = `Field \"${field}\" is not described for model ${this.name}`\n throw ex\n }\n if (this.restricted_for_lookup.includes(field)) {\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\n ex.info[field] = `Field \"${field}\" is restricted for searching model ${this.name}`\n throw ex\n }\n q.where(field, data[field])\n const rule = rules[field] as ODValidatorRuleSchema\n filtered_rules[field] = Array.isArray(data[field]) ? { type: 'array', children: { '*': rule } } : rule\n }\n parse(filtered_rules, data, { strictMode: false })\n return q\n }\n\n /**\n * Creates object\n * @param data\n */\n static async create(data: Record<string, unknown>): Promise<Model> {\n const rules = this.validation_rules\n const new_data: Record<string, unknown> = {}\n for (const field of Object.keys(data)) {\n if (!Object.hasOwn(rules, field)) {\n if (this.ignore_extra_fields) {\n continue\n }\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\n ex.info[field] = `Field \"${field}\" is not described for model ${this.name}`\n throw ex\n }\n if (this.restricted_for_create.includes(field)) {\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\n ex.info[field] = `Field \"${field}\" is restricted for creating model ${this.name}`\n throw ex\n }\n new_data[field] = data[field]\n }\n const Cls = this as unknown as new (data?: Record<string, unknown>) => Model\n return (new Cls(new_data)).save()\n }\n\n /**\n * Updates object\n * @param data\n */\n async update(data: Record<string, unknown>): Promise<this> {\n if (!this.id) {\n throw new OrangeDatabaseModelRuntimeError('You can update saved object only')\n }\n const cls = this._mCls\n const rules = cls.validation_rules\n const new_data: Record<string, unknown> = {}\n for (const field of Object.keys(data)) {\n if (!Object.hasOwn(rules, field)) {\n if (cls.ignore_extra_fields) {\n continue\n }\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\n ex.info[field] = `Field \"${field}\" is not described for model ${cls.name}`\n throw ex\n }\n if (cls.restricted_for_update.includes(field)) {\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\n ex.info[field] = `Field \"${field}\" is restricted for updating model ${cls.name}`\n throw ex\n }\n new_data[field] = data[field]\n }\n return this.save(new_data)\n }\n\n /**\n * Checks uniqueness of the object based on unique_keys\n */\n async checkUniqueness(exception_mode = false, ignore_null = false): Promise<boolean> {\n const cls = this._mCls\n for (const fields of cls.unique_keys) {\n if (!await this.isUnique(fields, ignore_null)) {\n if (exception_mode) {\n const ex = new OrangeDatabaseInputValidationError('Object is not unique')\n for (const field of fields) {\n ex.info[field] = 'Part of the unique key'\n }\n throw ex\n }\n return false\n }\n }\n return true\n }\n\n protected override async _preSave(_is_new?: boolean): Promise<void> {\n const cls = this._mCls\n if (cls.ignore_extra_fields) {\n const rules = cls.validation_rules\n for (const key of Object.keys(this.data).filter(v => !Object.hasOwn(rules, v))) {\n delete this.data[key]\n }\n }\n await super._preSave(_is_new)\n await this.checkUniqueness(true, true)\n await this.validate()\n }\n\n /**\n * Performs custom validation - returns null in case of success or an object of validation issues\n */\n async custom_validation(): Promise<Record<string, string> | null> {\n return null\n }\n\n /**\n * Validate object's data\n */\n async validate(): Promise<void> {\n const cls = this._mCls\n const rules = cls.validation_rules\n if (!rules) {\n throw new OrangeDatabaseModelError(`Validation rules are not defined for model ${cls.name}`)\n }\n for (const rule_name of Object.keys(rules)) {\n if (Object.hasOwn(this.data, rule_name)) {\n const rule = rules[rule_name] as ODValidatorRuleSchema\n if (rule?.type) {\n const types = Array.isArray(rule.type) ? (rule.type as string[]) : [rule.type as string]\n if (types.includes('boolean')) {\n if ((this.data[rule_name] === 1) || (this.data[rule_name] === 0)) {\n this.data[rule_name] = this.data[rule_name] === 1\n }\n }\n }\n }\n }\n this.data = parse(rules, this.data, { strictMode: false })\n const custom_validation_errors = await this.custom_validation()\n if (custom_validation_errors && Object.keys(custom_validation_errors).length) {\n const ex = new OrangeDatabaseInputValidationError('Validation failed')\n for (const [param, message] of Object.entries(custom_validation_errors)) ex.info[param] = message\n throw ex\n }\n const relation_errors: string[] = []\n for (const rel_name of Object.keys(cls.available_relations)) {\n const rel: Relation = cls.available_relations[rel_name]\n if (rel.mode === 'parent') {\n const aKey = (rel as unknown as { _a_key_by_mode: string })._a_key_by_mode\n if (Object.hasOwn(this.data, aKey) && (this.data[aKey] !== null) && (this.data[aKey] !== 0)) {\n if ((await this.rel(rel_name, true) as Model | null) === null) {\n relation_errors.push(aKey)\n }\n }\n }\n if (relation_errors.length) {\n const ex = new OrangeDatabaseInputValidationError(`Some relations of the ${cls.name} are not found`)\n for (const param of relation_errors) ex.info[param] = 'Parent object not found'\n throw ex\n }\n }\n }\n\n /**\n * Returns object by ID if it exists and accessible by user\n * @param id\n * @param user\n * @param mode\n */\n static async findAndCheckAccessOrDie(id: unknown, user: unknown, mode: string | null = null): Promise<Model> {\n const obj = await this.find(id) as Model | null\n if (!obj) {\n throw new OrangeDatabaseModelRuntimeError(`${this.name} #${id} not found`)\n }\n if (!(await obj.accessible(user, mode))) {\n throw new OrangeDatabaseModelAccessError(`${this.name} #${id} is not accessible${mode ? ` for ${mode}` : ''}`)\n }\n return obj\n }\n\n /**\n * Returns whether the object is accessible by user\n * @param user\n * @param mode\n */\n \n async accessible(user: unknown, mode: string | null = null): Promise<boolean> {\n return mode === null\n }\n\n /**\n * Returns public data of the object\n */\n get output(): Record<string, unknown> {\n return {\n id: this.id,\n }\n }\n\n /**\n * Format output\n * @param mode\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n formatOutput(mode: string | null = null): Record<string, unknown> {\n return this.output\n }\n\n /**\n * Returns public data of the object with relations\n * @param required_relations\n * @param mode\n */\n async getExtendedOutput(required_relations: string[] = [], mode: string | null = null): Promise<Record<string, unknown>> {\n const output = this.formatOutput(mode)\n const cls = this._mCls\n for (const name of required_relations) {\n if (name.split(':').length > 1) continue\n if (cls.restricted_for_output.includes(name)) {\n throw new OrangeDatabaseModelError(`Relation \"${name}\" is not allowed for extended output of model ${cls.name}`)\n }\n const rel_data = await this.rel(name) as Model | Model[] | null\n const rel_mode = `relation:${cls.name}.${name}`\n const rel_relations = required_relations.filter(v => v.startsWith(`${name}:`)).map(v => v.slice(name.length + 1))\n output[`:${name}`] = Array.isArray(rel_data)\n ? await Promise.all(rel_data.map(v => v.getExtendedOutput(rel_relations, rel_mode)))\n : (rel_data ? await rel_data.getExtendedOutput(rel_relations, rel_mode) : null)\n }\n return output\n }\n}\n","import { OrangeDatabaseError, OrangeDatabaseInputError } from 'orange-dragonfly-orm'\n\nexport class OrangeDatabaseInputValidationError extends OrangeDatabaseInputError {\n private _info: Record<string, string> = {}\n\n get info(): Record<string, string> {\n return this._info\n }\n\n set info(v: Record<string, string>) {\n this._info = v\n }\n}\n\nexport class OrangeDatabaseModelError extends OrangeDatabaseError {}\n\nexport class OrangeDatabaseModelRuntimeError extends OrangeDatabaseModelError {}\n\nexport class OrangeDatabaseModelAccessError extends OrangeDatabaseModelRuntimeError {}\n"],"mappings":"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","names":["import_orange_dragonfly_orm"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/model.ts","../src/errors.ts"],"sourcesContent":["export { default } from './model'\nexport { default as Model, type IModelConstructor, type ModelData } from './model'\nexport {\n OrangeDatabaseInputValidationError,\n OrangeDatabaseModelAccessError,\n OrangeDatabaseModelError,\n OrangeDatabaseModelRuntimeError,\n} from './errors'\n","import { ActiveRecord, type DeleteQuery, type InsertQuery, type IQueryBuilder, type Relation, SelectQuery, type UpdateQuery } from 'orange-dragonfly-orm'\r\nimport { ODValidatorException, parse, type ODValidatorRuleSchema, type ODValidatorRulesSchema } from 'orange-dragonfly-validator'\r\n\r\ntype ValidatorTSType<T extends string> =\r\n T extends 'string' ? string :\r\n T extends 'integer' | 'number' ? number :\r\n T extends 'boolean' ? boolean :\r\n T extends 'null' ? null :\r\n T extends 'object' ? Record<string, unknown> :\r\n T extends 'array' ? unknown[] :\r\n T extends 'function' ? (...args: unknown[]) => unknown :\r\n unknown\r\n\r\ntype FieldTS<R extends ODValidatorRuleSchema> =\r\n R['type'] extends string\r\n ? ValidatorTSType<R['type']>\r\n : R['type'] extends readonly (infer U extends string)[]\r\n ? ValidatorTSType<U>\r\n : unknown\r\n\r\n/**\r\n * Converts an `ODValidatorRulesSchema` to a TypeScript object type.\r\n * Requires the schema to be declared with `as const satisfies ODValidatorRulesSchema`\r\n * to preserve literal type information.\r\n *\r\n * @example\r\n * const schema = { name: { type: 'string', required: true } } as const satisfies ODValidatorRulesSchema\r\n * class MyModel extends Model {\r\n * static override get validation_rules() { return schema }\r\n * declare data: ModelData<typeof schema>\r\n * }\r\n */\r\nexport type ModelData<S extends ODValidatorRulesSchema> = {\r\n [K in Exclude<keyof S, '@' | '#' | '*'>]: S[K] extends ODValidatorRuleSchema ? FieldTS<S[K]> : never\r\n}\r\n\r\nimport {\r\n OrangeDatabaseInputValidationError,\r\n OrangeDatabaseModelAccessError,\r\n OrangeDatabaseModelError,\r\n OrangeDatabaseModelRuntimeError,\r\n} from './errors'\r\n\r\nexport interface IModelConstructor {\r\n new(data?: Record<string, unknown>): Model\r\n readonly id_key: string\r\n readonly table: string\r\n readonly name: string\r\n readonly special_fields: string[]\r\n readonly available_relations: Record<string, Relation>\r\n readonly ignore_extra_fields: boolean\r\n readonly unique_keys: string[][]\r\n readonly fulltext_indexes: string[][]\r\n /** @deprecated Use `ignore_extra_fields` instead */\r\n readonly IGNORE_EXTRA_FIELDS: boolean\r\n /** @deprecated Use `unique_keys` instead */\r\n readonly UNIQUE_KEYS: string[][]\r\n /** @deprecated Use `fulltext_indexes` instead */\r\n readonly FULLTEXT_INDEXES: string[][]\r\n readonly validation_rules: ODValidatorRulesSchema\r\n readonly restricted_for_output: string[]\r\n readonly restricted_for_lookup: string[]\r\n readonly restricted_for_create: string[]\r\n readonly restricted_for_update: string[]\r\n resetRegisteredModels(): void\r\n insertQuery(): InsertQuery\r\n selectQuery(include_deleted?: boolean): IQueryBuilder<Model>\r\n updateQuery(include_deleted?: boolean): UpdateQuery\r\n deleteQuery(include_deleted?: boolean): DeleteQuery\r\n loadRelations(objects: Model[], relations?: string[] | null): Promise<Model[]>\r\n find(id: unknown, include_deleted?: boolean): Promise<Model | null>\r\n all(include_deleted?: boolean): Promise<Model[]>\r\n lookupQuery(data: Record<string, unknown>, basicQuery?: SelectQuery | null): SelectQuery<Model>\r\n create(data: Record<string, unknown>): Promise<Model>\r\n findAndCheckAccessOrDie(id: unknown, user: unknown, mode?: string | null): Promise<Model>\r\n model(class_name: string): IModelConstructor\r\n registerModel(model_class: IModelConstructor): IModelConstructor\r\n}\r\n\r\nexport default class Model extends ActiveRecord {\r\n private get _mCls(): typeof Model {\r\n return this.constructor as typeof Model\r\n }\r\n\r\n static get ignore_extra_fields(): boolean {\r\n return false\r\n }\r\n\r\n /**\r\n * Returns list of unique keys\r\n * @returns List of unique keys\r\n */\r\n static get unique_keys(): string[][] {\r\n return []\r\n }\r\n\r\n /**\r\n * Returns list of fulltext indexes\r\n * @returns List of fulltext indexes\r\n */\r\n static get fulltext_indexes(): string[][] {\r\n return []\r\n }\r\n\r\n /** @deprecated Use `ignore_extra_fields` instead */\r\n static get IGNORE_EXTRA_FIELDS(): boolean {\r\n return this.ignore_extra_fields\r\n }\r\n\r\n /** @deprecated Use `unique_keys` instead */\r\n static get UNIQUE_KEYS(): string[][] {\r\n return this.unique_keys\r\n }\r\n\r\n /** @deprecated Use `fulltext_indexes` instead */\r\n static get FULLTEXT_INDEXES(): string[][] {\r\n return this.fulltext_indexes\r\n }\r\n\r\n /**\r\n * Returns schema for the model (Orange Dragonfly Validator format)\r\n */\r\n static get validation_rules(): ODValidatorRulesSchema {\r\n return {\r\n id: {\r\n required: false,\r\n type: 'integer',\r\n min: 1,\r\n },\r\n }\r\n }\r\n\r\n /**\r\n * Overridden method of ActiveRecord. Returns special fields list based on validation rules\r\n */\r\n static override get special_fields(): string[] {\r\n const rules = this.validation_rules\r\n const fields: string[] = []\r\n for (const field of ['created_at', 'updated_at', 'deleted_at']) {\r\n if (Object.hasOwn(rules, field)) fields.push(field)\r\n }\r\n return fields\r\n }\r\n\r\n /**\r\n * Returns list of relations restricted for extended output\r\n */\r\n static get restricted_for_output(): string[] {\r\n return []\r\n }\r\n\r\n /**\r\n * Returns list of fields restricted for lookup\r\n */\r\n static get restricted_for_lookup(): string[] {\r\n return []\r\n }\r\n\r\n /**\r\n * Returns list of fields restricted for create method\r\n */\r\n static get restricted_for_create(): string[] {\r\n return ['id'].concat(this.special_fields)\r\n }\r\n\r\n /**\r\n * Returns list of fields restricted for update method\r\n */\r\n static get restricted_for_update(): string[] {\r\n return ['id'].concat(this.special_fields)\r\n }\r\n\r\n /**\r\n * Lookup method\r\n * @param data\r\n * @param basicQuery Query to be used for adding conditions. By default a new SelectQuery is created.\r\n */\r\n static lookupQuery<T extends Model>(\r\n this: abstract new (data?: Record<string, unknown>) => T,\r\n data: Record<string, unknown>,\r\n basicQuery: SelectQuery | null = null,\r\n ): SelectQuery<T> {\r\n const cls = this as unknown as typeof Model\r\n const rules = cls.validation_rules\r\n const q = (basicQuery ?? cls.selectQuery()) as SelectQuery<T>\r\n const filtered_rules: ODValidatorRulesSchema = {}\r\n for (const field of Object.keys(data)) {\r\n if (!Object.hasOwn(rules, field)) {\r\n if (cls.ignore_extra_fields) {\r\n continue\r\n }\r\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\r\n ex.info[field] = `Field \"${field}\" is not described for model ${cls.name}`\r\n throw ex\r\n }\r\n if (cls.restricted_for_lookup.includes(field)) {\r\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\r\n ex.info[field] = `Field \"${field}\" is restricted for searching model ${cls.name}`\r\n throw ex\r\n }\r\n q.where(field, data[field])\r\n const rule = rules[field] as ODValidatorRuleSchema\r\n filtered_rules[field] = Array.isArray(data[field]) ? { type: 'array', children: { '*': rule } } : rule\r\n }\r\n try {\r\n parse(filtered_rules, data, { strictMode: false })\r\n } catch (e) {\r\n if (e instanceof ODValidatorException) {\r\n const message = `Model ${cls.name} lookup rules validation failed`\r\n console.error(message, e.info)\r\n throw new OrangeDatabaseInputValidationError(message)\r\n } else {\r\n throw e\r\n }\r\n }\r\n return q\r\n }\r\n\r\n /**\r\n * Creates object\r\n * @param data\r\n */\r\n static async create<T extends Model>(\r\n this: abstract new (data?: Record<string, unknown>) => T,\r\n data: Record<string, unknown>,\r\n ): Promise<T> {\r\n const cls = this as unknown as typeof Model\r\n const rules = cls.validation_rules\r\n const new_data: Record<string, unknown> = {}\r\n for (const field of Object.keys(data)) {\r\n if (!Object.hasOwn(rules, field)) {\r\n if (cls.ignore_extra_fields) {\r\n continue\r\n }\r\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\r\n ex.info[field] = `Field \"${field}\" is not described for model ${cls.name}`\r\n throw ex\r\n }\r\n if (cls.restricted_for_create.includes(field)) {\r\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\r\n ex.info[field] = `Field \"${field}\" is restricted for creating model ${cls.name}`\r\n throw ex\r\n }\r\n new_data[field] = data[field]\r\n }\r\n const Cls = this as unknown as new (data?: Record<string, unknown>) => T\r\n return (new Cls(new_data)).save()\r\n }\r\n\r\n /**\r\n * Updates object\r\n * @param data\r\n */\r\n async update(data: Record<string, unknown>): Promise<this> {\r\n if (!this.id) {\r\n throw new OrangeDatabaseModelRuntimeError('You can update saved object only')\r\n }\r\n const cls = this._mCls\r\n const rules = cls.validation_rules\r\n const new_data: Record<string, unknown> = {}\r\n for (const field of Object.keys(data)) {\r\n if (!Object.hasOwn(rules, field)) {\r\n if (cls.ignore_extra_fields) {\r\n continue\r\n }\r\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\r\n ex.info[field] = `Field \"${field}\" is not described for model ${cls.name}`\r\n throw ex\r\n }\r\n if (cls.restricted_for_update.includes(field)) {\r\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\r\n ex.info[field] = `Field \"${field}\" is restricted for updating model ${cls.name}`\r\n throw ex\r\n }\r\n new_data[field] = data[field]\r\n }\r\n return this.save(new_data)\r\n }\r\n\r\n /**\r\n * Checks uniqueness of the object based on unique_keys\r\n */\r\n async checkUniqueness(exception_mode = false, ignore_null = false): Promise<boolean> {\r\n const cls = this._mCls\r\n for (const fields of cls.unique_keys) {\r\n if (!await this.isUnique(fields, ignore_null)) {\r\n if (exception_mode) {\r\n const ex = new OrangeDatabaseInputValidationError('Object is not unique')\r\n for (const field of fields) {\r\n ex.info[field] = 'Part of the unique key'\r\n }\r\n throw ex\r\n }\r\n return false\r\n }\r\n }\r\n return true\r\n }\r\n\r\n protected override async _preSave(_is_new?: boolean): Promise<void> {\r\n const cls = this._mCls\r\n if (cls.ignore_extra_fields) {\r\n const rules = cls.validation_rules\r\n for (const key of Object.keys(this.data).filter(v => !Object.hasOwn(rules, v))) {\r\n delete this.data[key]\r\n }\r\n }\r\n await super._preSave(_is_new)\r\n await this.checkUniqueness(true, true)\r\n await this.validate()\r\n }\r\n\r\n /**\r\n * Performs custom validation - returns null in case of success or an object of validation issues\r\n */\r\n async custom_validation(): Promise<Record<string, string> | null> {\r\n return null\r\n }\r\n\r\n /**\r\n * Validate object's data\r\n */\r\n async validate(): Promise<void> {\r\n const cls = this._mCls\r\n const rules = cls.validation_rules\r\n if (!rules) {\r\n throw new OrangeDatabaseModelError(`Validation rules are not defined for model ${cls.name}`)\r\n }\r\n for (const rule_name of Object.keys(rules)) {\r\n if (Object.hasOwn(this.data, rule_name)) {\r\n const rule = rules[rule_name] as ODValidatorRuleSchema\r\n if (rule?.type) {\r\n const types = Array.isArray(rule.type) ? (rule.type as string[]) : [rule.type as string]\r\n if (types.includes('boolean')) {\r\n if ((this.data[rule_name] === 1) || (this.data[rule_name] === 0)) {\r\n this.data[rule_name] = this.data[rule_name] === 1\r\n }\r\n }\r\n }\r\n }\r\n }\r\n try {\r\n this.data = parse(rules, this.data, { strictMode: false })\r\n } catch (e) {\r\n if (e instanceof ODValidatorException) {\r\n const message = `Model ${cls.name} rules validation failed`\r\n console.error(message, e.info)\r\n const ex = new OrangeDatabaseInputValidationError(message)\r\n for (const [key, msgs] of Object.entries(e.info as Record<string, string | string[]>)) {\r\n ex.info[key] = Array.isArray(msgs) ? msgs[0] : msgs\r\n }\r\n throw ex\r\n } else {\r\n throw e\r\n }\r\n }\r\n const custom_validation_errors = await this.custom_validation()\r\n if (custom_validation_errors && Object.keys(custom_validation_errors).length) {\r\n const ex = new OrangeDatabaseInputValidationError('Validation failed')\r\n for (const [param, message] of Object.entries(custom_validation_errors)) ex.info[param] = message\r\n throw ex\r\n }\r\n const relation_errors: string[] = []\r\n for (const rel_name of Object.keys(cls.available_relations)) {\r\n const rel: Relation = cls.available_relations[rel_name]\r\n if (rel.mode === 'parent') {\r\n const aKey = (rel as unknown as { _a_key_by_mode: string })._a_key_by_mode\r\n if (Object.hasOwn(this.data, aKey) && (this.data[aKey] !== null) && (this.data[aKey] !== 0)) {\r\n if ((await this.rel(rel_name, true) as Model | null) === null) {\r\n relation_errors.push(aKey)\r\n }\r\n }\r\n }\r\n }\r\n if (relation_errors.length) {\r\n const ex = new OrangeDatabaseInputValidationError(`Some relations of the ${cls.name} are not found`)\r\n for (const param of relation_errors) ex.info[param] = 'Parent object not found'\r\n throw ex\r\n }\r\n }\r\n\r\n static override model(class_name: string): IModelConstructor {\r\n return super.model(class_name) as unknown as IModelConstructor\r\n }\r\n\r\n static override registerModel(model_class: Parameters<typeof ActiveRecord.registerModel>[0]): typeof Model {\r\n return super.registerModel(model_class) as unknown as typeof Model\r\n }\r\n\r\n /**\r\n * Returns object by ID if it exists and accessible by user\r\n * @param id\r\n * @param user\r\n * @param mode\r\n */\r\n static async findAndCheckAccessOrDie<T extends Model>(\r\n this: abstract new (data?: Record<string, unknown>) => T,\r\n id: number,\r\n user: unknown,\r\n mode: string | null = null,\r\n ): Promise<T> {\r\n const cls = this as unknown as typeof Model\r\n const obj = await cls.find(id) as T | null\r\n if (!obj) {\r\n throw new OrangeDatabaseModelRuntimeError(`${cls.name} #${id} not found`)\r\n }\r\n if (!(await obj.accessible(user, mode))) {\r\n throw new OrangeDatabaseModelAccessError(`${cls.name} #${id} is not accessible${mode ? ` for ${mode}` : ''}`)\r\n }\r\n return obj\r\n }\r\n\r\n /**\r\n * Returns whether the object is accessible by user\r\n * @param user\r\n * @param mode\r\n */\r\n \r\n async accessible(_user: unknown, mode: string | null = null): Promise<boolean> {\r\n return mode === null\r\n }\r\n\r\n /**\r\n * Returns public data of the object\r\n */\r\n get output(): Record<string, unknown> {\r\n return {\r\n id: this.id,\r\n }\r\n }\r\n\r\n /**\r\n * Format output\r\n * @param mode\r\n */\r\n formatOutput(_mode: string | null = null): Record<string, unknown> {\r\n return this.output\r\n }\r\n\r\n /**\r\n * Returns public data of the object with relations\r\n * @param required_relations\r\n * @param mode\r\n */\r\n async getExtendedOutput(required_relations: string[] = [], mode: string | null = null): Promise<Record<string, unknown>> {\r\n const output = this.formatOutput(mode)\r\n const cls = this._mCls\r\n for (const name of required_relations) {\r\n if (name.split(':').length > 1) continue\r\n if (cls.restricted_for_output.includes(name)) {\r\n throw new OrangeDatabaseModelError(`Relation \"${name}\" is not allowed for extended output of model ${cls.name}`)\r\n }\r\n const rel_data = await this.rel(name) as Model | Model[] | null\r\n const rel_mode = `relation:${cls.name}.${name}`\r\n const rel_relations = required_relations.filter(v => v.startsWith(`${name}:`)).map(v => v.slice(name.length + 1))\r\n output[`:${name}`] = Array.isArray(rel_data)\r\n ? await Promise.all(rel_data.map(v => v.getExtendedOutput(rel_relations, rel_mode)))\r\n : (rel_data ? await rel_data.getExtendedOutput(rel_relations, rel_mode) : null)\r\n }\r\n return output\r\n }\r\n}\r\n","import { OrangeDatabaseError, OrangeDatabaseInputError } from 'orange-dragonfly-orm'\n\nexport class OrangeDatabaseInputValidationError extends OrangeDatabaseInputError {\n private _info: Record<string, string> = {}\n\n get info(): Record<string, string> {\n return this._info\n }\n\n set info(v: Record<string, string>) {\n this._info = v\n }\n}\n\nexport class OrangeDatabaseModelError extends OrangeDatabaseError {}\n\nexport class OrangeDatabaseModelRuntimeError extends OrangeDatabaseModelError {}\n\nexport class OrangeDatabaseModelAccessError extends OrangeDatabaseModelRuntimeError {}\n"],"mappings":"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","names":["import_orange_dragonfly_orm"]}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,58 @@
1
- import { ActiveRecord, SelectQuery, OrangeDatabaseInputError, OrangeDatabaseError } from 'orange-dragonfly-orm';
2
- import { ODValidatorRulesSchema } from 'orange-dragonfly-validator';
1
+ import { ActiveRecord, SelectQuery, Relation, InsertQuery, IQueryBuilder, UpdateQuery, DeleteQuery, OrangeDatabaseInputError, OrangeDatabaseError } from 'orange-dragonfly-orm';
2
+ import { ODValidatorRulesSchema, ODValidatorRuleSchema } from 'orange-dragonfly-validator';
3
3
 
4
+ type ValidatorTSType<T extends string> = T extends 'string' ? string : T extends 'integer' | 'number' ? number : T extends 'boolean' ? boolean : T extends 'null' ? null : T extends 'object' ? Record<string, unknown> : T extends 'array' ? unknown[] : T extends 'function' ? (...args: unknown[]) => unknown : unknown;
5
+ type FieldTS<R extends ODValidatorRuleSchema> = R['type'] extends string ? ValidatorTSType<R['type']> : R['type'] extends readonly (infer U extends string)[] ? ValidatorTSType<U> : unknown;
6
+ /**
7
+ * Converts an `ODValidatorRulesSchema` to a TypeScript object type.
8
+ * Requires the schema to be declared with `as const satisfies ODValidatorRulesSchema`
9
+ * to preserve literal type information.
10
+ *
11
+ * @example
12
+ * const schema = { name: { type: 'string', required: true } } as const satisfies ODValidatorRulesSchema
13
+ * class MyModel extends Model {
14
+ * static override get validation_rules() { return schema }
15
+ * declare data: ModelData<typeof schema>
16
+ * }
17
+ */
18
+ type ModelData<S extends ODValidatorRulesSchema> = {
19
+ [K in Exclude<keyof S, '@' | '#' | '*'>]: S[K] extends ODValidatorRuleSchema ? FieldTS<S[K]> : never;
20
+ };
21
+ interface IModelConstructor {
22
+ new (data?: Record<string, unknown>): Model;
23
+ readonly id_key: string;
24
+ readonly table: string;
25
+ readonly name: string;
26
+ readonly special_fields: string[];
27
+ readonly available_relations: Record<string, Relation>;
28
+ readonly ignore_extra_fields: boolean;
29
+ readonly unique_keys: string[][];
30
+ readonly fulltext_indexes: string[][];
31
+ /** @deprecated Use `ignore_extra_fields` instead */
32
+ readonly IGNORE_EXTRA_FIELDS: boolean;
33
+ /** @deprecated Use `unique_keys` instead */
34
+ readonly UNIQUE_KEYS: string[][];
35
+ /** @deprecated Use `fulltext_indexes` instead */
36
+ readonly FULLTEXT_INDEXES: string[][];
37
+ readonly validation_rules: ODValidatorRulesSchema;
38
+ readonly restricted_for_output: string[];
39
+ readonly restricted_for_lookup: string[];
40
+ readonly restricted_for_create: string[];
41
+ readonly restricted_for_update: string[];
42
+ resetRegisteredModels(): void;
43
+ insertQuery(): InsertQuery;
44
+ selectQuery(include_deleted?: boolean): IQueryBuilder<Model>;
45
+ updateQuery(include_deleted?: boolean): UpdateQuery;
46
+ deleteQuery(include_deleted?: boolean): DeleteQuery;
47
+ loadRelations(objects: Model[], relations?: string[] | null): Promise<Model[]>;
48
+ find(id: unknown, include_deleted?: boolean): Promise<Model | null>;
49
+ all(include_deleted?: boolean): Promise<Model[]>;
50
+ lookupQuery(data: Record<string, unknown>, basicQuery?: SelectQuery | null): SelectQuery<Model>;
51
+ create(data: Record<string, unknown>): Promise<Model>;
52
+ findAndCheckAccessOrDie(id: unknown, user: unknown, mode?: string | null): Promise<Model>;
53
+ model(class_name: string): IModelConstructor;
54
+ registerModel(model_class: IModelConstructor): IModelConstructor;
55
+ }
4
56
  declare class Model extends ActiveRecord {
5
57
  private get _mCls();
6
58
  static get ignore_extra_fields(): boolean;
@@ -49,12 +101,12 @@ declare class Model extends ActiveRecord {
49
101
  * @param data
50
102
  * @param basicQuery Query to be used for adding conditions. By default a new SelectQuery is created.
51
103
  */
52
- static lookupQuery(data: Record<string, unknown>, basicQuery?: SelectQuery | null): SelectQuery;
104
+ static lookupQuery<T extends Model>(this: abstract new (data?: Record<string, unknown>) => T, data: Record<string, unknown>, basicQuery?: SelectQuery | null): SelectQuery<T>;
53
105
  /**
54
106
  * Creates object
55
107
  * @param data
56
108
  */
57
- static create(data: Record<string, unknown>): Promise<Model>;
109
+ static create<T extends Model>(this: abstract new (data?: Record<string, unknown>) => T, data: Record<string, unknown>): Promise<T>;
58
110
  /**
59
111
  * Updates object
60
112
  * @param data
@@ -73,19 +125,21 @@ declare class Model extends ActiveRecord {
73
125
  * Validate object's data
74
126
  */
75
127
  validate(): Promise<void>;
128
+ static model(class_name: string): IModelConstructor;
129
+ static registerModel(model_class: Parameters<typeof ActiveRecord.registerModel>[0]): typeof Model;
76
130
  /**
77
131
  * Returns object by ID if it exists and accessible by user
78
132
  * @param id
79
133
  * @param user
80
134
  * @param mode
81
135
  */
82
- static findAndCheckAccessOrDie(id: unknown, user: unknown, mode?: string | null): Promise<Model>;
136
+ static findAndCheckAccessOrDie<T extends Model>(this: abstract new (data?: Record<string, unknown>) => T, id: number, user: unknown, mode?: string | null): Promise<T>;
83
137
  /**
84
138
  * Returns whether the object is accessible by user
85
139
  * @param user
86
140
  * @param mode
87
141
  */
88
- accessible(user: unknown, mode?: string | null): Promise<boolean>;
142
+ accessible(_user: unknown, mode?: string | null): Promise<boolean>;
89
143
  /**
90
144
  * Returns public data of the object
91
145
  */
@@ -94,7 +148,7 @@ declare class Model extends ActiveRecord {
94
148
  * Format output
95
149
  * @param mode
96
150
  */
97
- formatOutput(mode?: string | null): Record<string, unknown>;
151
+ formatOutput(_mode?: string | null): Record<string, unknown>;
98
152
  /**
99
153
  * Returns public data of the object with relations
100
154
  * @param required_relations
@@ -115,4 +169,4 @@ declare class OrangeDatabaseModelRuntimeError extends OrangeDatabaseModelError {
115
169
  declare class OrangeDatabaseModelAccessError extends OrangeDatabaseModelRuntimeError {
116
170
  }
117
171
 
118
- export { Model, OrangeDatabaseInputValidationError, OrangeDatabaseModelAccessError, OrangeDatabaseModelError, OrangeDatabaseModelRuntimeError, Model as default };
172
+ export { type IModelConstructor, Model, type ModelData, OrangeDatabaseInputValidationError, OrangeDatabaseModelAccessError, OrangeDatabaseModelError, OrangeDatabaseModelRuntimeError, Model as default };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,58 @@
1
- import { ActiveRecord, SelectQuery, OrangeDatabaseInputError, OrangeDatabaseError } from 'orange-dragonfly-orm';
2
- import { ODValidatorRulesSchema } from 'orange-dragonfly-validator';
1
+ import { ActiveRecord, SelectQuery, Relation, InsertQuery, IQueryBuilder, UpdateQuery, DeleteQuery, OrangeDatabaseInputError, OrangeDatabaseError } from 'orange-dragonfly-orm';
2
+ import { ODValidatorRulesSchema, ODValidatorRuleSchema } from 'orange-dragonfly-validator';
3
3
 
4
+ type ValidatorTSType<T extends string> = T extends 'string' ? string : T extends 'integer' | 'number' ? number : T extends 'boolean' ? boolean : T extends 'null' ? null : T extends 'object' ? Record<string, unknown> : T extends 'array' ? unknown[] : T extends 'function' ? (...args: unknown[]) => unknown : unknown;
5
+ type FieldTS<R extends ODValidatorRuleSchema> = R['type'] extends string ? ValidatorTSType<R['type']> : R['type'] extends readonly (infer U extends string)[] ? ValidatorTSType<U> : unknown;
6
+ /**
7
+ * Converts an `ODValidatorRulesSchema` to a TypeScript object type.
8
+ * Requires the schema to be declared with `as const satisfies ODValidatorRulesSchema`
9
+ * to preserve literal type information.
10
+ *
11
+ * @example
12
+ * const schema = { name: { type: 'string', required: true } } as const satisfies ODValidatorRulesSchema
13
+ * class MyModel extends Model {
14
+ * static override get validation_rules() { return schema }
15
+ * declare data: ModelData<typeof schema>
16
+ * }
17
+ */
18
+ type ModelData<S extends ODValidatorRulesSchema> = {
19
+ [K in Exclude<keyof S, '@' | '#' | '*'>]: S[K] extends ODValidatorRuleSchema ? FieldTS<S[K]> : never;
20
+ };
21
+ interface IModelConstructor {
22
+ new (data?: Record<string, unknown>): Model;
23
+ readonly id_key: string;
24
+ readonly table: string;
25
+ readonly name: string;
26
+ readonly special_fields: string[];
27
+ readonly available_relations: Record<string, Relation>;
28
+ readonly ignore_extra_fields: boolean;
29
+ readonly unique_keys: string[][];
30
+ readonly fulltext_indexes: string[][];
31
+ /** @deprecated Use `ignore_extra_fields` instead */
32
+ readonly IGNORE_EXTRA_FIELDS: boolean;
33
+ /** @deprecated Use `unique_keys` instead */
34
+ readonly UNIQUE_KEYS: string[][];
35
+ /** @deprecated Use `fulltext_indexes` instead */
36
+ readonly FULLTEXT_INDEXES: string[][];
37
+ readonly validation_rules: ODValidatorRulesSchema;
38
+ readonly restricted_for_output: string[];
39
+ readonly restricted_for_lookup: string[];
40
+ readonly restricted_for_create: string[];
41
+ readonly restricted_for_update: string[];
42
+ resetRegisteredModels(): void;
43
+ insertQuery(): InsertQuery;
44
+ selectQuery(include_deleted?: boolean): IQueryBuilder<Model>;
45
+ updateQuery(include_deleted?: boolean): UpdateQuery;
46
+ deleteQuery(include_deleted?: boolean): DeleteQuery;
47
+ loadRelations(objects: Model[], relations?: string[] | null): Promise<Model[]>;
48
+ find(id: unknown, include_deleted?: boolean): Promise<Model | null>;
49
+ all(include_deleted?: boolean): Promise<Model[]>;
50
+ lookupQuery(data: Record<string, unknown>, basicQuery?: SelectQuery | null): SelectQuery<Model>;
51
+ create(data: Record<string, unknown>): Promise<Model>;
52
+ findAndCheckAccessOrDie(id: unknown, user: unknown, mode?: string | null): Promise<Model>;
53
+ model(class_name: string): IModelConstructor;
54
+ registerModel(model_class: IModelConstructor): IModelConstructor;
55
+ }
4
56
  declare class Model extends ActiveRecord {
5
57
  private get _mCls();
6
58
  static get ignore_extra_fields(): boolean;
@@ -49,12 +101,12 @@ declare class Model extends ActiveRecord {
49
101
  * @param data
50
102
  * @param basicQuery Query to be used for adding conditions. By default a new SelectQuery is created.
51
103
  */
52
- static lookupQuery(data: Record<string, unknown>, basicQuery?: SelectQuery | null): SelectQuery;
104
+ static lookupQuery<T extends Model>(this: abstract new (data?: Record<string, unknown>) => T, data: Record<string, unknown>, basicQuery?: SelectQuery | null): SelectQuery<T>;
53
105
  /**
54
106
  * Creates object
55
107
  * @param data
56
108
  */
57
- static create(data: Record<string, unknown>): Promise<Model>;
109
+ static create<T extends Model>(this: abstract new (data?: Record<string, unknown>) => T, data: Record<string, unknown>): Promise<T>;
58
110
  /**
59
111
  * Updates object
60
112
  * @param data
@@ -73,19 +125,21 @@ declare class Model extends ActiveRecord {
73
125
  * Validate object's data
74
126
  */
75
127
  validate(): Promise<void>;
128
+ static model(class_name: string): IModelConstructor;
129
+ static registerModel(model_class: Parameters<typeof ActiveRecord.registerModel>[0]): typeof Model;
76
130
  /**
77
131
  * Returns object by ID if it exists and accessible by user
78
132
  * @param id
79
133
  * @param user
80
134
  * @param mode
81
135
  */
82
- static findAndCheckAccessOrDie(id: unknown, user: unknown, mode?: string | null): Promise<Model>;
136
+ static findAndCheckAccessOrDie<T extends Model>(this: abstract new (data?: Record<string, unknown>) => T, id: number, user: unknown, mode?: string | null): Promise<T>;
83
137
  /**
84
138
  * Returns whether the object is accessible by user
85
139
  * @param user
86
140
  * @param mode
87
141
  */
88
- accessible(user: unknown, mode?: string | null): Promise<boolean>;
142
+ accessible(_user: unknown, mode?: string | null): Promise<boolean>;
89
143
  /**
90
144
  * Returns public data of the object
91
145
  */
@@ -94,7 +148,7 @@ declare class Model extends ActiveRecord {
94
148
  * Format output
95
149
  * @param mode
96
150
  */
97
- formatOutput(mode?: string | null): Record<string, unknown>;
151
+ formatOutput(_mode?: string | null): Record<string, unknown>;
98
152
  /**
99
153
  * Returns public data of the object with relations
100
154
  * @param required_relations
@@ -115,4 +169,4 @@ declare class OrangeDatabaseModelRuntimeError extends OrangeDatabaseModelError {
115
169
  declare class OrangeDatabaseModelAccessError extends OrangeDatabaseModelRuntimeError {
116
170
  }
117
171
 
118
- export { Model, OrangeDatabaseInputValidationError, OrangeDatabaseModelAccessError, OrangeDatabaseModelError, OrangeDatabaseModelRuntimeError, Model as default };
172
+ export { type IModelConstructor, Model, type ModelData, OrangeDatabaseInputValidationError, OrangeDatabaseModelAccessError, OrangeDatabaseModelError, OrangeDatabaseModelRuntimeError, Model as default };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/model.ts
2
2
  import { ActiveRecord } from "orange-dragonfly-orm";
3
- import { parse } from "orange-dragonfly-validator";
3
+ import { ODValidatorException, parse } from "orange-dragonfly-validator";
4
4
 
5
5
  // src/errors.ts
6
6
  import { OrangeDatabaseError, OrangeDatabaseInputError } from "orange-dragonfly-orm";
@@ -107,28 +107,39 @@ var Model = class extends ActiveRecord {
107
107
  * @param basicQuery Query to be used for adding conditions. By default a new SelectQuery is created.
108
108
  */
109
109
  static lookupQuery(data, basicQuery = null) {
110
- const rules = this.validation_rules;
111
- const q = basicQuery ?? this.selectQuery();
110
+ const cls = this;
111
+ const rules = cls.validation_rules;
112
+ const q = basicQuery ?? cls.selectQuery();
112
113
  const filtered_rules = {};
113
114
  for (const field of Object.keys(data)) {
114
115
  if (!Object.hasOwn(rules, field)) {
115
- if (this.ignore_extra_fields) {
116
+ if (cls.ignore_extra_fields) {
116
117
  continue;
117
118
  }
118
119
  const ex = new OrangeDatabaseInputValidationError("Parameters error");
119
- ex.info[field] = `Field "${field}" is not described for model ${this.name}`;
120
+ ex.info[field] = `Field "${field}" is not described for model ${cls.name}`;
120
121
  throw ex;
121
122
  }
122
- if (this.restricted_for_lookup.includes(field)) {
123
+ if (cls.restricted_for_lookup.includes(field)) {
123
124
  const ex = new OrangeDatabaseInputValidationError("Parameters error");
124
- ex.info[field] = `Field "${field}" is restricted for searching model ${this.name}`;
125
+ ex.info[field] = `Field "${field}" is restricted for searching model ${cls.name}`;
125
126
  throw ex;
126
127
  }
127
128
  q.where(field, data[field]);
128
129
  const rule = rules[field];
129
130
  filtered_rules[field] = Array.isArray(data[field]) ? { type: "array", children: { "*": rule } } : rule;
130
131
  }
131
- parse(filtered_rules, data, { strictMode: false });
132
+ try {
133
+ parse(filtered_rules, data, { strictMode: false });
134
+ } catch (e) {
135
+ if (e instanceof ODValidatorException) {
136
+ const message = `Model ${cls.name} lookup rules validation failed`;
137
+ console.error(message, e.info);
138
+ throw new OrangeDatabaseInputValidationError(message);
139
+ } else {
140
+ throw e;
141
+ }
142
+ }
132
143
  return q;
133
144
  }
134
145
  /**
@@ -136,20 +147,21 @@ var Model = class extends ActiveRecord {
136
147
  * @param data
137
148
  */
138
149
  static async create(data) {
139
- const rules = this.validation_rules;
150
+ const cls = this;
151
+ const rules = cls.validation_rules;
140
152
  const new_data = {};
141
153
  for (const field of Object.keys(data)) {
142
154
  if (!Object.hasOwn(rules, field)) {
143
- if (this.ignore_extra_fields) {
155
+ if (cls.ignore_extra_fields) {
144
156
  continue;
145
157
  }
146
158
  const ex = new OrangeDatabaseInputValidationError("Parameters error");
147
- ex.info[field] = `Field "${field}" is not described for model ${this.name}`;
159
+ ex.info[field] = `Field "${field}" is not described for model ${cls.name}`;
148
160
  throw ex;
149
161
  }
150
- if (this.restricted_for_create.includes(field)) {
162
+ if (cls.restricted_for_create.includes(field)) {
151
163
  const ex = new OrangeDatabaseInputValidationError("Parameters error");
152
- ex.info[field] = `Field "${field}" is restricted for creating model ${this.name}`;
164
+ ex.info[field] = `Field "${field}" is restricted for creating model ${cls.name}`;
153
165
  throw ex;
154
166
  }
155
167
  new_data[field] = data[field];
@@ -245,7 +257,21 @@ var Model = class extends ActiveRecord {
245
257
  }
246
258
  }
247
259
  }
248
- this.data = parse(rules, this.data, { strictMode: false });
260
+ try {
261
+ this.data = parse(rules, this.data, { strictMode: false });
262
+ } catch (e) {
263
+ if (e instanceof ODValidatorException) {
264
+ const message = `Model ${cls.name} rules validation failed`;
265
+ console.error(message, e.info);
266
+ const ex = new OrangeDatabaseInputValidationError(message);
267
+ for (const [key, msgs] of Object.entries(e.info)) {
268
+ ex.info[key] = Array.isArray(msgs) ? msgs[0] : msgs;
269
+ }
270
+ throw ex;
271
+ } else {
272
+ throw e;
273
+ }
274
+ }
249
275
  const custom_validation_errors = await this.custom_validation();
250
276
  if (custom_validation_errors && Object.keys(custom_validation_errors).length) {
251
277
  const ex = new OrangeDatabaseInputValidationError("Validation failed");
@@ -263,12 +289,18 @@ var Model = class extends ActiveRecord {
263
289
  }
264
290
  }
265
291
  }
266
- if (relation_errors.length) {
267
- const ex = new OrangeDatabaseInputValidationError(`Some relations of the ${cls.name} are not found`);
268
- for (const param of relation_errors) ex.info[param] = "Parent object not found";
269
- throw ex;
270
- }
271
292
  }
293
+ if (relation_errors.length) {
294
+ const ex = new OrangeDatabaseInputValidationError(`Some relations of the ${cls.name} are not found`);
295
+ for (const param of relation_errors) ex.info[param] = "Parent object not found";
296
+ throw ex;
297
+ }
298
+ }
299
+ static model(class_name) {
300
+ return super.model(class_name);
301
+ }
302
+ static registerModel(model_class) {
303
+ return super.registerModel(model_class);
272
304
  }
273
305
  /**
274
306
  * Returns object by ID if it exists and accessible by user
@@ -277,12 +309,13 @@ var Model = class extends ActiveRecord {
277
309
  * @param mode
278
310
  */
279
311
  static async findAndCheckAccessOrDie(id, user, mode = null) {
280
- const obj = await this.find(id);
312
+ const cls = this;
313
+ const obj = await cls.find(id);
281
314
  if (!obj) {
282
- throw new OrangeDatabaseModelRuntimeError(`${this.name} #${id} not found`);
315
+ throw new OrangeDatabaseModelRuntimeError(`${cls.name} #${id} not found`);
283
316
  }
284
317
  if (!await obj.accessible(user, mode)) {
285
- throw new OrangeDatabaseModelAccessError(`${this.name} #${id} is not accessible${mode ? ` for ${mode}` : ""}`);
318
+ throw new OrangeDatabaseModelAccessError(`${cls.name} #${id} is not accessible${mode ? ` for ${mode}` : ""}`);
286
319
  }
287
320
  return obj;
288
321
  }
@@ -291,7 +324,7 @@ var Model = class extends ActiveRecord {
291
324
  * @param user
292
325
  * @param mode
293
326
  */
294
- async accessible(user, mode = null) {
327
+ async accessible(_user, mode = null) {
295
328
  return mode === null;
296
329
  }
297
330
  /**
@@ -306,8 +339,7 @@ var Model = class extends ActiveRecord {
306
339
  * Format output
307
340
  * @param mode
308
341
  */
309
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
310
- formatOutput(mode = null) {
342
+ formatOutput(_mode = null) {
311
343
  return this.output;
312
344
  }
313
345
  /**
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/model.ts","../src/errors.ts"],"sourcesContent":["import { ActiveRecord, Relation, SelectQuery } from 'orange-dragonfly-orm'\nimport { parse, type ODValidatorRuleSchema, type ODValidatorRulesSchema } from 'orange-dragonfly-validator'\nimport {\n OrangeDatabaseInputValidationError,\n OrangeDatabaseModelAccessError,\n OrangeDatabaseModelError,\n OrangeDatabaseModelRuntimeError,\n} from './errors'\n\nexport default class Model extends ActiveRecord {\n private get _mCls(): typeof Model {\n return this.constructor as typeof Model\n }\n\n static get ignore_extra_fields(): boolean {\n return false\n }\n\n /**\n * Returns list of unique keys\n * @returns List of unique keys\n */\n static get unique_keys(): string[][] {\n return []\n }\n\n /**\n * Returns list of fulltext indexes\n * @returns List of fulltext indexes\n */\n static get fulltext_indexes(): string[][] {\n return []\n }\n\n /** @deprecated Use `ignore_extra_fields` instead */\n static get IGNORE_EXTRA_FIELDS(): boolean {\n return this.ignore_extra_fields\n }\n\n /** @deprecated Use `unique_keys` instead */\n static get UNIQUE_KEYS(): string[][] {\n return this.unique_keys\n }\n\n /** @deprecated Use `fulltext_indexes` instead */\n static get FULLTEXT_INDEXES(): string[][] {\n return this.fulltext_indexes\n }\n\n /**\n * Returns schema for the model (Orange Dragonfly Validator format)\n */\n static get validation_rules(): ODValidatorRulesSchema {\n return {\n id: {\n required: false,\n type: 'integer',\n min: 1,\n },\n }\n }\n\n /**\n * Overridden method of ActiveRecord. Returns special fields list based on validation rules\n */\n static override get special_fields(): string[] {\n const rules = this.validation_rules\n const fields: string[] = []\n for (const field of ['created_at', 'updated_at', 'deleted_at']) {\n if (Object.hasOwn(rules, field)) fields.push(field)\n }\n return fields\n }\n\n /**\n * Returns list of relations restricted for extended output\n */\n static get restricted_for_output(): string[] {\n return []\n }\n\n /**\n * Returns list of fields restricted for lookup\n */\n static get restricted_for_lookup(): string[] {\n return []\n }\n\n /**\n * Returns list of fields restricted for create method\n */\n static get restricted_for_create(): string[] {\n return ['id'].concat(this.special_fields)\n }\n\n /**\n * Returns list of fields restricted for update method\n */\n static get restricted_for_update(): string[] {\n return ['id'].concat(this.special_fields)\n }\n\n /**\n * Lookup method\n * @param data\n * @param basicQuery Query to be used for adding conditions. By default a new SelectQuery is created.\n */\n static lookupQuery(data: Record<string, unknown>, basicQuery: SelectQuery | null = null): SelectQuery {\n const rules = this.validation_rules\n const q = basicQuery ?? this.selectQuery()\n const filtered_rules: ODValidatorRulesSchema = {}\n for (const field of Object.keys(data)) {\n if (!Object.hasOwn(rules, field)) {\n if (this.ignore_extra_fields) {\n continue\n }\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\n ex.info[field] = `Field \"${field}\" is not described for model ${this.name}`\n throw ex\n }\n if (this.restricted_for_lookup.includes(field)) {\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\n ex.info[field] = `Field \"${field}\" is restricted for searching model ${this.name}`\n throw ex\n }\n q.where(field, data[field])\n const rule = rules[field] as ODValidatorRuleSchema\n filtered_rules[field] = Array.isArray(data[field]) ? { type: 'array', children: { '*': rule } } : rule\n }\n parse(filtered_rules, data, { strictMode: false })\n return q\n }\n\n /**\n * Creates object\n * @param data\n */\n static async create(data: Record<string, unknown>): Promise<Model> {\n const rules = this.validation_rules\n const new_data: Record<string, unknown> = {}\n for (const field of Object.keys(data)) {\n if (!Object.hasOwn(rules, field)) {\n if (this.ignore_extra_fields) {\n continue\n }\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\n ex.info[field] = `Field \"${field}\" is not described for model ${this.name}`\n throw ex\n }\n if (this.restricted_for_create.includes(field)) {\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\n ex.info[field] = `Field \"${field}\" is restricted for creating model ${this.name}`\n throw ex\n }\n new_data[field] = data[field]\n }\n const Cls = this as unknown as new (data?: Record<string, unknown>) => Model\n return (new Cls(new_data)).save()\n }\n\n /**\n * Updates object\n * @param data\n */\n async update(data: Record<string, unknown>): Promise<this> {\n if (!this.id) {\n throw new OrangeDatabaseModelRuntimeError('You can update saved object only')\n }\n const cls = this._mCls\n const rules = cls.validation_rules\n const new_data: Record<string, unknown> = {}\n for (const field of Object.keys(data)) {\n if (!Object.hasOwn(rules, field)) {\n if (cls.ignore_extra_fields) {\n continue\n }\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\n ex.info[field] = `Field \"${field}\" is not described for model ${cls.name}`\n throw ex\n }\n if (cls.restricted_for_update.includes(field)) {\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\n ex.info[field] = `Field \"${field}\" is restricted for updating model ${cls.name}`\n throw ex\n }\n new_data[field] = data[field]\n }\n return this.save(new_data)\n }\n\n /**\n * Checks uniqueness of the object based on unique_keys\n */\n async checkUniqueness(exception_mode = false, ignore_null = false): Promise<boolean> {\n const cls = this._mCls\n for (const fields of cls.unique_keys) {\n if (!await this.isUnique(fields, ignore_null)) {\n if (exception_mode) {\n const ex = new OrangeDatabaseInputValidationError('Object is not unique')\n for (const field of fields) {\n ex.info[field] = 'Part of the unique key'\n }\n throw ex\n }\n return false\n }\n }\n return true\n }\n\n protected override async _preSave(_is_new?: boolean): Promise<void> {\n const cls = this._mCls\n if (cls.ignore_extra_fields) {\n const rules = cls.validation_rules\n for (const key of Object.keys(this.data).filter(v => !Object.hasOwn(rules, v))) {\n delete this.data[key]\n }\n }\n await super._preSave(_is_new)\n await this.checkUniqueness(true, true)\n await this.validate()\n }\n\n /**\n * Performs custom validation - returns null in case of success or an object of validation issues\n */\n async custom_validation(): Promise<Record<string, string> | null> {\n return null\n }\n\n /**\n * Validate object's data\n */\n async validate(): Promise<void> {\n const cls = this._mCls\n const rules = cls.validation_rules\n if (!rules) {\n throw new OrangeDatabaseModelError(`Validation rules are not defined for model ${cls.name}`)\n }\n for (const rule_name of Object.keys(rules)) {\n if (Object.hasOwn(this.data, rule_name)) {\n const rule = rules[rule_name] as ODValidatorRuleSchema\n if (rule?.type) {\n const types = Array.isArray(rule.type) ? (rule.type as string[]) : [rule.type as string]\n if (types.includes('boolean')) {\n if ((this.data[rule_name] === 1) || (this.data[rule_name] === 0)) {\n this.data[rule_name] = this.data[rule_name] === 1\n }\n }\n }\n }\n }\n this.data = parse(rules, this.data, { strictMode: false })\n const custom_validation_errors = await this.custom_validation()\n if (custom_validation_errors && Object.keys(custom_validation_errors).length) {\n const ex = new OrangeDatabaseInputValidationError('Validation failed')\n for (const [param, message] of Object.entries(custom_validation_errors)) ex.info[param] = message\n throw ex\n }\n const relation_errors: string[] = []\n for (const rel_name of Object.keys(cls.available_relations)) {\n const rel: Relation = cls.available_relations[rel_name]\n if (rel.mode === 'parent') {\n const aKey = (rel as unknown as { _a_key_by_mode: string })._a_key_by_mode\n if (Object.hasOwn(this.data, aKey) && (this.data[aKey] !== null) && (this.data[aKey] !== 0)) {\n if ((await this.rel(rel_name, true) as Model | null) === null) {\n relation_errors.push(aKey)\n }\n }\n }\n if (relation_errors.length) {\n const ex = new OrangeDatabaseInputValidationError(`Some relations of the ${cls.name} are not found`)\n for (const param of relation_errors) ex.info[param] = 'Parent object not found'\n throw ex\n }\n }\n }\n\n /**\n * Returns object by ID if it exists and accessible by user\n * @param id\n * @param user\n * @param mode\n */\n static async findAndCheckAccessOrDie(id: unknown, user: unknown, mode: string | null = null): Promise<Model> {\n const obj = await this.find(id) as Model | null\n if (!obj) {\n throw new OrangeDatabaseModelRuntimeError(`${this.name} #${id} not found`)\n }\n if (!(await obj.accessible(user, mode))) {\n throw new OrangeDatabaseModelAccessError(`${this.name} #${id} is not accessible${mode ? ` for ${mode}` : ''}`)\n }\n return obj\n }\n\n /**\n * Returns whether the object is accessible by user\n * @param user\n * @param mode\n */\n \n async accessible(user: unknown, mode: string | null = null): Promise<boolean> {\n return mode === null\n }\n\n /**\n * Returns public data of the object\n */\n get output(): Record<string, unknown> {\n return {\n id: this.id,\n }\n }\n\n /**\n * Format output\n * @param mode\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n formatOutput(mode: string | null = null): Record<string, unknown> {\n return this.output\n }\n\n /**\n * Returns public data of the object with relations\n * @param required_relations\n * @param mode\n */\n async getExtendedOutput(required_relations: string[] = [], mode: string | null = null): Promise<Record<string, unknown>> {\n const output = this.formatOutput(mode)\n const cls = this._mCls\n for (const name of required_relations) {\n if (name.split(':').length > 1) continue\n if (cls.restricted_for_output.includes(name)) {\n throw new OrangeDatabaseModelError(`Relation \"${name}\" is not allowed for extended output of model ${cls.name}`)\n }\n const rel_data = await this.rel(name) as Model | Model[] | null\n const rel_mode = `relation:${cls.name}.${name}`\n const rel_relations = required_relations.filter(v => v.startsWith(`${name}:`)).map(v => v.slice(name.length + 1))\n output[`:${name}`] = Array.isArray(rel_data)\n ? await Promise.all(rel_data.map(v => v.getExtendedOutput(rel_relations, rel_mode)))\n : (rel_data ? await rel_data.getExtendedOutput(rel_relations, rel_mode) : null)\n }\n return output\n }\n}\n","import { OrangeDatabaseError, OrangeDatabaseInputError } from 'orange-dragonfly-orm'\n\nexport class OrangeDatabaseInputValidationError extends OrangeDatabaseInputError {\n private _info: Record<string, string> = {}\n\n get info(): Record<string, string> {\n return this._info\n }\n\n set info(v: Record<string, string>) {\n this._info = v\n }\n}\n\nexport class OrangeDatabaseModelError extends OrangeDatabaseError {}\n\nexport class OrangeDatabaseModelRuntimeError extends OrangeDatabaseModelError {}\n\nexport class OrangeDatabaseModelAccessError extends OrangeDatabaseModelRuntimeError {}\n"],"mappings":";AAAA,SAAS,oBAA2C;AACpD,SAAS,aAAsE;;;ACD/E,SAAS,qBAAqB,gCAAgC;AAEvD,IAAM,qCAAN,cAAiD,yBAAyB;AAAA,EACvE,QAAgC,CAAC;AAAA,EAEzC,IAAI,OAA+B;AACjC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,KAAK,GAA2B;AAClC,SAAK,QAAQ;AAAA,EACf;AACF;AAEO,IAAM,2BAAN,cAAuC,oBAAoB;AAAC;AAE5D,IAAM,kCAAN,cAA8C,yBAAyB;AAAC;AAExE,IAAM,iCAAN,cAA6C,gCAAgC;AAAC;;;ADTrF,IAAqB,QAArB,cAAmC,aAAa;AAAA,EAC9C,IAAY,QAAsB;AAChC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,WAAW,sBAA+B;AACxC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,cAA0B;AACnC,WAAO,CAAC;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,mBAA+B;AACxC,WAAO,CAAC;AAAA,EACV;AAAA;AAAA,EAGA,WAAW,sBAA+B;AACxC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,WAAW,cAA0B;AACnC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,WAAW,mBAA+B;AACxC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,mBAA2C;AACpD,WAAO;AAAA,MACL,IAAI;AAAA,QACF,UAAU;AAAA,QACV,MAAM;AAAA,QACN,KAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WAAoB,iBAA2B;AAC7C,UAAM,QAAQ,KAAK;AACnB,UAAM,SAAmB,CAAC;AAC1B,eAAW,SAAS,CAAC,cAAc,cAAc,YAAY,GAAG;AAC9D,UAAI,OAAO,OAAO,OAAO,KAAK,EAAG,QAAO,KAAK,KAAK;AAAA,IACpD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,wBAAkC;AAC3C,WAAO,CAAC;AAAA,EACV;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,wBAAkC;AAC3C,WAAO,CAAC;AAAA,EACV;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,wBAAkC;AAC3C,WAAO,CAAC,IAAI,EAAE,OAAO,KAAK,cAAc;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,wBAAkC;AAC3C,WAAO,CAAC,IAAI,EAAE,OAAO,KAAK,cAAc;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,YAAY,MAA+B,aAAiC,MAAmB;AACpG,UAAM,QAAQ,KAAK;AACnB,UAAM,IAAI,cAAc,KAAK,YAAY;AACzC,UAAM,iBAAyC,CAAC;AAChD,eAAW,SAAS,OAAO,KAAK,IAAI,GAAG;AACrC,UAAI,CAAC,OAAO,OAAO,OAAO,KAAK,GAAG;AAChC,YAAI,KAAK,qBAAqB;AAC5B;AAAA,QACF;AACA,cAAM,KAAK,IAAI,mCAAmC,kBAAkB;AACpE,WAAG,KAAK,KAAK,IAAI,UAAU,KAAK,gCAAgC,KAAK,IAAI;AACzE,cAAM;AAAA,MACR;AACA,UAAI,KAAK,sBAAsB,SAAS,KAAK,GAAG;AAC9C,cAAM,KAAK,IAAI,mCAAmC,kBAAkB;AACpE,WAAG,KAAK,KAAK,IAAI,UAAU,KAAK,uCAAuC,KAAK,IAAI;AAChF,cAAM;AAAA,MACR;AACA,QAAE,MAAM,OAAO,KAAK,KAAK,CAAC;AAC1B,YAAM,OAAO,MAAM,KAAK;AACxB,qBAAe,KAAK,IAAI,MAAM,QAAQ,KAAK,KAAK,CAAC,IAAI,EAAE,MAAM,SAAS,UAAU,EAAE,KAAK,KAAK,EAAE,IAAI;AAAA,IACpG;AACA,UAAM,gBAAgB,MAAM,EAAE,YAAY,MAAM,CAAC;AACjD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,OAAO,MAA+C;AACjE,UAAM,QAAQ,KAAK;AACnB,UAAM,WAAoC,CAAC;AAC3C,eAAW,SAAS,OAAO,KAAK,IAAI,GAAG;AACrC,UAAI,CAAC,OAAO,OAAO,OAAO,KAAK,GAAG;AAChC,YAAI,KAAK,qBAAqB;AAC5B;AAAA,QACF;AACA,cAAM,KAAK,IAAI,mCAAmC,kBAAkB;AACpE,WAAG,KAAK,KAAK,IAAI,UAAU,KAAK,gCAAgC,KAAK,IAAI;AACzE,cAAM;AAAA,MACR;AACA,UAAI,KAAK,sBAAsB,SAAS,KAAK,GAAG;AAC9C,cAAM,KAAK,IAAI,mCAAmC,kBAAkB;AACpE,WAAG,KAAK,KAAK,IAAI,UAAU,KAAK,sCAAsC,KAAK,IAAI;AAC/E,cAAM;AAAA,MACR;AACA,eAAS,KAAK,IAAI,KAAK,KAAK;AAAA,IAC9B;AACA,UAAM,MAAM;AACZ,WAAQ,IAAI,IAAI,QAAQ,EAAG,KAAK;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,MAA8C;AACzD,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,IAAI,gCAAgC,kCAAkC;AAAA,IAC9E;AACA,UAAM,MAAM,KAAK;AACjB,UAAM,QAAQ,IAAI;AAClB,UAAM,WAAoC,CAAC;AAC3C,eAAW,SAAS,OAAO,KAAK,IAAI,GAAG;AACrC,UAAI,CAAC,OAAO,OAAO,OAAO,KAAK,GAAG;AAChC,YAAI,IAAI,qBAAqB;AAC3B;AAAA,QACF;AACA,cAAM,KAAK,IAAI,mCAAmC,kBAAkB;AACpE,WAAG,KAAK,KAAK,IAAI,UAAU,KAAK,gCAAgC,IAAI,IAAI;AACxE,cAAM;AAAA,MACR;AACA,UAAI,IAAI,sBAAsB,SAAS,KAAK,GAAG;AAC7C,cAAM,KAAK,IAAI,mCAAmC,kBAAkB;AACpE,WAAG,KAAK,KAAK,IAAI,UAAU,KAAK,sCAAsC,IAAI,IAAI;AAC9E,cAAM;AAAA,MACR;AACA,eAAS,KAAK,IAAI,KAAK,KAAK;AAAA,IAC9B;AACA,WAAO,KAAK,KAAK,QAAQ;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBAAgB,iBAAiB,OAAO,cAAc,OAAyB;AACnF,UAAM,MAAM,KAAK;AACjB,eAAW,UAAU,IAAI,aAAa;AACpC,UAAI,CAAC,MAAM,KAAK,SAAS,QAAQ,WAAW,GAAG;AAC7C,YAAI,gBAAgB;AAClB,gBAAM,KAAK,IAAI,mCAAmC,sBAAsB;AACxE,qBAAW,SAAS,QAAQ;AAC1B,eAAG,KAAK,KAAK,IAAI;AAAA,UACnB;AACA,gBAAM;AAAA,QACR;AACA,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAyB,SAAS,SAAkC;AAClE,UAAM,MAAM,KAAK;AACjB,QAAI,IAAI,qBAAqB;AAC3B,YAAM,QAAQ,IAAI;AAClB,iBAAW,OAAO,OAAO,KAAK,KAAK,IAAI,EAAE,OAAO,OAAK,CAAC,OAAO,OAAO,OAAO,CAAC,CAAC,GAAG;AAC9E,eAAO,KAAK,KAAK,GAAG;AAAA,MACtB;AAAA,IACF;AACA,UAAM,MAAM,SAAS,OAAO;AAC5B,UAAM,KAAK,gBAAgB,MAAM,IAAI;AACrC,UAAM,KAAK,SAAS;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBAA4D;AAChE,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAA0B;AAC9B,UAAM,MAAM,KAAK;AACjB,UAAM,QAAQ,IAAI;AAClB,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,yBAAyB,8CAA8C,IAAI,IAAI,EAAE;AAAA,IAC7F;AACA,eAAW,aAAa,OAAO,KAAK,KAAK,GAAG;AAC1C,UAAI,OAAO,OAAO,KAAK,MAAM,SAAS,GAAG;AACvC,cAAM,OAAO,MAAM,SAAS;AAC5B,YAAI,MAAM,MAAM;AACd,gBAAM,QAAQ,MAAM,QAAQ,KAAK,IAAI,IAAK,KAAK,OAAoB,CAAC,KAAK,IAAc;AACvF,cAAI,MAAM,SAAS,SAAS,GAAG;AAC7B,gBAAK,KAAK,KAAK,SAAS,MAAM,KAAO,KAAK,KAAK,SAAS,MAAM,GAAI;AAChE,mBAAK,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,MAAM;AAAA,YAClD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,SAAK,OAAO,MAAM,OAAO,KAAK,MAAM,EAAE,YAAY,MAAM,CAAC;AACzD,UAAM,2BAA2B,MAAM,KAAK,kBAAkB;AAC9D,QAAI,4BAA4B,OAAO,KAAK,wBAAwB,EAAE,QAAQ;AAC5E,YAAM,KAAK,IAAI,mCAAmC,mBAAmB;AACrE,iBAAW,CAAC,OAAO,OAAO,KAAK,OAAO,QAAQ,wBAAwB,EAAG,IAAG,KAAK,KAAK,IAAI;AAC1F,YAAM;AAAA,IACR;AACA,UAAM,kBAA4B,CAAC;AACnC,eAAW,YAAY,OAAO,KAAK,IAAI,mBAAmB,GAAG;AAC3D,YAAM,MAAgB,IAAI,oBAAoB,QAAQ;AACtD,UAAI,IAAI,SAAS,UAAU;AACzB,cAAM,OAAQ,IAA8C;AAC5D,YAAI,OAAO,OAAO,KAAK,MAAM,IAAI,KAAM,KAAK,KAAK,IAAI,MAAM,QAAU,KAAK,KAAK,IAAI,MAAM,GAAI;AAC3F,cAAK,MAAM,KAAK,IAAI,UAAU,IAAI,MAAuB,MAAM;AAC7D,4BAAgB,KAAK,IAAI;AAAA,UAC3B;AAAA,QACF;AAAA,MACF;AACA,UAAI,gBAAgB,QAAQ;AAC1B,cAAM,KAAK,IAAI,mCAAmC,yBAAyB,IAAI,IAAI,gBAAgB;AACnG,mBAAW,SAAS,gBAAiB,IAAG,KAAK,KAAK,IAAI;AACtD,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,wBAAwB,IAAa,MAAe,OAAsB,MAAsB;AAC3G,UAAM,MAAM,MAAM,KAAK,KAAK,EAAE;AAC9B,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,gCAAgC,GAAG,KAAK,IAAI,KAAK,EAAE,YAAY;AAAA,IAC3E;AACA,QAAI,CAAE,MAAM,IAAI,WAAW,MAAM,IAAI,GAAI;AACvC,YAAM,IAAI,+BAA+B,GAAG,KAAK,IAAI,KAAK,EAAE,qBAAqB,OAAO,QAAQ,IAAI,KAAK,EAAE,EAAE;AAAA,IAC/G;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,WAAW,MAAe,OAAsB,MAAwB;AAC5E,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAkC;AACpC,WAAO;AAAA,MACL,IAAI,KAAK;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,OAAsB,MAA+B;AAChE,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,kBAAkB,qBAA+B,CAAC,GAAG,OAAsB,MAAwC;AACvH,UAAM,SAAS,KAAK,aAAa,IAAI;AACrC,UAAM,MAAM,KAAK;AACjB,eAAW,QAAQ,oBAAoB;AACrC,UAAI,KAAK,MAAM,GAAG,EAAE,SAAS,EAAG;AAChC,UAAI,IAAI,sBAAsB,SAAS,IAAI,GAAG;AAC5C,cAAM,IAAI,yBAAyB,aAAa,IAAI,iDAAiD,IAAI,IAAI,EAAE;AAAA,MACjH;AACA,YAAM,WAAW,MAAM,KAAK,IAAI,IAAI;AACpC,YAAM,WAAW,YAAY,IAAI,IAAI,IAAI,IAAI;AAC7C,YAAM,gBAAgB,mBAAmB,OAAO,OAAK,EAAE,WAAW,GAAG,IAAI,GAAG,CAAC,EAAE,IAAI,OAAK,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC;AAChH,aAAO,IAAI,IAAI,EAAE,IAAI,MAAM,QAAQ,QAAQ,IACvC,MAAM,QAAQ,IAAI,SAAS,IAAI,OAAK,EAAE,kBAAkB,eAAe,QAAQ,CAAC,CAAC,IAChF,WAAW,MAAM,SAAS,kBAAkB,eAAe,QAAQ,IAAI;AAAA,IAC9E;AACA,WAAO;AAAA,EACT;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/model.ts","../src/errors.ts"],"sourcesContent":["import { ActiveRecord, type DeleteQuery, type InsertQuery, type IQueryBuilder, type Relation, SelectQuery, type UpdateQuery } from 'orange-dragonfly-orm'\r\nimport { ODValidatorException, parse, type ODValidatorRuleSchema, type ODValidatorRulesSchema } from 'orange-dragonfly-validator'\r\n\r\ntype ValidatorTSType<T extends string> =\r\n T extends 'string' ? string :\r\n T extends 'integer' | 'number' ? number :\r\n T extends 'boolean' ? boolean :\r\n T extends 'null' ? null :\r\n T extends 'object' ? Record<string, unknown> :\r\n T extends 'array' ? unknown[] :\r\n T extends 'function' ? (...args: unknown[]) => unknown :\r\n unknown\r\n\r\ntype FieldTS<R extends ODValidatorRuleSchema> =\r\n R['type'] extends string\r\n ? ValidatorTSType<R['type']>\r\n : R['type'] extends readonly (infer U extends string)[]\r\n ? ValidatorTSType<U>\r\n : unknown\r\n\r\n/**\r\n * Converts an `ODValidatorRulesSchema` to a TypeScript object type.\r\n * Requires the schema to be declared with `as const satisfies ODValidatorRulesSchema`\r\n * to preserve literal type information.\r\n *\r\n * @example\r\n * const schema = { name: { type: 'string', required: true } } as const satisfies ODValidatorRulesSchema\r\n * class MyModel extends Model {\r\n * static override get validation_rules() { return schema }\r\n * declare data: ModelData<typeof schema>\r\n * }\r\n */\r\nexport type ModelData<S extends ODValidatorRulesSchema> = {\r\n [K in Exclude<keyof S, '@' | '#' | '*'>]: S[K] extends ODValidatorRuleSchema ? FieldTS<S[K]> : never\r\n}\r\n\r\nimport {\r\n OrangeDatabaseInputValidationError,\r\n OrangeDatabaseModelAccessError,\r\n OrangeDatabaseModelError,\r\n OrangeDatabaseModelRuntimeError,\r\n} from './errors'\r\n\r\nexport interface IModelConstructor {\r\n new(data?: Record<string, unknown>): Model\r\n readonly id_key: string\r\n readonly table: string\r\n readonly name: string\r\n readonly special_fields: string[]\r\n readonly available_relations: Record<string, Relation>\r\n readonly ignore_extra_fields: boolean\r\n readonly unique_keys: string[][]\r\n readonly fulltext_indexes: string[][]\r\n /** @deprecated Use `ignore_extra_fields` instead */\r\n readonly IGNORE_EXTRA_FIELDS: boolean\r\n /** @deprecated Use `unique_keys` instead */\r\n readonly UNIQUE_KEYS: string[][]\r\n /** @deprecated Use `fulltext_indexes` instead */\r\n readonly FULLTEXT_INDEXES: string[][]\r\n readonly validation_rules: ODValidatorRulesSchema\r\n readonly restricted_for_output: string[]\r\n readonly restricted_for_lookup: string[]\r\n readonly restricted_for_create: string[]\r\n readonly restricted_for_update: string[]\r\n resetRegisteredModels(): void\r\n insertQuery(): InsertQuery\r\n selectQuery(include_deleted?: boolean): IQueryBuilder<Model>\r\n updateQuery(include_deleted?: boolean): UpdateQuery\r\n deleteQuery(include_deleted?: boolean): DeleteQuery\r\n loadRelations(objects: Model[], relations?: string[] | null): Promise<Model[]>\r\n find(id: unknown, include_deleted?: boolean): Promise<Model | null>\r\n all(include_deleted?: boolean): Promise<Model[]>\r\n lookupQuery(data: Record<string, unknown>, basicQuery?: SelectQuery | null): SelectQuery<Model>\r\n create(data: Record<string, unknown>): Promise<Model>\r\n findAndCheckAccessOrDie(id: unknown, user: unknown, mode?: string | null): Promise<Model>\r\n model(class_name: string): IModelConstructor\r\n registerModel(model_class: IModelConstructor): IModelConstructor\r\n}\r\n\r\nexport default class Model extends ActiveRecord {\r\n private get _mCls(): typeof Model {\r\n return this.constructor as typeof Model\r\n }\r\n\r\n static get ignore_extra_fields(): boolean {\r\n return false\r\n }\r\n\r\n /**\r\n * Returns list of unique keys\r\n * @returns List of unique keys\r\n */\r\n static get unique_keys(): string[][] {\r\n return []\r\n }\r\n\r\n /**\r\n * Returns list of fulltext indexes\r\n * @returns List of fulltext indexes\r\n */\r\n static get fulltext_indexes(): string[][] {\r\n return []\r\n }\r\n\r\n /** @deprecated Use `ignore_extra_fields` instead */\r\n static get IGNORE_EXTRA_FIELDS(): boolean {\r\n return this.ignore_extra_fields\r\n }\r\n\r\n /** @deprecated Use `unique_keys` instead */\r\n static get UNIQUE_KEYS(): string[][] {\r\n return this.unique_keys\r\n }\r\n\r\n /** @deprecated Use `fulltext_indexes` instead */\r\n static get FULLTEXT_INDEXES(): string[][] {\r\n return this.fulltext_indexes\r\n }\r\n\r\n /**\r\n * Returns schema for the model (Orange Dragonfly Validator format)\r\n */\r\n static get validation_rules(): ODValidatorRulesSchema {\r\n return {\r\n id: {\r\n required: false,\r\n type: 'integer',\r\n min: 1,\r\n },\r\n }\r\n }\r\n\r\n /**\r\n * Overridden method of ActiveRecord. Returns special fields list based on validation rules\r\n */\r\n static override get special_fields(): string[] {\r\n const rules = this.validation_rules\r\n const fields: string[] = []\r\n for (const field of ['created_at', 'updated_at', 'deleted_at']) {\r\n if (Object.hasOwn(rules, field)) fields.push(field)\r\n }\r\n return fields\r\n }\r\n\r\n /**\r\n * Returns list of relations restricted for extended output\r\n */\r\n static get restricted_for_output(): string[] {\r\n return []\r\n }\r\n\r\n /**\r\n * Returns list of fields restricted for lookup\r\n */\r\n static get restricted_for_lookup(): string[] {\r\n return []\r\n }\r\n\r\n /**\r\n * Returns list of fields restricted for create method\r\n */\r\n static get restricted_for_create(): string[] {\r\n return ['id'].concat(this.special_fields)\r\n }\r\n\r\n /**\r\n * Returns list of fields restricted for update method\r\n */\r\n static get restricted_for_update(): string[] {\r\n return ['id'].concat(this.special_fields)\r\n }\r\n\r\n /**\r\n * Lookup method\r\n * @param data\r\n * @param basicQuery Query to be used for adding conditions. By default a new SelectQuery is created.\r\n */\r\n static lookupQuery<T extends Model>(\r\n this: abstract new (data?: Record<string, unknown>) => T,\r\n data: Record<string, unknown>,\r\n basicQuery: SelectQuery | null = null,\r\n ): SelectQuery<T> {\r\n const cls = this as unknown as typeof Model\r\n const rules = cls.validation_rules\r\n const q = (basicQuery ?? cls.selectQuery()) as SelectQuery<T>\r\n const filtered_rules: ODValidatorRulesSchema = {}\r\n for (const field of Object.keys(data)) {\r\n if (!Object.hasOwn(rules, field)) {\r\n if (cls.ignore_extra_fields) {\r\n continue\r\n }\r\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\r\n ex.info[field] = `Field \"${field}\" is not described for model ${cls.name}`\r\n throw ex\r\n }\r\n if (cls.restricted_for_lookup.includes(field)) {\r\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\r\n ex.info[field] = `Field \"${field}\" is restricted for searching model ${cls.name}`\r\n throw ex\r\n }\r\n q.where(field, data[field])\r\n const rule = rules[field] as ODValidatorRuleSchema\r\n filtered_rules[field] = Array.isArray(data[field]) ? { type: 'array', children: { '*': rule } } : rule\r\n }\r\n try {\r\n parse(filtered_rules, data, { strictMode: false })\r\n } catch (e) {\r\n if (e instanceof ODValidatorException) {\r\n const message = `Model ${cls.name} lookup rules validation failed`\r\n console.error(message, e.info)\r\n throw new OrangeDatabaseInputValidationError(message)\r\n } else {\r\n throw e\r\n }\r\n }\r\n return q\r\n }\r\n\r\n /**\r\n * Creates object\r\n * @param data\r\n */\r\n static async create<T extends Model>(\r\n this: abstract new (data?: Record<string, unknown>) => T,\r\n data: Record<string, unknown>,\r\n ): Promise<T> {\r\n const cls = this as unknown as typeof Model\r\n const rules = cls.validation_rules\r\n const new_data: Record<string, unknown> = {}\r\n for (const field of Object.keys(data)) {\r\n if (!Object.hasOwn(rules, field)) {\r\n if (cls.ignore_extra_fields) {\r\n continue\r\n }\r\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\r\n ex.info[field] = `Field \"${field}\" is not described for model ${cls.name}`\r\n throw ex\r\n }\r\n if (cls.restricted_for_create.includes(field)) {\r\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\r\n ex.info[field] = `Field \"${field}\" is restricted for creating model ${cls.name}`\r\n throw ex\r\n }\r\n new_data[field] = data[field]\r\n }\r\n const Cls = this as unknown as new (data?: Record<string, unknown>) => T\r\n return (new Cls(new_data)).save()\r\n }\r\n\r\n /**\r\n * Updates object\r\n * @param data\r\n */\r\n async update(data: Record<string, unknown>): Promise<this> {\r\n if (!this.id) {\r\n throw new OrangeDatabaseModelRuntimeError('You can update saved object only')\r\n }\r\n const cls = this._mCls\r\n const rules = cls.validation_rules\r\n const new_data: Record<string, unknown> = {}\r\n for (const field of Object.keys(data)) {\r\n if (!Object.hasOwn(rules, field)) {\r\n if (cls.ignore_extra_fields) {\r\n continue\r\n }\r\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\r\n ex.info[field] = `Field \"${field}\" is not described for model ${cls.name}`\r\n throw ex\r\n }\r\n if (cls.restricted_for_update.includes(field)) {\r\n const ex = new OrangeDatabaseInputValidationError('Parameters error')\r\n ex.info[field] = `Field \"${field}\" is restricted for updating model ${cls.name}`\r\n throw ex\r\n }\r\n new_data[field] = data[field]\r\n }\r\n return this.save(new_data)\r\n }\r\n\r\n /**\r\n * Checks uniqueness of the object based on unique_keys\r\n */\r\n async checkUniqueness(exception_mode = false, ignore_null = false): Promise<boolean> {\r\n const cls = this._mCls\r\n for (const fields of cls.unique_keys) {\r\n if (!await this.isUnique(fields, ignore_null)) {\r\n if (exception_mode) {\r\n const ex = new OrangeDatabaseInputValidationError('Object is not unique')\r\n for (const field of fields) {\r\n ex.info[field] = 'Part of the unique key'\r\n }\r\n throw ex\r\n }\r\n return false\r\n }\r\n }\r\n return true\r\n }\r\n\r\n protected override async _preSave(_is_new?: boolean): Promise<void> {\r\n const cls = this._mCls\r\n if (cls.ignore_extra_fields) {\r\n const rules = cls.validation_rules\r\n for (const key of Object.keys(this.data).filter(v => !Object.hasOwn(rules, v))) {\r\n delete this.data[key]\r\n }\r\n }\r\n await super._preSave(_is_new)\r\n await this.checkUniqueness(true, true)\r\n await this.validate()\r\n }\r\n\r\n /**\r\n * Performs custom validation - returns null in case of success or an object of validation issues\r\n */\r\n async custom_validation(): Promise<Record<string, string> | null> {\r\n return null\r\n }\r\n\r\n /**\r\n * Validate object's data\r\n */\r\n async validate(): Promise<void> {\r\n const cls = this._mCls\r\n const rules = cls.validation_rules\r\n if (!rules) {\r\n throw new OrangeDatabaseModelError(`Validation rules are not defined for model ${cls.name}`)\r\n }\r\n for (const rule_name of Object.keys(rules)) {\r\n if (Object.hasOwn(this.data, rule_name)) {\r\n const rule = rules[rule_name] as ODValidatorRuleSchema\r\n if (rule?.type) {\r\n const types = Array.isArray(rule.type) ? (rule.type as string[]) : [rule.type as string]\r\n if (types.includes('boolean')) {\r\n if ((this.data[rule_name] === 1) || (this.data[rule_name] === 0)) {\r\n this.data[rule_name] = this.data[rule_name] === 1\r\n }\r\n }\r\n }\r\n }\r\n }\r\n try {\r\n this.data = parse(rules, this.data, { strictMode: false })\r\n } catch (e) {\r\n if (e instanceof ODValidatorException) {\r\n const message = `Model ${cls.name} rules validation failed`\r\n console.error(message, e.info)\r\n const ex = new OrangeDatabaseInputValidationError(message)\r\n for (const [key, msgs] of Object.entries(e.info as Record<string, string | string[]>)) {\r\n ex.info[key] = Array.isArray(msgs) ? msgs[0] : msgs\r\n }\r\n throw ex\r\n } else {\r\n throw e\r\n }\r\n }\r\n const custom_validation_errors = await this.custom_validation()\r\n if (custom_validation_errors && Object.keys(custom_validation_errors).length) {\r\n const ex = new OrangeDatabaseInputValidationError('Validation failed')\r\n for (const [param, message] of Object.entries(custom_validation_errors)) ex.info[param] = message\r\n throw ex\r\n }\r\n const relation_errors: string[] = []\r\n for (const rel_name of Object.keys(cls.available_relations)) {\r\n const rel: Relation = cls.available_relations[rel_name]\r\n if (rel.mode === 'parent') {\r\n const aKey = (rel as unknown as { _a_key_by_mode: string })._a_key_by_mode\r\n if (Object.hasOwn(this.data, aKey) && (this.data[aKey] !== null) && (this.data[aKey] !== 0)) {\r\n if ((await this.rel(rel_name, true) as Model | null) === null) {\r\n relation_errors.push(aKey)\r\n }\r\n }\r\n }\r\n }\r\n if (relation_errors.length) {\r\n const ex = new OrangeDatabaseInputValidationError(`Some relations of the ${cls.name} are not found`)\r\n for (const param of relation_errors) ex.info[param] = 'Parent object not found'\r\n throw ex\r\n }\r\n }\r\n\r\n static override model(class_name: string): IModelConstructor {\r\n return super.model(class_name) as unknown as IModelConstructor\r\n }\r\n\r\n static override registerModel(model_class: Parameters<typeof ActiveRecord.registerModel>[0]): typeof Model {\r\n return super.registerModel(model_class) as unknown as typeof Model\r\n }\r\n\r\n /**\r\n * Returns object by ID if it exists and accessible by user\r\n * @param id\r\n * @param user\r\n * @param mode\r\n */\r\n static async findAndCheckAccessOrDie<T extends Model>(\r\n this: abstract new (data?: Record<string, unknown>) => T,\r\n id: number,\r\n user: unknown,\r\n mode: string | null = null,\r\n ): Promise<T> {\r\n const cls = this as unknown as typeof Model\r\n const obj = await cls.find(id) as T | null\r\n if (!obj) {\r\n throw new OrangeDatabaseModelRuntimeError(`${cls.name} #${id} not found`)\r\n }\r\n if (!(await obj.accessible(user, mode))) {\r\n throw new OrangeDatabaseModelAccessError(`${cls.name} #${id} is not accessible${mode ? ` for ${mode}` : ''}`)\r\n }\r\n return obj\r\n }\r\n\r\n /**\r\n * Returns whether the object is accessible by user\r\n * @param user\r\n * @param mode\r\n */\r\n \r\n async accessible(_user: unknown, mode: string | null = null): Promise<boolean> {\r\n return mode === null\r\n }\r\n\r\n /**\r\n * Returns public data of the object\r\n */\r\n get output(): Record<string, unknown> {\r\n return {\r\n id: this.id,\r\n }\r\n }\r\n\r\n /**\r\n * Format output\r\n * @param mode\r\n */\r\n formatOutput(_mode: string | null = null): Record<string, unknown> {\r\n return this.output\r\n }\r\n\r\n /**\r\n * Returns public data of the object with relations\r\n * @param required_relations\r\n * @param mode\r\n */\r\n async getExtendedOutput(required_relations: string[] = [], mode: string | null = null): Promise<Record<string, unknown>> {\r\n const output = this.formatOutput(mode)\r\n const cls = this._mCls\r\n for (const name of required_relations) {\r\n if (name.split(':').length > 1) continue\r\n if (cls.restricted_for_output.includes(name)) {\r\n throw new OrangeDatabaseModelError(`Relation \"${name}\" is not allowed for extended output of model ${cls.name}`)\r\n }\r\n const rel_data = await this.rel(name) as Model | Model[] | null\r\n const rel_mode = `relation:${cls.name}.${name}`\r\n const rel_relations = required_relations.filter(v => v.startsWith(`${name}:`)).map(v => v.slice(name.length + 1))\r\n output[`:${name}`] = Array.isArray(rel_data)\r\n ? await Promise.all(rel_data.map(v => v.getExtendedOutput(rel_relations, rel_mode)))\r\n : (rel_data ? await rel_data.getExtendedOutput(rel_relations, rel_mode) : null)\r\n }\r\n return output\r\n }\r\n}\r\n","import { OrangeDatabaseError, OrangeDatabaseInputError } from 'orange-dragonfly-orm'\n\nexport class OrangeDatabaseInputValidationError extends OrangeDatabaseInputError {\n private _info: Record<string, string> = {}\n\n get info(): Record<string, string> {\n return this._info\n }\n\n set info(v: Record<string, string>) {\n this._info = v\n }\n}\n\nexport class OrangeDatabaseModelError extends OrangeDatabaseError {}\n\nexport class OrangeDatabaseModelRuntimeError extends OrangeDatabaseModelError {}\n\nexport class OrangeDatabaseModelAccessError extends OrangeDatabaseModelRuntimeError {}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orange-dragonfly-model",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "description": "Orange Dragonfly Model - advanced active record ORM model class for Orange Dragonfly framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "homepage": "https://github.com/charger88/orange-dragonfly-model#readme",
54
54
  "dependencies": {
55
- "orange-dragonfly-orm": "^0.8.0",
55
+ "orange-dragonfly-orm": "file:./../orange-dragonfly-db",
56
56
  "orange-dragonfly-validator": "^1.0.2"
57
57
  },
58
58
  "devDependencies": {