@spinajs/orm 2.0.490 → 2.0.494

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +80 -80
  2. package/lib/cjs/builders.d.ts +1 -2
  3. package/lib/cjs/builders.d.ts.map +1 -1
  4. package/lib/cjs/builders.js +2 -0
  5. package/lib/cjs/builders.js.map +1 -1
  6. package/lib/cjs/decorators.d.ts +22 -0
  7. package/lib/cjs/decorators.d.ts.map +1 -1
  8. package/lib/cjs/decorators.js +29 -0
  9. package/lib/cjs/decorators.js.map +1 -1
  10. package/lib/cjs/descriptor.d.ts.map +1 -1
  11. package/lib/cjs/descriptor.js +2 -0
  12. package/lib/cjs/descriptor.js.map +1 -1
  13. package/lib/cjs/driver.d.ts +12 -0
  14. package/lib/cjs/driver.d.ts.map +1 -1
  15. package/lib/cjs/driver.js +12 -0
  16. package/lib/cjs/driver.js.map +1 -1
  17. package/lib/cjs/interfaces.d.ts +35 -24
  18. package/lib/cjs/interfaces.d.ts.map +1 -1
  19. package/lib/cjs/interfaces.js.map +1 -1
  20. package/lib/cjs/model.d.ts +4 -5
  21. package/lib/cjs/model.d.ts.map +1 -1
  22. package/lib/cjs/model.js +6 -7
  23. package/lib/cjs/model.js.map +1 -1
  24. package/lib/cjs/orm.d.ts.map +1 -1
  25. package/lib/cjs/orm.js +4 -1
  26. package/lib/cjs/orm.js.map +1 -1
  27. package/lib/cjs/relation-objects.d.ts +76 -163
  28. package/lib/cjs/relation-objects.d.ts.map +1 -1
  29. package/lib/cjs/relation-objects.js +223 -192
  30. package/lib/cjs/relation-objects.js.map +1 -1
  31. package/lib/cjs/schema-providers.d.ts +34 -0
  32. package/lib/cjs/schema-providers.d.ts.map +1 -1
  33. package/lib/cjs/schema-providers.js +59 -3
  34. package/lib/cjs/schema-providers.js.map +1 -1
  35. package/lib/cjs/schema.d.ts +20 -3
  36. package/lib/cjs/schema.d.ts.map +1 -1
  37. package/lib/cjs/schema.js +59 -9
  38. package/lib/cjs/schema.js.map +1 -1
  39. package/lib/mjs/builders.d.ts +1 -2
  40. package/lib/mjs/builders.d.ts.map +1 -1
  41. package/lib/mjs/builders.js +2 -0
  42. package/lib/mjs/builders.js.map +1 -1
  43. package/lib/mjs/decorators.d.ts +22 -0
  44. package/lib/mjs/decorators.d.ts.map +1 -1
  45. package/lib/mjs/decorators.js +28 -0
  46. package/lib/mjs/decorators.js.map +1 -1
  47. package/lib/mjs/descriptor.d.ts.map +1 -1
  48. package/lib/mjs/descriptor.js +2 -0
  49. package/lib/mjs/descriptor.js.map +1 -1
  50. package/lib/mjs/driver.d.ts +12 -0
  51. package/lib/mjs/driver.d.ts.map +1 -1
  52. package/lib/mjs/driver.js +12 -0
  53. package/lib/mjs/driver.js.map +1 -1
  54. package/lib/mjs/interfaces.d.ts +35 -24
  55. package/lib/mjs/interfaces.d.ts.map +1 -1
  56. package/lib/mjs/interfaces.js.map +1 -1
  57. package/lib/mjs/model.d.ts +4 -5
  58. package/lib/mjs/model.d.ts.map +1 -1
  59. package/lib/mjs/model.js +6 -7
  60. package/lib/mjs/model.js.map +1 -1
  61. package/lib/mjs/orm.d.ts.map +1 -1
  62. package/lib/mjs/orm.js +4 -1
  63. package/lib/mjs/orm.js.map +1 -1
  64. package/lib/mjs/relation-objects.d.ts +76 -163
  65. package/lib/mjs/relation-objects.d.ts.map +1 -1
  66. package/lib/mjs/relation-objects.js +225 -194
  67. package/lib/mjs/relation-objects.js.map +1 -1
  68. package/lib/mjs/schema-providers.d.ts +34 -0
  69. package/lib/mjs/schema-providers.d.ts.map +1 -1
  70. package/lib/mjs/schema-providers.js +59 -3
  71. package/lib/mjs/schema-providers.js.map +1 -1
  72. package/lib/mjs/schema.d.ts +20 -3
  73. package/lib/mjs/schema.d.ts.map +1 -1
  74. package/lib/mjs/schema.js +59 -9
  75. package/lib/mjs/schema.js.map +1 -1
  76. package/lib/tsconfig.cjs.tsbuildinfo +1 -1
  77. package/lib/tsconfig.mjs.tsbuildinfo +1 -1
  78. package/package.json +75 -73
