@stonyx/orm 0.3.2-alpha.90 → 0.3.2-alpha.92
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 +6 -0
- package/dist/orm-request.d.ts +1 -0
- package/dist/orm-request.js +24 -7
- package/package.json +6 -5
- package/src/orm-request.ts +30 -7
package/README.md
CHANGED
|
@@ -113,6 +113,12 @@ export default {
|
|
|
113
113
|
};
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
+
> **`route` and JSON:API `links`.** Generated endpoints are mounted under `route`, and every
|
|
117
|
+
> `links.self` / `links.related` the ORM emits is an absolute URL that includes it. With
|
|
118
|
+
> `ORM_REST_ROUTE='/api'` the animal collection is served at `/api/animals` and advertises
|
|
119
|
+
> `http://host/api/animals`, so published links are followable as-is — do not prepend the
|
|
120
|
+
> mount yourself.
|
|
121
|
+
|
|
116
122
|
Then run the application via the Stonyx CLI, which auto-initializes all modules including the ORM:
|
|
117
123
|
|
|
118
124
|
```bash
|
package/dist/orm-request.d.ts
CHANGED
package/dist/orm-request.js
CHANGED
|
@@ -42,11 +42,28 @@ function getModelRelationships(modelName) {
|
|
|
42
42
|
}
|
|
43
43
|
return relationships;
|
|
44
44
|
}
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Build the absolute base URL that every advertised link hangs off — origin
|
|
47
|
+
* plus the prefix the ORM's routes are actually mounted at.
|
|
48
|
+
*
|
|
49
|
+
* The prefix is derived from the *request*, not from
|
|
50
|
+
* `config.orm.restServer.route`. Express sets `request.baseUrl` to the real
|
|
51
|
+
* mountpath registered by `RestServer.mountRoute`, which for this module is
|
|
52
|
+
* always `<prefix>/<pluralizedModel>` (see setup-rest-server.ts). Stripping the
|
|
53
|
+
* trailing model segment therefore yields the prefix by construction, and the
|
|
54
|
+
* link builder cannot drift from the mount registrar the way a second,
|
|
55
|
+
* independent normalisation of `route` would.
|
|
56
|
+
*
|
|
57
|
+
* When `request.baseUrl` is absent or does not end in the model segment the
|
|
58
|
+
* prefix is empty, which reproduces the previous origin-only behaviour.
|
|
59
|
+
*/
|
|
60
|
+
function getBaseUrl(request, pluralizedModel) {
|
|
47
61
|
const protocol = request.protocol || 'http';
|
|
48
62
|
const host = request.get('host');
|
|
49
|
-
|
|
63
|
+
const modelSegment = `/${pluralizedModel}`;
|
|
64
|
+
const mountPath = request.baseUrl ?? '';
|
|
65
|
+
const prefix = mountPath.endsWith(modelSegment) ? mountPath.slice(0, -modelSegment.length) : '';
|
|
66
|
+
return `${protocol}://${host}${prefix}`;
|
|
50
67
|
}
|
|
51
68
|
function getId(params) {
|
|
52
69
|
const id = params.id;
|
|
@@ -209,7 +226,7 @@ export default class OrmRequest extends Request {
|
|
|
209
226
|
recordsToReturn = recordsToReturn.filter(accessFilter);
|
|
210
227
|
if (queryFilterPredicate)
|
|
211
228
|
recordsToReturn = recordsToReturn.filter(queryFilterPredicate);
|
|
212
|
-
const baseUrl = getBaseUrl(request);
|
|
229
|
+
const baseUrl = getBaseUrl(request, pluralizedModel);
|
|
213
230
|
const data = recordsToReturn.map(record => record.toJSON?.({ fields: modelFields, baseUrl }));
|
|
214
231
|
return buildResponse(data, request.query?.include, recordsToReturn, {
|
|
215
232
|
links: { self: `${baseUrl}/${pluralizedModel}` },
|
|
@@ -222,7 +239,7 @@ export default class OrmRequest extends Request {
|
|
|
222
239
|
return 404;
|
|
223
240
|
const fieldsMap = parseFields(request.query);
|
|
224
241
|
const modelFields = fieldsMap.get(pluralizedModel) || fieldsMap.get(model);
|
|
225
|
-
const baseUrl = getBaseUrl(request);
|
|
242
|
+
const baseUrl = getBaseUrl(request, pluralizedModel);
|
|
226
243
|
return buildResponse(record.toJSON?.({ fields: modelFields, baseUrl }), request.query?.include, record, {
|
|
227
244
|
links: { self: `${baseUrl}/${pluralizedModel}/${request.params.id}` },
|
|
228
245
|
baseUrl
|
|
@@ -397,7 +414,7 @@ export default class OrmRequest extends Request {
|
|
|
397
414
|
if (!record)
|
|
398
415
|
return 404;
|
|
399
416
|
const relatedData = record.__relationships[relationshipName];
|
|
400
|
-
const baseUrl = getBaseUrl(request);
|
|
417
|
+
const baseUrl = getBaseUrl(request, pluralizedModel);
|
|
401
418
|
let data;
|
|
402
419
|
if (info.isArray) {
|
|
403
420
|
// hasMany - return array
|
|
@@ -419,7 +436,7 @@ export default class OrmRequest extends Request {
|
|
|
419
436
|
if (!record)
|
|
420
437
|
return 404;
|
|
421
438
|
const relatedData = record.__relationships[relationshipName];
|
|
422
|
-
const baseUrl = getBaseUrl(request);
|
|
439
|
+
const baseUrl = getBaseUrl(request, pluralizedModel);
|
|
423
440
|
let data;
|
|
424
441
|
if (info.isArray) {
|
|
425
442
|
// hasMany - return array of linkage objects
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"stonyx-async",
|
|
5
5
|
"stonyx-module"
|
|
6
6
|
],
|
|
7
|
-
"version": "0.3.2-alpha.
|
|
7
|
+
"version": "0.3.2-alpha.92",
|
|
8
8
|
"description": "",
|
|
9
9
|
"main": "dist/index.js",
|
|
10
10
|
"type": "module",
|
|
@@ -61,10 +61,10 @@
|
|
|
61
61
|
},
|
|
62
62
|
"homepage": "https://github.com/abofs/stonyx-orm#readme",
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@stonyx/cron": "0.2.1-beta.
|
|
64
|
+
"@stonyx/cron": "0.2.1-beta.95",
|
|
65
65
|
"@stonyx/events": "0.1.1-beta.52",
|
|
66
66
|
"@stonyx/utils": "0.2.3-beta.26",
|
|
67
|
-
"stonyx": "0.2.3-beta.
|
|
67
|
+
"stonyx": "0.2.3-beta.81"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
70
|
"@aws-sdk/client-dynamodb": "^3.0.0",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
}
|
|
92
92
|
},
|
|
93
93
|
"devDependencies": {
|
|
94
|
-
"@stonyx/rest-server": "0.2.1-beta.
|
|
94
|
+
"@stonyx/rest-server": "0.2.1-beta.98",
|
|
95
95
|
"@types/node": "^25.6.0",
|
|
96
96
|
"mysql2": "^3.20.0",
|
|
97
97
|
"pg": "^8.20.0",
|
|
@@ -103,7 +103,8 @@
|
|
|
103
103
|
"scripts": {
|
|
104
104
|
"build": "tsc",
|
|
105
105
|
"build:test": "tsc -p tsconfig.test.json",
|
|
106
|
-
"test": "pnpm build && NODE_ENV=test node --import tsx/esm --import ./test/setup.ts node_modules/qunit/bin/qunit.js 'test/**/*-test.ts'",
|
|
106
|
+
"test": "pnpm build && NODE_ENV=test node --import tsx/esm --import ./test/setup.ts node_modules/qunit/bin/qunit.js 'test/**/*-test.ts' && ORM_TEST_ROUTE=/ pnpm test:mounted && ORM_TEST_ROUTE=/api pnpm test:mounted && ORM_TEST_ROUTE=api pnpm test:mounted && ORM_TEST_ROUTE=/api/v1 pnpm test:mounted && ORM_TEST_ROUTE=/api/ pnpm test:mounted",
|
|
107
|
+
"test:mounted": "node --import tsx/esm --import ./test/integration/mounted-route/setup.ts node_modules/qunit/bin/qunit.js 'test/integration/mounted-route/links-mounted.ts' 'test/zz-exit-test.ts'",
|
|
107
108
|
"test:dynamodb": "pnpm build && node --import tsx/esm --import ./test/integration/dynamodb/setup.ts node_modules/qunit/bin/qunit.js 'test/integration/dynamodb/**/*-test.ts'"
|
|
108
109
|
}
|
|
109
110
|
}
|
package/src/orm-request.ts
CHANGED
|
@@ -10,6 +10,10 @@ import { isOrmRecord } from './utils.js';
|
|
|
10
10
|
|
|
11
11
|
interface OrmRequest$ extends Request {
|
|
12
12
|
protocol?: string;
|
|
13
|
+
// Express sets this to the path the router was mounted at, e.g. '/api/animals'
|
|
14
|
+
// when orm.restServer.route is '/api'. Optional because non-Express callers
|
|
15
|
+
// (unit tests, programmatic handler invocation) do not supply it.
|
|
16
|
+
baseUrl?: string;
|
|
13
17
|
method: string;
|
|
14
18
|
params: { [key: string]: string };
|
|
15
19
|
body?: { [key: string]: unknown };
|
|
@@ -77,11 +81,30 @@ function getModelRelationships(modelName: string): { [key: string]: Relationship
|
|
|
77
81
|
return relationships;
|
|
78
82
|
}
|
|
79
83
|
|
|
80
|
-
|
|
81
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Build the absolute base URL that every advertised link hangs off — origin
|
|
86
|
+
* plus the prefix the ORM's routes are actually mounted at.
|
|
87
|
+
*
|
|
88
|
+
* The prefix is derived from the *request*, not from
|
|
89
|
+
* `config.orm.restServer.route`. Express sets `request.baseUrl` to the real
|
|
90
|
+
* mountpath registered by `RestServer.mountRoute`, which for this module is
|
|
91
|
+
* always `<prefix>/<pluralizedModel>` (see setup-rest-server.ts). Stripping the
|
|
92
|
+
* trailing model segment therefore yields the prefix by construction, and the
|
|
93
|
+
* link builder cannot drift from the mount registrar the way a second,
|
|
94
|
+
* independent normalisation of `route` would.
|
|
95
|
+
*
|
|
96
|
+
* When `request.baseUrl` is absent or does not end in the model segment the
|
|
97
|
+
* prefix is empty, which reproduces the previous origin-only behaviour.
|
|
98
|
+
*/
|
|
99
|
+
function getBaseUrl(request: OrmRequest$, pluralizedModel: string): string {
|
|
82
100
|
const protocol = request.protocol || 'http';
|
|
83
101
|
const host = request.get('host');
|
|
84
|
-
|
|
102
|
+
|
|
103
|
+
const modelSegment = `/${pluralizedModel}`;
|
|
104
|
+
const mountPath = request.baseUrl ?? '';
|
|
105
|
+
const prefix = mountPath.endsWith(modelSegment) ? mountPath.slice(0, -modelSegment.length) : '';
|
|
106
|
+
|
|
107
|
+
return `${protocol}://${host}${prefix}`;
|
|
85
108
|
}
|
|
86
109
|
|
|
87
110
|
function getId(params: { id?: string; [key: string]: unknown }): string | number {
|
|
@@ -278,7 +301,7 @@ export default class OrmRequest extends Request {
|
|
|
278
301
|
if (accessFilter) recordsToReturn = recordsToReturn.filter(accessFilter as (record: OrmRecord) => boolean);
|
|
279
302
|
if (queryFilterPredicate) recordsToReturn = recordsToReturn.filter(queryFilterPredicate as (record: OrmRecord) => boolean);
|
|
280
303
|
|
|
281
|
-
const baseUrl = getBaseUrl(request);
|
|
304
|
+
const baseUrl = getBaseUrl(request, pluralizedModel);
|
|
282
305
|
const data = recordsToReturn.map(record => record.toJSON?.({ fields: modelFields, baseUrl }));
|
|
283
306
|
|
|
284
307
|
return buildResponse(data, request.query?.include, recordsToReturn, {
|
|
@@ -294,7 +317,7 @@ export default class OrmRequest extends Request {
|
|
|
294
317
|
const fieldsMap = parseFields(request.query);
|
|
295
318
|
const modelFields = fieldsMap.get(pluralizedModel) || fieldsMap.get(model);
|
|
296
319
|
|
|
297
|
-
const baseUrl = getBaseUrl(request);
|
|
320
|
+
const baseUrl = getBaseUrl(request, pluralizedModel);
|
|
298
321
|
return buildResponse(record.toJSON?.({ fields: modelFields, baseUrl }), request.query?.include, record, {
|
|
299
322
|
links: { self: `${baseUrl}/${pluralizedModel}/${request.params.id}` },
|
|
300
323
|
baseUrl
|
|
@@ -502,7 +525,7 @@ export default class OrmRequest extends Request {
|
|
|
502
525
|
if (!record) return 404;
|
|
503
526
|
|
|
504
527
|
const relatedData = record.__relationships[relationshipName];
|
|
505
|
-
const baseUrl = getBaseUrl(request);
|
|
528
|
+
const baseUrl = getBaseUrl(request, pluralizedModel);
|
|
506
529
|
|
|
507
530
|
let data: unknown;
|
|
508
531
|
if (info.isArray) {
|
|
@@ -526,7 +549,7 @@ export default class OrmRequest extends Request {
|
|
|
526
549
|
if (!record) return 404;
|
|
527
550
|
|
|
528
551
|
const relatedData = record.__relationships[relationshipName];
|
|
529
|
-
const baseUrl = getBaseUrl(request);
|
|
552
|
+
const baseUrl = getBaseUrl(request, pluralizedModel);
|
|
530
553
|
|
|
531
554
|
let data: unknown;
|
|
532
555
|
if (info.isArray) {
|