@spinajs/orm-http 2.0.480 → 2.0.482

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
@@ -1,11 +1,100 @@
1
- # `orm-http`
1
+ # `@spinajs/orm-http`
2
2
 
3
- > TODO: description
3
+ Glue between [`@spinajs/orm`](../orm) and `@spinajs/http`: route arguments that load or build
4
+ models straight from a request, a declarative filtering layer, and DTO fields that resolve to
5
+ database entities.
6
+
7
+ It does **not** generate controllers or routes. You write ordinary `@spinajs/http` controllers;
8
+ this package removes the boilerplate inside them.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install @spinajs/orm-http
14
+ ```
15
+
16
+ Importing it is enough — its bootstrapper registers itself with DI and runs when the ORM
17
+ resolves.
4
18
 
5
19
  ## Usage
6
20
 
21
+ ```ts
22
+ import { BaseController, BasePath, Get, Post, Ok } from '@spinajs/http';
23
+ import { Connection, Model, ModelBase, Primary } from '@spinajs/orm';
24
+ import { FromModel, AsModel, Filter, Filterable, IFilterRequest } from '@spinajs/orm-http';
25
+
26
+ @Connection('default')
27
+ @Model('articles')
28
+ export class Article extends ModelBase<Article> {
29
+ @Primary()
30
+ public Id: number;
31
+
32
+ @Filterable(['eq', 'like'])
33
+ public Title: string;
34
+ }
35
+
36
+ @BasePath('articles')
37
+ export class ArticleController extends BaseController {
38
+ /** GET /articles/:article — loaded by primary key, 404 when missing. */
39
+ @Get(':article')
40
+ public one(@FromModel() article: Article) {
41
+ return new Ok(article.dehydrate());
42
+ }
43
+
44
+ /** GET /articles?filter={"op":"and","filters":[{"Column":"Title","Operator":"like","Value":"x"}]} */
45
+ @Get()
46
+ public async list(@Filter(Article) filter: IFilterRequest) {
47
+ const rows = await Article.select().filter(filter.filters, filter.op);
48
+ return new Ok(rows.map((r) => r.dehydrate()));
49
+ }
50
+
51
+ /** POST /articles — hydrated from the body, not fetched or saved. */
52
+ @Post()
53
+ public async create(@AsModel() article: Article) {
54
+ await article.insert();
55
+ return new Ok(article.dehydrate());
56
+ }
57
+ }
7
58
  ```
8
- const ormHttp = require('orm-http');
9
59
 
10
- // TODO: DEMONSTRATE API
60
+ ## What it adds
61
+
62
+ | Feature | Entry point |
63
+ | --- | --- |
64
+ | Load a model from a route / query / body / header parameter | `@FromModel()` |
65
+ | Build an unsaved model from the request body | `@AsModel()` |
66
+ | Declarative, schema-validated filtering | `@Filterable()` + `@Filter()` |
67
+ | DTO fields that resolve to entities | `@Relation()` |
68
+ | Pagination and ordering DTOs | `PaginationDTO`, `OrderDTO` |
69
+ | `404` for `OrmNotFoundException` | `OrmNotFound` |
70
+
71
+ It also installs `filter()`, `filterColumns()` and `filterSchema()` onto every model class.
72
+
73
+ ## Documentation
74
+
75
+ Full documentation lives in **[docs/](docs/)**.
76
+
77
+ | | Page |
78
+ | --- | --- |
79
+ | 01 | [Overview](docs/01-overview.md) |
80
+ | 02 | [Route arguments](docs/02-route-args.md) |
81
+ | 03 | [Filtering](docs/03-filtering.md) |
82
+ | 04 | [DTO relations](docs/04-dto-relations.md) |
83
+ | 05 | [Pagination and ordering](docs/05-pagination-and-order.md) |
84
+ | 06 | [Repository middleware](docs/06-repository-middleware.md) |
85
+
86
+ ## Known issues
87
+
88
+ - `RepositoryMiddleware` is defined in `src/middleware.ts` but re-exported from neither
89
+ `src/index.ts` nor the `exports` map, so it is currently unreachable. Use `QueryMiddleware`
90
+ from the core instead — see [docs/06](docs/06-repository-middleware.md).
91
+ - `npm test` fails during bootstrap with `No __file_provider_instance__ registered`: the test
92
+ harness does not register `@spinajs/fs`. That is a test-configuration gap, not a defect in the
93
+ package.
94
+
95
+ ## Development
96
+
97
+ ```bash
98
+ npm run build
99
+ npm run docs:check # from the repo root
11
100
  ```
@@ -0,0 +1,36 @@
1
+ import 'reflect-metadata';
2
+ import { ModelBase } from '@spinajs/orm';
3
+ import { ArgHydrator, IRouteParameter } from '@spinajs/http';
4
+ /**
5
+ * Global symbol (shared via the global registry) under which a DTO's relation
6
+ * descriptors are stored on its prototype. Global so `http-swagger` can read it
7
+ * without importing this package.
8
+ */
9
+ export declare const RELATION_SYMBOL: unique symbol;
10
+ export interface IDtoRelationDescriptor {
11
+ field: string;
12
+ target: () => typeof ModelBase;
13
+ by?: string;
14
+ }
15
+ export interface IDtoRelations {
16
+ Relations: Map<string, IDtoRelationDescriptor>;
17
+ }
18
+ export interface IRelationOptions {
19
+ /** Natural-key column on the target model to look the entity up by. Defaults to the target's primary key. */
20
+ by?: string;
21
+ }
22
+ /**
23
+ * Marks a DTO field as a reference to a DB entity. On an incoming request the
24
+ * field value is looked up on `target` by `by` (or the target's primary key),
25
+ * 404 if missing, and the field is replaced with the resolved model instance.
26
+ */
27
+ export declare function Relation(target: () => typeof ModelBase, options?: IRelationOptions): PropertyDecorator;
28
+ /**
29
+ * Resolves a DTO's @Relation fields against the DB. Enforces that any DTO with a
30
+ * @Relation declares a @Schema, resolves each present relation field to a model
31
+ * instance (404 if not found), and leaves absent/null fields untouched.
32
+ */
33
+ export declare class RelationResolverHydrator extends ArgHydrator {
34
+ hydrate(input: any, parameter: IRouteParameter): Promise<any>;
35
+ }
36
+ //# sourceMappingURL=dto-relation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dto-relation.d.ts","sourceRoot":"","sources":["../../src/dto-relation.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAAE,SAAS,EAAwB,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAI7D;;;;GAIG;AACH,eAAO,MAAM,eAAe,eAAmC,CAAC;AAEhE,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,OAAO,SAAS,CAAC;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,gBAAgB;IAC/B,6GAA6G;IAC7G,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,SAAS,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,CAatG;AAcD;;;;GAIG;AACH,qBAAa,wBAAyB,SAAQ,WAAW;IAC1C,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC;CA4C3E"}
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RelationResolverHydrator = exports.RELATION_SYMBOL = void 0;
4
+ exports.Relation = Relation;
5
+ require("reflect-metadata");
6
+ const di_1 = require("@spinajs/di");
7
+ const orm_1 = require("@spinajs/orm");
8
+ const http_1 = require("@spinajs/http");
9
+ const validation_1 = require("@spinajs/validation");
10
+ const exceptions_1 = require("@spinajs/exceptions");
11
+ /**
12
+ * Global symbol (shared via the global registry) under which a DTO's relation
13
+ * descriptors are stored on its prototype. Global so `http-swagger` can read it
14
+ * without importing this package.
15
+ */
16
+ exports.RELATION_SYMBOL = Symbol.for('orm-http:relations');
17
+ /**
18
+ * Marks a DTO field as a reference to a DB entity. On an incoming request the
19
+ * field value is looked up on `target` by `by` (or the target's primary key),
20
+ * 404 if missing, and the field is replaced with the resolved model instance.
21
+ */
22
+ function Relation(target, options) {
23
+ return (proto, propertyKey) => {
24
+ const field = String(propertyKey);
25
+ const descriptor = (0, di_1.getInheritedDescriptor)(proto, exports.RELATION_SYMBOL, () => ({ Relations: new Map() }));
26
+ descriptor.Relations.set(field, { field, target, by: options?.by });
27
+ // Register the resolver as the DTO's arg hydrator so a plain @Body() picks
28
+ // it up through the existing hydrator hook — unless one is already set.
29
+ const ctor = proto.constructor;
30
+ if (!Reflect.getOwnMetadata('custom:arg_hydrator', ctor)) {
31
+ Reflect.defineMetadata('custom:arg_hydrator', { hydrator: RelationResolverHydrator }, ctor);
32
+ }
33
+ };
34
+ }
35
+ const schemaChecked = new WeakSet();
36
+ /** Enforces the rule: a DTO using @Relation must declare a @Schema. */
37
+ function assertDtoHasSchema(ctor) {
38
+ if (schemaChecked.has(ctor))
39
+ return;
40
+ const schema = Reflect.getMetadata(validation_1.SCHEMA_SYMBOL, ctor.prototype) ?? Reflect.getMetadata(validation_1.SCHEMA_SYMBOL, ctor);
41
+ if (!schema) {
42
+ throw new exceptions_1.InvalidOperation(`DTO ${ctor.name} uses @Relation but has no @Schema. All DTOs with @Relation must declare a @Schema.`);
43
+ }
44
+ schemaChecked.add(ctor);
45
+ }
46
+ /**
47
+ * Resolves a DTO's @Relation fields against the DB. Enforces that any DTO with a
48
+ * @Relation declares a @Schema, resolves each present relation field to a model
49
+ * instance (404 if not found), and leaves absent/null fields untouched.
50
+ */
51
+ class RelationResolverHydrator extends http_1.ArgHydrator {
52
+ async hydrate(input, parameter) {
53
+ const ctor = parameter.RuntimeType;
54
+ const dto = new ctor(input);
55
+ const relDesc = Reflect.getMetadata(exports.RELATION_SYMBOL, ctor.prototype);
56
+ if (!relDesc || relDesc.Relations.size === 0) {
57
+ return dto;
58
+ }
59
+ // Enforce "every @Relation DTO must have a @Schema" once per class.
60
+ assertDtoHasSchema(ctor);
61
+ await Promise.all([...relDesc.Relations.values()].map(async (rel) => {
62
+ const value = dto[rel.field];
63
+ // Absent / null: optional fields are skipped; required fields were
64
+ // already rejected upstream by @Schema validation.
65
+ if (value === undefined || value === null) {
66
+ return;
67
+ }
68
+ const model = rel.target();
69
+ const descriptor = model.getModelDescriptor();
70
+ // `PrimaryKey` is `string[]` since composite keys landed. A DTO relation field carries
71
+ // ONE value, so it cannot address a composite key — fail with a clear message instead
72
+ // of building a nonsense WHERE. Same contract as @FromModel route params, which ask for
73
+ // `queryField`; here the escape hatch is `by` on the relation decorator.
74
+ if (!rel.by && (descriptor.PrimaryKey?.length ?? 0) !== 1) {
75
+ throw new exceptions_1.InvalidOperation(`model ${descriptor.Name} has a composite primary key (${(descriptor.PrimaryKey ?? []).join(', ')}); set \`by\` on the relation to select a single lookup column`);
76
+ }
77
+ const by = rel.by ?? descriptor.PrimaryKey[0];
78
+ const resolved = await model
79
+ .where({ [by]: value })
80
+ .firstOrThrow(new orm_1.OrmNotFoundException(`${model.name} referenced by '${rel.field}' not found`));
81
+ dto[rel.field] = resolved;
82
+ }));
83
+ return dto;
84
+ }
85
+ }
86
+ exports.RelationResolverHydrator = RelationResolverHydrator;
87
+ //# sourceMappingURL=dto-relation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dto-relation.js","sourceRoot":"","sources":["../../src/dto-relation.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"dto.d.ts","sourceRoot":"","sources":["../../src/dto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,qBASa,aAAa;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;gBAER,IAAI,EAAE,OAAO,CAAC,aAAa,CAAC;CAGzC;AAED,qBAQa,QAAQ;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC;CAGpC"}
1
+ {"version":3,"file":"dto.d.ts","sourceRoot":"","sources":["../../src/dto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,qBAUa,aAAa;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;gBAER,IAAI,EAAE,OAAO,CAAC,aAAa,CAAC;CAGzC;AAED,qBAQa,QAAQ;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC;CAGpC"}
package/lib/cjs/dto.js CHANGED
@@ -21,10 +21,11 @@ exports.PaginationDTO = PaginationDTO = __decorate([
21
21
  (0, validation_1.Schema)({
22
22
  type: 'object',
23
23
  $id: 'arrow.common.PaginationDTO',
24
+ // Must match the class fields below — otherwise `page` is never validated
25
+ // and offset/take validate phantom properties that the class never declares.
24
26
  properties: {
25
27
  limit: { type: 'number', minimum: 0 },
26
- offset: { type: 'number', minimum: 0 },
27
- take: { type: 'number', minimum: 0 },
28
+ page: { type: 'number', minimum: 0 },
28
29
  },
29
30
  }),
30
31
  __metadata("design:paramtypes", [Object])
@@ -1 +1 @@
1
- {"version":3,"file":"dto.js","sourceRoot":"","sources":["../../src/dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,oDAA6C;AAWtC,IAAM,aAAa,GAAnB,MAAM,aAAa;IAIxB,YAAY,IAA4B;QACtC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF,CAAA;AAPY,sCAAa;wBAAb,aAAa;IATzB,IAAA,mBAAM,EAAC;QACN,IAAI,EAAE,QAAQ;QACd,GAAG,EAAE,4BAA4B;QACjC,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;YACrC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;YACtC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;SACrC;KACF,CAAC;;GACW,aAAa,CAOzB;AAUM,IAAM,QAAQ,GAAd,MAAM,QAAQ;IAInB,YAAY,IAAuB;QACjC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF,CAAA;AAPY,4BAAQ;mBAAR,QAAQ;IARpB,IAAA,mBAAM,EAAC;QACN,IAAI,EAAE,QAAQ;QACd,GAAG,EAAE,uBAAuB;QAC5B,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE;YAC/D,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;SAC3B;KACF,CAAC;;GACW,QAAQ,CAOpB"}
1
+ {"version":3,"file":"dto.js","sourceRoot":"","sources":["../../src/dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,oDAA6C;AAYtC,IAAM,aAAa,GAAnB,MAAM,aAAa;IAIxB,YAAY,IAA4B;QACtC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF,CAAA;AAPY,sCAAa;wBAAb,aAAa;IAVzB,IAAA,mBAAM,EAAC;QACN,IAAI,EAAE,QAAQ;QACd,GAAG,EAAE,4BAA4B;QACjC,0EAA0E;QAC1E,6EAA6E;QAC7E,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;YACrC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;SACrC;KACF,CAAC;;GACW,aAAa,CAOzB;AAUM,IAAM,QAAQ,GAAd,MAAM,QAAQ;IAInB,YAAY,IAAuB;QACjC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF,CAAA;AAPY,4BAAQ;mBAAR,QAAQ;IARpB,IAAA,mBAAM,EAAC;QACN,IAAI,EAAE,QAAQ;QACd,GAAG,EAAE,uBAAuB;QAC5B,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE;YAC/D,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;SAC3B;KACF,CAAC;;GACW,QAAQ,CAOpB"}
@@ -9,6 +9,7 @@ export * from './extension.js';
9
9
  export * from './route-arg.js';
10
10
  export * from './builders.js';
11
11
  export * from './dto.js';
12
+ export * from './dto-relation.js';
12
13
  export * from './response-methods/OrmNotFound.js';
13
14
  import * as express from 'express';
14
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAgG,MAAM,cAAc,CAAC;AAC5I,OAAO,EAAE,eAAe,EAAE,UAAU,EAAoB,aAAa,EAAE,WAAW,EAAE,OAAO,IAAI,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAClJ,OAAO,EAAE,UAAU,EAAqC,YAAY,EAAM,MAAM,aAAa,CAAC;AAE9F,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,mCAAmC,CAAC;AAClD,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAEnC;;;;GAIG;AACH,qBACa,SAAU,SAAQ,SAAS;IACtC,IAAW,aAAa,IAAI,MAAM,CAEjC;IAEY,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM;;;;CAU1I;AAED,qBACa,WAAY,SAAQ,SAAS;IAExC,SAAS,CAAC,SAAS,EAAE,UAAU,CAAC;IAGhC,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAEb,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAE9B,IAAW,aAAa,IAAI,MAAM,CAEjC;IAEY,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ;;;;IAWjG,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,eAAe,CAAC,gBAAgB,CAAC,OAAO,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ;IAuBjG,SAAS,CAAC,+BAA+B,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,CAAC,gBAAgB,CAAC,OAAO,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ;CA8D5J;AAED,qBAAa,eAAgB,SAAQ,WAAW;IACjC,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC;CAS3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,yGAE3D;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,OAAO,SAAS,EAAE,OAAO,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,yGAElF;AAED,qBACa,mBAAoB,SAAQ,YAAY;IACtC,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAgBxC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAgG,MAAM,cAAc,CAAC;AAC5I,OAAO,EAAE,eAAe,EAAE,UAAU,EAAoB,aAAa,EAAE,WAAW,EAAE,OAAO,IAAI,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAClJ,OAAO,EAAE,UAAU,EAAqC,YAAY,EAAM,MAAM,aAAa,CAAC;AAE9F,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,cAAc,mCAAmC,CAAC;AAClD,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAEnC;;;;GAIG;AACH,qBACa,SAAU,SAAQ,SAAS;IACtC,IAAW,aAAa,IAAI,MAAM,CAEjC;IAEY,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM;;;;CAU1I;AAED,qBACa,WAAY,SAAQ,SAAS;IAExC,SAAS,CAAC,SAAS,EAAE,UAAU,CAAC;IAGhC,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAEb,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAE9B,IAAW,aAAa,IAAI,MAAM,CAEjC;IAEY,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ;;;;IAWjG,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,eAAe,CAAC,gBAAgB,CAAC,OAAO,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ;IAuBjG,SAAS,CAAC,+BAA+B,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,CAAC,gBAAgB,CAAC,OAAO,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ;CAqE5J;AAED,qBAAa,eAAgB,SAAQ,WAAW;IACjC,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC;CAS3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,yGAE3D;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,OAAO,SAAS,EAAE,OAAO,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,yGAElF;AAED,qBACa,mBAAoB,SAAQ,YAAY;IACtC,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAgBxC"}
package/lib/cjs/index.js CHANGED
@@ -38,6 +38,7 @@ __exportStar(require("./extension.js"), exports);
38
38
  __exportStar(require("./route-arg.js"), exports);
39
39
  __exportStar(require("./builders.js"), exports);
40
40
  __exportStar(require("./dto.js"), exports);
41
+ __exportStar(require("./dto-relation.js"), exports);
41
42
  __exportStar(require("./response-methods/OrmNotFound.js"), exports);
42
43
  /**
43
44
  * Route arg to hydrate model from request body
@@ -100,7 +101,12 @@ let FromDbModel = class FromDbModel extends http_1.RouteArgs {
100
101
  const pkValue = this._extractValue(param, req);
101
102
  const query = param.RuntimeType['query']();
102
103
  const descriptor = (0, orm_1.extractModelDescriptor)(param.RuntimeType);
103
- const queryField = param?.Options?.queryField ?? descriptor.PrimaryKey;
104
+ // A route parameter carries ONE value, so it cannot address a composite key. Fail with a
105
+ // 400 rather than silently filtering on the first key column and returning the wrong row.
106
+ if (!param?.Options?.queryField && (descriptor.PrimaryKey?.length ?? 0) !== 1) {
107
+ throw new exceptions_1.BadRequest(`model ${descriptor.Name} has a composite primary key (${(descriptor.PrimaryKey ?? []).join(', ')}); pass queryField to select a single lookup column`);
108
+ }
109
+ const queryField = param?.Options?.queryField ?? descriptor.PrimaryKey[0];
104
110
  query.setTable(descriptor.TableName, `$${descriptor.TableName}`);
105
111
  query.select('*');
106
112
  query.where(queryField, pkValue);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"route-arg.d.ts","sourceRoot":"","sources":["../../src/route-arg.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAiC,WAAW,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAA8B,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE5E,qBAEa,mBAAoB,SAAQ,SAAS;IAChD,SAAS,CAAC,SAAS,EAAE,UAAU,CAAC;gBAEpB,CAAC,EAAE,UAAU;IAMnB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAE9B,IAAW,aAAa,IAAI,aAAa,GAAG,MAAM,CAEjD;IAEY,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,CAAC,WAAW,CAAC,SAAS,CAAC,GAAG,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM;;;;CAgDpM"}
1
+ {"version":3,"file":"route-arg.d.ts","sourceRoot":"","sources":["../../src/route-arg.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAiC,WAAW,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAA8B,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE5E,qBAEa,mBAAoB,SAAQ,SAAS;IAChD,SAAS,CAAC,SAAS,EAAE,UAAU,CAAC;gBAEpB,CAAC,EAAE,UAAU;IAMnB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAE9B,IAAW,aAAa,IAAI,aAAa,GAAG,MAAM,CAEjD;IAEY,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,CAAC,WAAW,CAAC,SAAS,CAAC,GAAG,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM;;;;CA8DpM"}
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.FilterModelRouteArg = void 0;
13
13
  const di_1 = require("@spinajs/di");
14
14
  const http_1 = require("@spinajs/http");
15
+ const exceptions_1 = require("@spinajs/exceptions");
15
16
  const interfaces_js_1 = require("./interfaces.js");
16
17
  let FilterModelRouteArg = class FilterModelRouteArg extends http_1.RouteArgs {
17
18
  constructor(c) {
@@ -52,10 +53,13 @@ let FilterModelRouteArg = class FilterModelRouteArg extends http_1.RouteArgs {
52
53
  anyOf: param.Options.map((x) => {
53
54
  return {
54
55
  type: 'object',
55
- required: ['Column', 'Value', 'Operator'],
56
+ // Value is intentionally NOT required: valueless operators
57
+ // (isnull/notnull/exists/n-exists) carry no value. Mirror the
58
+ // model-derived schema in model.ts (filterSchema()).
59
+ required: ['Column', 'Operator'],
56
60
  properties: {
57
61
  Column: { const: x.column },
58
- Value: { type: ['string', 'integer', 'array'] },
62
+ Value: { type: ['string', 'integer', 'array', 'boolean'] },
59
63
  Operator: { type: 'string', enum: x.operators },
60
64
  },
61
65
  };
@@ -65,7 +69,18 @@ let FilterModelRouteArg = class FilterModelRouteArg extends http_1.RouteArgs {
65
69
  },
66
70
  };
67
71
  }
68
- let result = await this.tryHydrateParam(typeof filter === 'string' ? JSON.parse(filter) : filter, rParam, route);
72
+ let parsed = filter;
73
+ if (typeof filter === 'string') {
74
+ try {
75
+ parsed = JSON.parse(filter);
76
+ }
77
+ catch (err) {
78
+ // A malformed filter string is a client error (400), not an
79
+ // unhandled 500 out of the route-arg extractor.
80
+ throw new exceptions_1.InvalidArgument(`Filter parameter '${param.Name}' is invalid JSON. Reason: ${err.message}`, err);
81
+ }
82
+ }
83
+ let result = await this.tryHydrateParam(parsed, rParam, route);
69
84
  return { CallData: callData, Args: result };
70
85
  }
71
86
  };
@@ -1 +1 @@
1
- {"version":3,"file":"route-arg.js","sourceRoot":"","sources":["../../src/route-arg.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oCAAqF;AACrF,wCAA8F;AAG9F,mDAA4E;AAIrE,IAAM,mBAAmB,GAAzB,MAAM,mBAAoB,SAAQ,gBAAS;IAGhD,YAAY,CAAa;QACvB,KAAK,EAAE,CAAC;QAER,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,OAAO,KAAoB,CAAC;IAElC,IAAW,aAAa;QACtB,OAAO,qBAAqB,CAAC;IAC/B,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,QAAoB,EAAE,KAAgB,EAAE,KAAyE,EAAE,GAAoB,EAAE,IAAsB,EAAE,KAAa;QACjM,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAE/D,wDAAwD;QACxD,iEAAiE;QACjE,MAAM,MAAM,GAAG;YACb,GAAG,KAAK;YACR,MAAM,EAAE,EAAE;SACX,CAAC;QAEF,yBAAyB;QACzB,0CAA0C;QAC1C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAK,KAAK,CAAC,OAAe,CAAC,YAAY,EAAE,CAAC;YACzE,uBAAuB;YACvB,MAAM,CAAC,MAAM,GAAI,KAAK,CAAC,OAAe,CAAC,YAAY,EAAE,CAAC;QACxD,CAAC;aAAM,CAAC;YACN,+BAA+B;YAC/B,MAAM,CAAC,MAAM,GAAG;gBACd,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,EAAE,EAAE;wBACF,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,CAAC,0CAA0B,CAAC,GAAG,EAAE,0CAA0B,CAAC,EAAE,CAAC;qBACtE;oBACD,OAAO,EAAE;wBACP,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE;4BACL,IAAI,EAAE,QAAQ;4BACd,KAAK,EAAG,KAAK,CAAC,OAAoC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gCAC3D,OAAO;oCACL,IAAI,EAAE,QAAQ;oCACd,QAAQ,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC;oCACzC,UAAU,EAAE;wCACV,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;wCAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE;wCAC/C,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,SAAS,EAAE;qCAChD;iCACF,CAAC;4BACJ,CAAC,CAAC;yBACH;qBACF;iBACF;aACF,CAAC;QACJ,CAAC;QAED,IAAI,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QACjH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC9C,CAAC;CACF,CAAA;AA/DY,kDAAmB;8BAAnB,mBAAmB;IAF/B,IAAA,eAAU,GAAE;IACZ,IAAA,WAAM,EAAC,cAAS,CAAC;;GACL,mBAAmB,CA+D/B"}
1
+ {"version":3,"file":"route-arg.js","sourceRoot":"","sources":["../../src/route-arg.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import 'reflect-metadata';
2
+ import { ModelBase } from '@spinajs/orm';
3
+ import { ArgHydrator, IRouteParameter } from '@spinajs/http';
4
+ /**
5
+ * Global symbol (shared via the global registry) under which a DTO's relation
6
+ * descriptors are stored on its prototype. Global so `http-swagger` can read it
7
+ * without importing this package.
8
+ */
9
+ export declare const RELATION_SYMBOL: unique symbol;
10
+ export interface IDtoRelationDescriptor {
11
+ field: string;
12
+ target: () => typeof ModelBase;
13
+ by?: string;
14
+ }
15
+ export interface IDtoRelations {
16
+ Relations: Map<string, IDtoRelationDescriptor>;
17
+ }
18
+ export interface IRelationOptions {
19
+ /** Natural-key column on the target model to look the entity up by. Defaults to the target's primary key. */
20
+ by?: string;
21
+ }
22
+ /**
23
+ * Marks a DTO field as a reference to a DB entity. On an incoming request the
24
+ * field value is looked up on `target` by `by` (or the target's primary key),
25
+ * 404 if missing, and the field is replaced with the resolved model instance.
26
+ */
27
+ export declare function Relation(target: () => typeof ModelBase, options?: IRelationOptions): PropertyDecorator;
28
+ /**
29
+ * Resolves a DTO's @Relation fields against the DB. Enforces that any DTO with a
30
+ * @Relation declares a @Schema, resolves each present relation field to a model
31
+ * instance (404 if not found), and leaves absent/null fields untouched.
32
+ */
33
+ export declare class RelationResolverHydrator extends ArgHydrator {
34
+ hydrate(input: any, parameter: IRouteParameter): Promise<any>;
35
+ }
36
+ //# sourceMappingURL=dto-relation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dto-relation.d.ts","sourceRoot":"","sources":["../../src/dto-relation.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAAE,SAAS,EAAwB,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAI7D;;;;GAIG;AACH,eAAO,MAAM,eAAe,eAAmC,CAAC;AAEhE,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,OAAO,SAAS,CAAC;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,gBAAgB;IAC/B,6GAA6G;IAC7G,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,SAAS,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,CAatG;AAcD;;;;GAIG;AACH,qBAAa,wBAAyB,SAAQ,WAAW;IAC1C,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC;CA4C3E"}
@@ -0,0 +1,82 @@
1
+ import 'reflect-metadata';
2
+ import { getInheritedDescriptor } from '@spinajs/di';
3
+ import { OrmNotFoundException } from '@spinajs/orm';
4
+ import { ArgHydrator } from '@spinajs/http';
5
+ import { SCHEMA_SYMBOL } from '@spinajs/validation';
6
+ import { InvalidOperation } from '@spinajs/exceptions';
7
+ /**
8
+ * Global symbol (shared via the global registry) under which a DTO's relation
9
+ * descriptors are stored on its prototype. Global so `http-swagger` can read it
10
+ * without importing this package.
11
+ */
12
+ export const RELATION_SYMBOL = Symbol.for('orm-http:relations');
13
+ /**
14
+ * Marks a DTO field as a reference to a DB entity. On an incoming request the
15
+ * field value is looked up on `target` by `by` (or the target's primary key),
16
+ * 404 if missing, and the field is replaced with the resolved model instance.
17
+ */
18
+ export function Relation(target, options) {
19
+ return (proto, propertyKey) => {
20
+ const field = String(propertyKey);
21
+ const descriptor = getInheritedDescriptor(proto, RELATION_SYMBOL, () => ({ Relations: new Map() }));
22
+ descriptor.Relations.set(field, { field, target, by: options?.by });
23
+ // Register the resolver as the DTO's arg hydrator so a plain @Body() picks
24
+ // it up through the existing hydrator hook — unless one is already set.
25
+ const ctor = proto.constructor;
26
+ if (!Reflect.getOwnMetadata('custom:arg_hydrator', ctor)) {
27
+ Reflect.defineMetadata('custom:arg_hydrator', { hydrator: RelationResolverHydrator }, ctor);
28
+ }
29
+ };
30
+ }
31
+ const schemaChecked = new WeakSet();
32
+ /** Enforces the rule: a DTO using @Relation must declare a @Schema. */
33
+ function assertDtoHasSchema(ctor) {
34
+ if (schemaChecked.has(ctor))
35
+ return;
36
+ const schema = Reflect.getMetadata(SCHEMA_SYMBOL, ctor.prototype) ?? Reflect.getMetadata(SCHEMA_SYMBOL, ctor);
37
+ if (!schema) {
38
+ throw new InvalidOperation(`DTO ${ctor.name} uses @Relation but has no @Schema. All DTOs with @Relation must declare a @Schema.`);
39
+ }
40
+ schemaChecked.add(ctor);
41
+ }
42
+ /**
43
+ * Resolves a DTO's @Relation fields against the DB. Enforces that any DTO with a
44
+ * @Relation declares a @Schema, resolves each present relation field to a model
45
+ * instance (404 if not found), and leaves absent/null fields untouched.
46
+ */
47
+ export class RelationResolverHydrator extends ArgHydrator {
48
+ async hydrate(input, parameter) {
49
+ const ctor = parameter.RuntimeType;
50
+ const dto = new ctor(input);
51
+ const relDesc = Reflect.getMetadata(RELATION_SYMBOL, ctor.prototype);
52
+ if (!relDesc || relDesc.Relations.size === 0) {
53
+ return dto;
54
+ }
55
+ // Enforce "every @Relation DTO must have a @Schema" once per class.
56
+ assertDtoHasSchema(ctor);
57
+ await Promise.all([...relDesc.Relations.values()].map(async (rel) => {
58
+ const value = dto[rel.field];
59
+ // Absent / null: optional fields are skipped; required fields were
60
+ // already rejected upstream by @Schema validation.
61
+ if (value === undefined || value === null) {
62
+ return;
63
+ }
64
+ const model = rel.target();
65
+ const descriptor = model.getModelDescriptor();
66
+ // `PrimaryKey` is `string[]` since composite keys landed. A DTO relation field carries
67
+ // ONE value, so it cannot address a composite key — fail with a clear message instead
68
+ // of building a nonsense WHERE. Same contract as @FromModel route params, which ask for
69
+ // `queryField`; here the escape hatch is `by` on the relation decorator.
70
+ if (!rel.by && (descriptor.PrimaryKey?.length ?? 0) !== 1) {
71
+ throw new InvalidOperation(`model ${descriptor.Name} has a composite primary key (${(descriptor.PrimaryKey ?? []).join(', ')}); set \`by\` on the relation to select a single lookup column`);
72
+ }
73
+ const by = rel.by ?? descriptor.PrimaryKey[0];
74
+ const resolved = await model
75
+ .where({ [by]: value })
76
+ .firstOrThrow(new OrmNotFoundException(`${model.name} referenced by '${rel.field}' not found`));
77
+ dto[rel.field] = resolved;
78
+ }));
79
+ return dto;
80
+ }
81
+ }
82
+ //# sourceMappingURL=dto-relation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dto-relation.js","sourceRoot":"","sources":["../../src/dto-relation.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"dto.d.ts","sourceRoot":"","sources":["../../src/dto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,qBASa,aAAa;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;gBAER,IAAI,EAAE,OAAO,CAAC,aAAa,CAAC;CAGzC;AAED,qBAQa,QAAQ;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC;CAGpC"}
1
+ {"version":3,"file":"dto.d.ts","sourceRoot":"","sources":["../../src/dto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,qBAUa,aAAa;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;gBAER,IAAI,EAAE,OAAO,CAAC,aAAa,CAAC;CAGzC;AAED,qBAQa,QAAQ;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC;CAGpC"}
package/lib/mjs/dto.js CHANGED
@@ -17,10 +17,11 @@ PaginationDTO = __decorate([
17
17
  Schema({
18
18
  type: 'object',
19
19
  $id: 'arrow.common.PaginationDTO',
20
+ // Must match the class fields below — otherwise `page` is never validated
21
+ // and offset/take validate phantom properties that the class never declares.
20
22
  properties: {
21
23
  limit: { type: 'number', minimum: 0 },
22
- offset: { type: 'number', minimum: 0 },
23
- take: { type: 'number', minimum: 0 },
24
+ page: { type: 'number', minimum: 0 },
24
25
  },
25
26
  }),
26
27
  __metadata("design:paramtypes", [Object])
@@ -1 +1 @@
1
- {"version":3,"file":"dto.js","sourceRoot":"","sources":["../../src/dto.ts"],"names":[],"mappings":";;;;;;;;;AACA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAWtC,IAAM,aAAa,GAAnB,MAAM,aAAa;IAIxB,YAAY,IAA4B;QACtC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF,CAAA;AAPY,aAAa;IATzB,MAAM,CAAC;QACN,IAAI,EAAE,QAAQ;QACd,GAAG,EAAE,4BAA4B;QACjC,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;YACrC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;YACtC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;SACrC;KACF,CAAC;;GACW,aAAa,CAOzB;;AAUM,IAAM,QAAQ,GAAd,MAAM,QAAQ;IAInB,YAAY,IAAuB;QACjC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF,CAAA;AAPY,QAAQ;IARpB,MAAM,CAAC;QACN,IAAI,EAAE,QAAQ;QACd,GAAG,EAAE,uBAAuB;QAC5B,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE;YAC/D,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;SAC3B;KACF,CAAC;;GACW,QAAQ,CAOpB"}
1
+ {"version":3,"file":"dto.js","sourceRoot":"","sources":["../../src/dto.ts"],"names":[],"mappings":";;;;;;;;;AACA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAYtC,IAAM,aAAa,GAAnB,MAAM,aAAa;IAIxB,YAAY,IAA4B;QACtC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF,CAAA;AAPY,aAAa;IAVzB,MAAM,CAAC;QACN,IAAI,EAAE,QAAQ;QACd,GAAG,EAAE,4BAA4B;QACjC,0EAA0E;QAC1E,6EAA6E;QAC7E,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;YACrC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;SACrC;KACF,CAAC;;GACW,aAAa,CAOzB;;AAUM,IAAM,QAAQ,GAAd,MAAM,QAAQ;IAInB,YAAY,IAAuB;QACjC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF,CAAA;AAPY,QAAQ;IARpB,MAAM,CAAC;QACN,IAAI,EAAE,QAAQ;QACd,GAAG,EAAE,uBAAuB;QAC5B,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE;YAC/D,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;SAC3B;KACF,CAAC;;GACW,QAAQ,CAOpB"}
@@ -9,6 +9,7 @@ export * from './extension.js';
9
9
  export * from './route-arg.js';
10
10
  export * from './builders.js';
11
11
  export * from './dto.js';
12
+ export * from './dto-relation.js';
12
13
  export * from './response-methods/OrmNotFound.js';
13
14
  import * as express from 'express';
14
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAgG,MAAM,cAAc,CAAC;AAC5I,OAAO,EAAE,eAAe,EAAE,UAAU,EAAoB,aAAa,EAAE,WAAW,EAAE,OAAO,IAAI,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAClJ,OAAO,EAAE,UAAU,EAAqC,YAAY,EAAM,MAAM,aAAa,CAAC;AAE9F,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,mCAAmC,CAAC;AAClD,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAEnC;;;;GAIG;AACH,qBACa,SAAU,SAAQ,SAAS;IACtC,IAAW,aAAa,IAAI,MAAM,CAEjC;IAEY,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM;;;;CAU1I;AAED,qBACa,WAAY,SAAQ,SAAS;IAExC,SAAS,CAAC,SAAS,EAAE,UAAU,CAAC;IAGhC,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAEb,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAE9B,IAAW,aAAa,IAAI,MAAM,CAEjC;IAEY,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ;;;;IAWjG,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,eAAe,CAAC,gBAAgB,CAAC,OAAO,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ;IAuBjG,SAAS,CAAC,+BAA+B,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,CAAC,gBAAgB,CAAC,OAAO,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ;CA8D5J;AAED,qBAAa,eAAgB,SAAQ,WAAW;IACjC,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC;CAS3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,yGAE3D;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,OAAO,SAAS,EAAE,OAAO,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,yGAElF;AAED,qBACa,mBAAoB,SAAQ,YAAY;IACtC,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAgBxC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAgG,MAAM,cAAc,CAAC;AAC5I,OAAO,EAAE,eAAe,EAAE,UAAU,EAAoB,aAAa,EAAE,WAAW,EAAE,OAAO,IAAI,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAClJ,OAAO,EAAE,UAAU,EAAqC,YAAY,EAAM,MAAM,aAAa,CAAC;AAE9F,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,cAAc,mCAAmC,CAAC;AAClD,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAEnC;;;;GAIG;AACH,qBACa,SAAU,SAAQ,SAAS;IACtC,IAAW,aAAa,IAAI,MAAM,CAEjC;IAEY,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM;;;;CAU1I;AAED,qBACa,WAAY,SAAQ,SAAS;IAExC,SAAS,CAAC,SAAS,EAAE,UAAU,CAAC;IAGhC,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAEb,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAE9B,IAAW,aAAa,IAAI,MAAM,CAEjC;IAEY,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ;;;;IAWjG,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,eAAe,CAAC,gBAAgB,CAAC,OAAO,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ;IAuBjG,SAAS,CAAC,+BAA+B,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,CAAC,gBAAgB,CAAC,OAAO,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ;CAqE5J;AAED,qBAAa,eAAgB,SAAQ,WAAW;IACjC,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC;CAS3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,yGAE3D;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,OAAO,SAAS,EAAE,OAAO,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,yGAElF;AAED,qBACa,mBAAoB,SAAQ,YAAY;IACtC,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAgBxC"}
package/lib/mjs/index.js CHANGED
@@ -19,6 +19,7 @@ export * from './extension.js';
19
19
  export * from './route-arg.js';
20
20
  export * from './builders.js';
21
21
  export * from './dto.js';
22
+ export * from './dto-relation.js';
22
23
  export * from './response-methods/OrmNotFound.js';
23
24
  /**
24
25
  * Route arg to hydrate model from request body
@@ -81,7 +82,12 @@ let FromDbModel = class FromDbModel extends RouteArgs {
81
82
  const pkValue = this._extractValue(param, req);
82
83
  const query = param.RuntimeType['query']();
83
84
  const descriptor = extractModelDescriptor(param.RuntimeType);
84
- const queryField = param?.Options?.queryField ?? descriptor.PrimaryKey;
85
+ // A route parameter carries ONE value, so it cannot address a composite key. Fail with a
86
+ // 400 rather than silently filtering on the first key column and returning the wrong row.
87
+ if (!param?.Options?.queryField && (descriptor.PrimaryKey?.length ?? 0) !== 1) {
88
+ throw new BadRequest(`model ${descriptor.Name} has a composite primary key (${(descriptor.PrimaryKey ?? []).join(', ')}); pass queryField to select a single lookup column`);
89
+ }
90
+ const queryField = param?.Options?.queryField ?? descriptor.PrimaryKey[0];
85
91
  query.setTable(descriptor.TableName, `$${descriptor.TableName}`);
86
92
  query.select('*');
87
93
  query.where(queryField, pkValue);