@@ -1,5 +1,6 @@
1
1
  import { Class } from '@spinajs/di';
2
2
  import { SchemaProvider } from '@spinajs/validation';
3
+ import { IModelDescriptor } from './interfaces.js';
3
4
  /**
4
5
  * Resolves an ORM model name to its column schema plus relations. A name → model
5
6
  * class map is built once at initialization (see `resolve`) and reused on every
@@ -9,5 +10,38 @@ export declare class ModelSchemaProvider extends SchemaProvider {
9
10
  protected Models: Map<string, Class<unknown>>;
10
11
  resolve(): void;
11
12
  getSchema(typeName: string): Record<string, unknown> | undefined;
13
+ /**
14
+ * The same set of columns as `getSchema`, but WITHOUT `required`, without the `@Hidden()`
15
+ * columns, and with the types this driver really returns (`descriptor.ResponseSchema`).
16
+ *
17
+ * A response is partial by nature: `dehydrateWithRelations({ skipUndefined: true })` drops
18
+ * fields the query did not load, and `include` decides which relations show up at all. The
19
+ * list of required columns describes an INSERT, not what goes out to the client - published
20
+ * on a response it breaks validation on the first row that has no password or no relation.
21
+ *
22
+ * @param typeName - the model class name
23
+ */
24
+ getResponseSchema(typeName: string): Record<string, unknown> | undefined;
25
+ /**
26
+ * The model's columns plus its relations as properties. `includeRequired` distinguishes
27
+ * the write contract (getSchema) from the read one (getResponseSchema).
28
+ *
29
+ * @param typeName - the model class name
30
+ * @param includeRequired - whether to include the list of required columns (write contract)
31
+ */
32
+ protected buildSchema(typeName: string, includeRequired: boolean): Record<string, unknown> | undefined;
33
+ /**
34
+ * The read schema off the descriptor. `Orm.reloadTableInfo` builds it alongside `Schema`;
35
+ * when it is absent (the model never got a connection, or the descriptor was assembled by
36
+ * hand in a test) we fall back to `Schema` and strip from it what a response never carries
37
+ * anyway - the `@Hidden()` columns. Describing a read with the write contract beats not
38
+ * describing it at all.
39
+ *
40
+ * @param descriptor - the model descriptor
41
+ */
42
+ protected responseColumns(descriptor: IModelDescriptor | undefined): {
43
+ properties?: Record<string, unknown>;
44
+ required?: string[];
45
+ } | undefined;
12
46
  }
13
47
  //# sourceMappingURL=schema-providers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema-providers.d.ts","sourceRoot":"","sources":["../../src/schema-providers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAkB,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD;;;;GAIG;AACH,qBACa,mBAAoB,SAAQ,cAAc;IACrD,SAAS,CAAC,MAAM,8BAAqC;IAE9C,OAAO,IAAI,IAAI;IAMf,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;CAiCxE"}
1
+ {"version":3,"file":"schema-providers.d.ts","sourceRoot":"","sources":["../../src/schema-providers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAkB,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAInD;;;;GAIG;AACH,qBACa,mBAAoB,SAAQ,cAAc;IACrD,SAAS,CAAC,MAAM,8BAAqC;IAE9C,OAAO,IAAI,IAAI;IAMf,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;IAIvE;;;;;;;;;;OAUG;IACI,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;IAI/E;;;;;;OAMG;IACH,SAAS,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;IA0CtG;;;;;;;;OAQG;IACH,SAAS,CAAC,eAAe,CAAC,UAAU,EAAE,gBAAgB,GAAG,SAAS,GAAG;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,SAAS;CAmB/I"}
@@ -23,6 +23,30 @@ let ModelSchemaProvider = class ModelSchemaProvider extends SchemaProvider {
23
23
  }
24
24
  }
25
25
  getSchema(typeName) {
26
+ return this.buildSchema(typeName, true);
27
+ }
28
+ /**
29
+ * The same set of columns as `getSchema`, but WITHOUT `required`, without the `@Hidden()`
30
+ * columns, and with the types this driver really returns (`descriptor.ResponseSchema`).
31
+ *
32
+ * A response is partial by nature: `dehydrateWithRelations({ skipUndefined: true })` drops
33
+ * fields the query did not load, and `include` decides which relations show up at all. The
34
+ * list of required columns describes an INSERT, not what goes out to the client - published
35
+ * on a response it breaks validation on the first row that has no password or no relation.
36
+ *
37
+ * @param typeName - the model class name
38
+ */
39
+ getResponseSchema(typeName) {
40
+ return this.buildSchema(typeName, false);
41
+ }
42
+ /**
43
+ * The model's columns plus its relations as properties. `includeRequired` distinguishes
44
+ * the write contract (getSchema) from the read one (getResponseSchema).
45
+ *
46
+ * @param typeName - the model class name
47
+ * @param includeRequired - whether to include the list of required columns (write contract)
48
+ */
49
+ buildSchema(typeName, includeRequired) {
26
50
  const model = this.Models.get(typeName);
27
51
  if (!model) {
28
52
  return undefined;
@@ -32,14 +56,21 @@ let ModelSchemaProvider = class ModelSchemaProvider extends SchemaProvider {
32
56
  * to get proper descriptor from prototype chain
33
57
  */
34
58
  const descriptor = model.getModelDescriptor();
35
- const columns = descriptor?.Schema;
59
+ const columns = includeRequired ? descriptor?.Schema : this.responseColumns(descriptor);
36
60
  if (!columns || !columns.properties) {
37
61
  return undefined;
38
62
  }
63
+ // `@Hidden()` marks properties, not just columns - a hidden relation is dropped by
64
+ // `dehydrateWithRelations` exactly like a hidden column, so a read schema must not
65
+ // advertise it either. Columns are already filtered upstream (`buildModelJsonSchema`
66
+ // for `ResponseSchema`, `responseColumns` for the fallback); relations are added here,
67
+ // so they have to be filtered here. The write contract keeps them: a client may well
68
+ // send a relation the API never hands back.
69
+ const hiddenRelations = includeRequired ? new Set() : new Set(descriptor?.Hidden ?? []);
39
70
  const properties = { ...columns.properties };
40
71
  descriptor?.Relations?.forEach((relation, relationName) => {
41
72
  const target = relation?.TargetModel?.name;
42
- if (!target) {
73
+ if (!target || hiddenRelations.has(relationName)) {
43
74
  return;
44
75
  }
45
76
  const ref = { type: 'object', description: target };
@@ -47,11 +78,36 @@ let ModelSchemaProvider = class ModelSchemaProvider extends SchemaProvider {
47
78
  relation.Type !== undefined && TO_MANY_RELATION.has(relation.Type) ? { type: 'array', items: ref } : ref;
48
79
  });
49
80
  const schema = { type: 'object', properties };
50
- if (columns.required && columns.required.length > 0) {
81
+ if (includeRequired && columns.required && columns.required.length > 0) {
51
82
  schema.required = columns.required;
52
83
  }
53
84
  return schema;
54
85
  }
86
+ /**
87
+ * The read schema off the descriptor. `Orm.reloadTableInfo` builds it alongside `Schema`;
88
+ * when it is absent (the model never got a connection, or the descriptor was assembled by
89
+ * hand in a test) we fall back to `Schema` and strip from it what a response never carries
90
+ * anyway - the `@Hidden()` columns. Describing a read with the write contract beats not
91
+ * describing it at all.
92
+ *
93
+ * @param descriptor - the model descriptor
94
+ */
95
+ responseColumns(descriptor) {
96
+ const response = descriptor?.ResponseSchema;
97
+ if (response?.properties) {
98
+ return response;
99
+ }
100
+ const write = descriptor?.Schema;
101
+ if (!write?.properties) {
102
+ return undefined;
103
+ }
104
+ const hidden = new Set(descriptor?.Hidden ?? []);
105
+ if (hidden.size === 0) {
106
+ return write;
107
+ }
108
+ const properties = Object.fromEntries(Object.entries(write.properties).filter(([name]) => !hidden.has(name)));
109
+ return { properties };
110
+ }
55
111
  };
56
112
  ModelSchemaProvider = __decorate([
57
113
  Injectable(SchemaProvider)
@@ -1 +1 @@
1
- {"version":3,"file":"schema-providers.js","sourceRoot":"","sources":["../../src/schema-providers.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAS,EAAE,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAEjD;;;;GAIG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAoB,SAAQ,cAAc;IAAhD;;QACK,WAAM,GAAG,IAAI,GAAG,EAA0B,CAAC;IAyCvD,CAAC;IAvCQ,OAAO;QACZ,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,kBAAkB,CAAC,YAAY,CAAC,EAAE,CAAC;YACxD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAuB,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAEM,SAAS,CAAC,QAAgB;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,SAAS,CAAC;QACnB,CAAC;QAED;;;WAGG;QACH,MAAM,UAAU,GAAI,KAAa,CAAC,kBAAkB,EAAkC,CAAC;QACvF,MAAM,OAAO,GAAG,UAAU,EAAE,MAAM,CAAC;QACnC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;YACpC,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,UAAU,GAA4B,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;QACtE,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE;YACxD,MAAM,MAAM,GAAG,QAAQ,EAAE,WAAW,EAAE,IAAI,CAAC;YAC3C,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO;YACT,CAAC;YACD,MAAM,GAAG,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;YACpD,UAAU,CAAC,YAAY,CAAC;gBACtB,QAAQ,CAAC,IAAI,KAAK,SAAS,IAAI,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAC7G,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAA4B,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;QACvE,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpD,MAAM,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACrC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAA;AA1CY,mBAAmB;IAD/B,UAAU,CAAC,cAAc,CAAC;GACd,mBAAmB,CA0C/B"}
1
+ {"version":3,"file":"schema-providers.js","sourceRoot":"","sources":["../../src/schema-providers.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,24 @@
1
1
  import { IModelDescriptor } from './interfaces.js';
2
2
  /**
3
- * Builds a JSON schema from a model's columns, stored on `descriptor.Schema` at model load.
4
- * `Ignore` columns are excluded and relations are omitted.
3
+ * Which side of the wire a model schema describes. `request` is what a client may SEND
4
+ * ( the model used as `@Body()` ), `response` is what the API hands BACK.
5
5
  */
6
- export declare function buildModelJsonSchema(descriptor: IModelDescriptor): any;
6
+ export type ModelSchemaKind = 'request' | 'response';
7
+ /**
8
+ * Builds a JSON schema from a model's columns, stored on `descriptor.Schema` /
9
+ * `descriptor.ResponseSchema` at model load. `Ignore` columns are excluded and relations
10
+ * are omitted.
11
+ *
12
+ * The two flavours differ in three ways, all of them facts about what a response IS:
13
+ * - `descriptor.Hidden` ( the model's `@Hidden()` properties ) is dropped: `dehydrate()` and
14
+ * `dehydrateWithRelations()` omit those columns unconditionally, so no response can
15
+ * ever carry them - rbac's User hides `Password`,
16
+ * - the driver may override a type it returns differently from what it accepts,
17
+ * - nothing is `required`: a response is partial by construction ( `skipUndefined`
18
+ * drops columns the query did not select ).
19
+ *
20
+ * @param descriptor - the model descriptor to describe
21
+ * @param kind - which contract to build, defaults to the write one
22
+ */
23
+ export declare function buildModelJsonSchema(descriptor: IModelDescriptor, kind?: ModelSchemaKind): any;
7
24
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAqBtE;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,gBAAgB,GAAG,GAAG,CAmBtE"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AA0CtE;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,UAAU,CAAC;AAErD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,gBAAgB,EAAE,IAAI,GAAE,eAA2B,GAAG,GAAG,CAqBzG"}
package/lib/mjs/schema.js CHANGED
@@ -1,5 +1,24 @@
1
1
  import { ColumnType } from './enums.js';
2
- /** SQL column type → JSON-schema shape; unlisted types fall back to `string`. */
2
+ /**
3
+ * SQL column type → JSON-schema shape; unlisted types fall back to `string`.
4
+ *
5
+ * The keys must be the strings a DRIVER puts in `IColumnDescriptor.Type`. Every driver
6
+ * stores the column's own `DATA_TYPE` verbatim ( see orm-mysql / orm-mssql `tableInfo` ),
7
+ * so a `ColumnType` member whose value does not spell the SQL type exactly the way the
8
+ * database reports it will never match, and the column silently falls back to `string`.
9
+ * That is why 'datetime' sits here next to `ColumnType.DATE_TIME` ( = 'dateTime' ), which
10
+ * neither MySQL nor MSSQL ever emits.
11
+ *
12
+ * Known remaining mismatches with mysql2's real output, left alone on purpose - correcting
13
+ * them changes an already-published schema for columns nobody has complained about:
14
+ * - `bit` arrives as a Buffer, not a number,
15
+ * - `set` arrives as a comma-separated string unless SetValueConverter is attached,
16
+ * - `blob` / `binary` / `varbinary` arrive as Buffers and fall through to `string`.
17
+ *
18
+ * The values here are what a client may SEND. Where the driver hands something else BACK -
19
+ * mysql2's stringified DECIMAL - that driver says so through `OrmDriver.ResponseSchemaTypes`
20
+ * rather than bending this shared map, which every driver reads.
21
+ */
3
22
  const SQL_TYPE_TO_SCHEMA = {
4
23
  [ColumnType.TINY_INTEGER]: { type: 'integer' },
5
24
  [ColumnType.SMALL_INTEGER]: { type: 'integer' },
@@ -13,39 +32,70 @@ const SQL_TYPE_TO_SCHEMA = {
13
32
  [ColumnType.BOOLEAN]: { type: 'boolean' },
14
33
  [ColumnType.DATE]: { type: 'string', format: 'date' },
15
34
  [ColumnType.DATE_TIME]: { type: 'string', format: 'date-time' },
35
+ // MySQL and MSSQL both report DATETIME as 'datetime'; ColumnType.DATE_TIME above never matches.
36
+ datetime: { type: 'string', format: 'date-time' },
16
37
  [ColumnType.TIMESTAMP]: { type: 'string', format: 'date-time' },
17
38
  [ColumnType.JSON]: { type: 'object' },
18
39
  [ColumnType.SET]: { type: 'array', items: { type: 'string' } },
19
40
  };
20
41
  /**
21
- * Builds a JSON schema from a model's columns, stored on `descriptor.Schema` at model load.
22
- * `Ignore` columns are excluded and relations are omitted.
42
+ * Builds a JSON schema from a model's columns, stored on `descriptor.Schema` /
43
+ * `descriptor.ResponseSchema` at model load. `Ignore` columns are excluded and relations
44
+ * are omitted.
45
+ *
46
+ * The two flavours differ in three ways, all of them facts about what a response IS:
47
+ * - `descriptor.Hidden` ( the model's `@Hidden()` properties ) is dropped: `dehydrate()` and
48
+ * `dehydrateWithRelations()` omit those columns unconditionally, so no response can
49
+ * ever carry them - rbac's User hides `Password`,
50
+ * - the driver may override a type it returns differently from what it accepts,
51
+ * - nothing is `required`: a response is partial by construction ( `skipUndefined`
52
+ * drops columns the query did not select ).
53
+ *
54
+ * @param descriptor - the model descriptor to describe
55
+ * @param kind - which contract to build, defaults to the write one
23
56
  */
24
- export function buildModelJsonSchema(descriptor) {
57
+ export function buildModelJsonSchema(descriptor, kind = 'request') {
25
58
  const properties = {};
26
59
  const required = [];
60
+ const hidden = kind === 'response' ? new Set(descriptor.Hidden ?? []) : new Set();
61
+ const overrides = kind === 'response' ? driverResponseTypes(descriptor) : {};
27
62
  for (const col of descriptor.Columns ?? []) {
28
- if (!col || col.Ignore || !col.Name) {
63
+ if (!col || col.Ignore || !col.Name || hidden.has(col.Name)) {
29
64
  continue;
30
65
  }
31
- properties[col.Name] = columnToSchema(col);
66
+ properties[col.Name] = columnToSchema(col, overrides);
32
67
  if (!col.Nullable && !col.AutoIncrement) {
33
68
  required.push(col.Name);
34
69
  }
35
70
  }
36
71
  const schema = { type: 'object', properties };
37
- if (required.length > 0) {
72
+ if (kind === 'request' && required.length > 0) {
38
73
  schema.required = required;
39
74
  }
40
75
  return schema;
41
76
  }
77
+ /**
78
+ * Per-SQL-type response overrides declared by the driver this model is bound to, or an
79
+ * empty map for a model with no connection yet ( then the shared defaults stand ).
80
+ *
81
+ * Read structurally rather than through the OrmDriver type: this module is imported by
82
+ * the descriptor building path and must not pull the driver module in with it.
83
+ *
84
+ * @param descriptor - the model descriptor whose driver is asked
85
+ */
86
+ function driverResponseTypes(descriptor) {
87
+ return descriptor.Driver?.ResponseSchemaTypes ?? {};
88
+ }
42
89
  /**
43
90
  * Maps a column descriptor to a JSON-schema property based on its SQL type.
44
91
  * Adds `maxLength`, `description` and `nullable` when the column has them.
92
+ *
93
+ * @param col - column to describe
94
+ * @param overrides - per-type shapes that win over the shared map ( response flavour only )
45
95
  */
46
- function columnToSchema(col) {
96
+ function columnToSchema(col, overrides = {}) {
47
97
  const converter = col.Converter?.constructor?.name;
48
- const schema = { ...(SQL_TYPE_TO_SCHEMA[col.Type] ?? { type: 'string' }) };
98
+ const schema = { ...(overrides[col.Type] ?? SQL_TYPE_TO_SCHEMA[col.Type] ?? { type: 'string' }) };
49
99
  if (converter === 'BooleanValueConverter') {
50
100
  schema.type = 'boolean';
51
101
  delete schema.format;
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/schema.ts"],"names":[],"mappings":"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"}