@atscript/moost-db 0.1.52 → 0.1.54

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/dist/index.cjs CHANGED
@@ -229,8 +229,15 @@ let AsDbReadableController = class AsDbReadableController {
229
229
  }
230
230
  /** Sets @db.http.path on the type metadata from the controller's computed prefix. */
231
231
  _resolveHttpPath() {
232
- const overview = this.app.getControllersOverview?.()?.find((o) => o.type === this.constructor);
233
- if (overview?.computedPrefix) this.readable.type.metadata.set("db.http.path", overview.computedPrefix);
232
+ let prefix;
233
+ try {
234
+ prefix = (0, moost.useControllerContext)().getPrefix();
235
+ } catch {}
236
+ if (!prefix) prefix = (this.app.getControllersOverview?.()?.find((o) => o.type === this.constructor))?.computedPrefix;
237
+ if (prefix) {
238
+ if (!prefix.startsWith("/")) prefix = `/${prefix}`;
239
+ this.readable.type.metadata.set("db.http.path", prefix);
240
+ }
234
241
  }
235
242
  /** Lazily serializes the type (after all controllers have set their @db.http.path). */
236
243
  getSerializedType() {
@@ -329,12 +336,14 @@ let AsDbReadableController = class AsDbReadableController {
329
336
  }
330
337
  /**
331
338
  * Transform filter before querying. Override to add tenant filtering, etc.
339
+ * May return a Promise for async lookups (session, permissions).
332
340
  */
333
341
  transformFilter(filter) {
334
342
  return filter;
335
343
  }
336
344
  /**
337
345
  * Transform projection before querying.
346
+ * May return a Promise for async lookups.
338
347
  */
339
348
  transformProjection(projection) {
340
349
  return projection;
@@ -393,7 +402,7 @@ let AsDbReadableController = class AsDbReadableController {
393
402
  const insightsError = this.validateInsights(parsed.insights);
394
403
  if (insightsError) return new _moostjs_event_http.HttpError(400, insightsError);
395
404
  }
396
- const filter = this.transformFilter(parsed.filter);
405
+ const filter = await this.transformFilter(parsed.filter);
397
406
  return this.readable.aggregate({
398
407
  filter,
399
408
  controls,
@@ -402,8 +411,7 @@ let AsDbReadableController = class AsDbReadableController {
402
411
  }
403
412
  const error = this.validateParsed(parsed, "query");
404
413
  if (error) return error;
405
- const filter = this.transformFilter(parsed.filter);
406
- const select = this.transformProjection(controls.$select);
414
+ const [filter, select] = await Promise.all([this.transformFilter(parsed.filter), this.transformProjection(controls.$select)]);
407
415
  if (controls.$count) return this.readable.count({
408
416
  filter,
409
417
  controls: {
@@ -443,8 +451,7 @@ let AsDbReadableController = class AsDbReadableController {
443
451
  const page = Math.max(Number(controls.$page || 1), 1);
444
452
  const size = Math.max(Number(controls.$size || 10), 1);
445
453
  const skip = (page - 1) * size;
446
- const filter = this.transformFilter(parsed.filter);
447
- const select = this.transformProjection(controls.$select);
454
+ const [filter, select] = await Promise.all([this.transformFilter(parsed.filter), this.transformProjection(controls.$select)]);
448
455
  const searchTerm = controls.$search;
449
456
  const indexName = controls.$index;
450
457
  const vectorField = controls.$vector;
@@ -482,7 +489,7 @@ let AsDbReadableController = class AsDbReadableController {
482
489
  if (Object.keys(parsed.filter).length > 0) return new _moostjs_event_http.HttpError(400, "Filtering is not allowed for \"one\" endpoint");
483
490
  const error = this.validateParsed(parsed, "getOne");
484
491
  if (error) return error;
485
- const select = this.transformProjection(parsed.controls.$select);
492
+ const select = await this.transformProjection(parsed.controls.$select);
486
493
  const controls = {
487
494
  ...parsed.controls,
488
495
  $select: select
@@ -497,7 +504,7 @@ let AsDbReadableController = class AsDbReadableController {
497
504
  const idObj = this.extractCompositeId(query);
498
505
  if (idObj instanceof _moostjs_event_http.HttpError) return idObj;
499
506
  const parsed = this.parseQueryString(url);
500
- const select = this.transformProjection(parsed.controls.$select);
507
+ const select = await this.transformProjection(parsed.controls.$select);
501
508
  const controls = {
502
509
  ...parsed.controls,
503
510
  $select: select
@@ -506,6 +513,11 @@ let AsDbReadableController = class AsDbReadableController {
506
513
  }
507
514
  /**
508
515
  * **GET /meta** — returns table/view metadata for UI.
516
+ *
517
+ * The return type includes `Promise<...>` so subclasses can override with an
518
+ * async implementation (e.g. to enrich the payload from an external source).
519
+ * The base cache only covers the base payload — async overrides must cache
520
+ * their own enrichment if needed.
509
521
  */
510
522
  meta() {
511
523
  if (this._metaResponse) return this._metaResponse;
@@ -523,7 +535,7 @@ let AsDbReadableController = class AsDbReadableController {
523
535
  filterable: true
524
536
  };
525
537
  }
526
- this._metaResponse = {
538
+ const response = {
527
539
  searchable: this.readable.isSearchable(),
528
540
  vectorSearchable: this.readable.isVectorSearchable(),
529
541
  searchIndexes: this.readable.getSearchIndexes(),
@@ -533,7 +545,8 @@ let AsDbReadableController = class AsDbReadableController {
533
545
  fields,
534
546
  type: this.getSerializedType()
535
547
  };
536
- return this._metaResponse;
548
+ this._metaResponse = response;
549
+ return response;
537
550
  }
538
551
  };
539
552
  __decorate([
@@ -570,7 +583,7 @@ __decorate([
570
583
  (0, _moostjs_event_http.Get)("meta"),
571
584
  __decorateMetadata("design:type", Function),
572
585
  __decorateMetadata("design:paramtypes", []),
573
- __decorateMetadata("design:returntype", void 0)
586
+ __decorateMetadata("design:returntype", Object)
574
587
  ], AsDbReadableController.prototype, "meta", null);
575
588
  AsDbReadableController = __decorate([
576
589
  UseValidationErrorTransform(),
@@ -593,12 +606,14 @@ let AsDbController = class AsDbController extends AsDbReadableController {
593
606
  }
594
607
  /**
595
608
  * Intercepts write operations. Return `undefined` to abort.
609
+ * May be async (e.g. to enrich payloads from session / permissions).
596
610
  */
597
611
  onWrite(action, data) {
598
612
  return data;
599
613
  }
600
614
  /**
601
615
  * Intercepts delete operations. Return `undefined` to abort.
616
+ * May be async (e.g. to resolve composite ids from external state).
602
617
  */
603
618
  onRemove(id) {
604
619
  return id;
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _atscript_typescript_utils0 from "@atscript/typescript/utils";
2
- import { TAtscriptAnnotatedType, TAtscriptDataType, TSerializeOptions, Validator, serializeAnnotatedType } from "@atscript/typescript/utils";
2
+ import { TAtscriptAnnotatedType, TAtscriptDataType, TSerializeOptions, Validator } from "@atscript/typescript/utils";
3
3
  import * as _uniqu_url0 from "@uniqu/url";
4
- import { AtscriptDbReadable, AtscriptDbTable, FilterExpr, Uniquery, UniqueryControls } from "@atscript/db";
4
+ import { AtscriptDbReadable, AtscriptDbTable, FilterExpr, TMetaResponse, Uniquery, UniqueryControls } from "@atscript/db";
5
5
  import { HttpError } from "@moostjs/event-http";
6
6
  import * as moost from "moost";
7
7
  import { Moost, TConsoleBase } from "moost";
@@ -63,12 +63,14 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
63
63
  protected computeEmbedding(_search: string, _fieldName?: string): Promise<number[]>;
64
64
  /**
65
65
  * Transform filter before querying. Override to add tenant filtering, etc.
66
+ * May return a Promise for async lookups (session, permissions).
66
67
  */
67
- protected transformFilter(filter: FilterExpr): FilterExpr;
68
+ protected transformFilter(filter: FilterExpr): FilterExpr | Promise<FilterExpr>;
68
69
  /**
69
70
  * Transform projection before querying.
71
+ * May return a Promise for async lookups.
70
72
  */
71
- protected transformProjection(projection?: UniqueryControls["$select"]): UniqueryControls["$select"] | undefined;
73
+ protected transformProjection(projection?: UniqueryControls["$select"]): UniqueryControls["$select"] | undefined | Promise<UniqueryControls["$select"] | undefined>;
72
74
  protected parseQueryString(url: string): _uniqu_url0.UrlQuery;
73
75
  protected returnOne(result: Promise<DataType | null>): Promise<DataType | HttpError>;
74
76
  /**
@@ -101,24 +103,13 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
101
103
  getOneComposite(query: Record<string, string>, url: string): Promise<DataType | HttpError>;
102
104
  /**
103
105
  * **GET /meta** — returns table/view metadata for UI.
106
+ *
107
+ * The return type includes `Promise<...>` so subclasses can override with an
108
+ * async implementation (e.g. to enrich the payload from an external source).
109
+ * The base cache only covers the base payload — async overrides must cache
110
+ * their own enrichment if needed.
104
111
  */
105
- meta(): {
106
- searchable: boolean;
107
- vectorSearchable: boolean;
108
- searchIndexes: ReturnType<AtscriptDbReadable<T>["getSearchIndexes"]>;
109
- primaryKeys: string[];
110
- readOnly: boolean;
111
- relations: Array<{
112
- name: string;
113
- direction: string;
114
- isArray: boolean;
115
- }>;
116
- fields: Record<string, {
117
- sortable: boolean;
118
- filterable: boolean;
119
- }>;
120
- type: ReturnType<typeof serializeAnnotatedType>;
121
- };
112
+ meta(): TMetaResponse | Promise<TMetaResponse>;
122
113
  }
123
114
  //#endregion
124
115
  //#region src/as-db.controller.d.ts
@@ -139,10 +130,12 @@ declare class AsDbController<T extends TAtscriptAnnotatedType = TAtscriptAnnotat
139
130
  protected _isReadOnly(): boolean;
140
131
  /**
141
132
  * Intercepts write operations. Return `undefined` to abort.
133
+ * May be async (e.g. to enrich payloads from session / permissions).
142
134
  */
143
135
  protected onWrite(action: "insert" | "insertMany" | "replace" | "replaceMany" | "update" | "updateMany", data: unknown): unknown;
144
136
  /**
145
137
  * Intercepts delete operations. Return `undefined` to abort.
138
+ * May be async (e.g. to resolve composite ids from external state).
146
139
  */
147
140
  protected onRemove(id: unknown): unknown;
148
141
  /**
package/dist/index.d.mts CHANGED
@@ -1,10 +1,10 @@
1
1
  import * as _atscript_typescript_utils0 from "@atscript/typescript/utils";
2
- import { TAtscriptAnnotatedType, TAtscriptDataType, TSerializeOptions, Validator, serializeAnnotatedType } from "@atscript/typescript/utils";
2
+ import { TAtscriptAnnotatedType, TAtscriptDataType, TSerializeOptions, Validator } from "@atscript/typescript/utils";
3
3
  import { HttpError } from "@moostjs/event-http";
4
4
  import * as moost from "moost";
5
5
  import { Moost, TConsoleBase } from "moost";
6
6
  import * as _uniqu_url0 from "@uniqu/url";
7
- import { AtscriptDbReadable, AtscriptDbTable, FilterExpr, Uniquery, UniqueryControls } from "@atscript/db";
7
+ import { AtscriptDbReadable, AtscriptDbTable, FilterExpr, TMetaResponse, Uniquery, UniqueryControls } from "@atscript/db";
8
8
 
9
9
  //#region src/as-db-readable.controller.d.ts
10
10
  /**
@@ -63,12 +63,14 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
63
63
  protected computeEmbedding(_search: string, _fieldName?: string): Promise<number[]>;
64
64
  /**
65
65
  * Transform filter before querying. Override to add tenant filtering, etc.
66
+ * May return a Promise for async lookups (session, permissions).
66
67
  */
67
- protected transformFilter(filter: FilterExpr): FilterExpr;
68
+ protected transformFilter(filter: FilterExpr): FilterExpr | Promise<FilterExpr>;
68
69
  /**
69
70
  * Transform projection before querying.
71
+ * May return a Promise for async lookups.
70
72
  */
71
- protected transformProjection(projection?: UniqueryControls["$select"]): UniqueryControls["$select"] | undefined;
73
+ protected transformProjection(projection?: UniqueryControls["$select"]): UniqueryControls["$select"] | undefined | Promise<UniqueryControls["$select"] | undefined>;
72
74
  protected parseQueryString(url: string): _uniqu_url0.UrlQuery;
73
75
  protected returnOne(result: Promise<DataType | null>): Promise<DataType | HttpError>;
74
76
  /**
@@ -101,24 +103,13 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
101
103
  getOneComposite(query: Record<string, string>, url: string): Promise<DataType | HttpError>;
102
104
  /**
103
105
  * **GET /meta** — returns table/view metadata for UI.
106
+ *
107
+ * The return type includes `Promise<...>` so subclasses can override with an
108
+ * async implementation (e.g. to enrich the payload from an external source).
109
+ * The base cache only covers the base payload — async overrides must cache
110
+ * their own enrichment if needed.
104
111
  */
105
- meta(): {
106
- searchable: boolean;
107
- vectorSearchable: boolean;
108
- searchIndexes: ReturnType<AtscriptDbReadable<T>["getSearchIndexes"]>;
109
- primaryKeys: string[];
110
- readOnly: boolean;
111
- relations: Array<{
112
- name: string;
113
- direction: string;
114
- isArray: boolean;
115
- }>;
116
- fields: Record<string, {
117
- sortable: boolean;
118
- filterable: boolean;
119
- }>;
120
- type: ReturnType<typeof serializeAnnotatedType>;
121
- };
112
+ meta(): TMetaResponse | Promise<TMetaResponse>;
122
113
  }
123
114
  //#endregion
124
115
  //#region src/as-db.controller.d.ts
@@ -139,10 +130,12 @@ declare class AsDbController<T extends TAtscriptAnnotatedType = TAtscriptAnnotat
139
130
  protected _isReadOnly(): boolean;
140
131
  /**
141
132
  * Intercepts write operations. Return `undefined` to abort.
133
+ * May be async (e.g. to enrich payloads from session / permissions).
142
134
  */
143
135
  protected onWrite(action: "insert" | "insertMany" | "replace" | "replaceMany" | "update" | "updateMany", data: unknown): unknown;
144
136
  /**
145
137
  * Intercepts delete operations. Return `undefined` to abort.
138
+ * May be async (e.g. to resolve composite ids from external state).
146
139
  */
147
140
  protected onRemove(id: unknown): unknown;
148
141
  /**
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ValidatorError, defineAnnotatedType, serializeAnnotatedType, throwFeatureDisabled } from "@atscript/typescript/utils";
2
2
  import { Body, Delete, Get, HttpError, Patch, Post, Put, Query, Url } from "@moostjs/event-http";
3
- import { ApplyDecorators, Controller, Inherit, Inject, Intercept, Moost, Param, Provide, TInterceptorPriority, defineInterceptor } from "moost";
3
+ import { ApplyDecorators, Controller, Inherit, Inject, Intercept, Moost, Param, Provide, TInterceptorPriority, defineInterceptor, useControllerContext } from "moost";
4
4
  import { parseUrl } from "@uniqu/url";
5
5
  import { DbError } from "@atscript/db";
6
6
  //#region src/decorators.ts
@@ -228,8 +228,15 @@ let AsDbReadableController = class AsDbReadableController {
228
228
  }
229
229
  /** Sets @db.http.path on the type metadata from the controller's computed prefix. */
230
230
  _resolveHttpPath() {
231
- const overview = this.app.getControllersOverview?.()?.find((o) => o.type === this.constructor);
232
- if (overview?.computedPrefix) this.readable.type.metadata.set("db.http.path", overview.computedPrefix);
231
+ let prefix;
232
+ try {
233
+ prefix = useControllerContext().getPrefix();
234
+ } catch {}
235
+ if (!prefix) prefix = (this.app.getControllersOverview?.()?.find((o) => o.type === this.constructor))?.computedPrefix;
236
+ if (prefix) {
237
+ if (!prefix.startsWith("/")) prefix = `/${prefix}`;
238
+ this.readable.type.metadata.set("db.http.path", prefix);
239
+ }
233
240
  }
234
241
  /** Lazily serializes the type (after all controllers have set their @db.http.path). */
235
242
  getSerializedType() {
@@ -328,12 +335,14 @@ let AsDbReadableController = class AsDbReadableController {
328
335
  }
329
336
  /**
330
337
  * Transform filter before querying. Override to add tenant filtering, etc.
338
+ * May return a Promise for async lookups (session, permissions).
331
339
  */
332
340
  transformFilter(filter) {
333
341
  return filter;
334
342
  }
335
343
  /**
336
344
  * Transform projection before querying.
345
+ * May return a Promise for async lookups.
337
346
  */
338
347
  transformProjection(projection) {
339
348
  return projection;
@@ -392,7 +401,7 @@ let AsDbReadableController = class AsDbReadableController {
392
401
  const insightsError = this.validateInsights(parsed.insights);
393
402
  if (insightsError) return new HttpError(400, insightsError);
394
403
  }
395
- const filter = this.transformFilter(parsed.filter);
404
+ const filter = await this.transformFilter(parsed.filter);
396
405
  return this.readable.aggregate({
397
406
  filter,
398
407
  controls,
@@ -401,8 +410,7 @@ let AsDbReadableController = class AsDbReadableController {
401
410
  }
402
411
  const error = this.validateParsed(parsed, "query");
403
412
  if (error) return error;
404
- const filter = this.transformFilter(parsed.filter);
405
- const select = this.transformProjection(controls.$select);
413
+ const [filter, select] = await Promise.all([this.transformFilter(parsed.filter), this.transformProjection(controls.$select)]);
406
414
  if (controls.$count) return this.readable.count({
407
415
  filter,
408
416
  controls: {
@@ -442,8 +450,7 @@ let AsDbReadableController = class AsDbReadableController {
442
450
  const page = Math.max(Number(controls.$page || 1), 1);
443
451
  const size = Math.max(Number(controls.$size || 10), 1);
444
452
  const skip = (page - 1) * size;
445
- const filter = this.transformFilter(parsed.filter);
446
- const select = this.transformProjection(controls.$select);
453
+ const [filter, select] = await Promise.all([this.transformFilter(parsed.filter), this.transformProjection(controls.$select)]);
447
454
  const searchTerm = controls.$search;
448
455
  const indexName = controls.$index;
449
456
  const vectorField = controls.$vector;
@@ -481,7 +488,7 @@ let AsDbReadableController = class AsDbReadableController {
481
488
  if (Object.keys(parsed.filter).length > 0) return new HttpError(400, "Filtering is not allowed for \"one\" endpoint");
482
489
  const error = this.validateParsed(parsed, "getOne");
483
490
  if (error) return error;
484
- const select = this.transformProjection(parsed.controls.$select);
491
+ const select = await this.transformProjection(parsed.controls.$select);
485
492
  const controls = {
486
493
  ...parsed.controls,
487
494
  $select: select
@@ -496,7 +503,7 @@ let AsDbReadableController = class AsDbReadableController {
496
503
  const idObj = this.extractCompositeId(query);
497
504
  if (idObj instanceof HttpError) return idObj;
498
505
  const parsed = this.parseQueryString(url);
499
- const select = this.transformProjection(parsed.controls.$select);
506
+ const select = await this.transformProjection(parsed.controls.$select);
500
507
  const controls = {
501
508
  ...parsed.controls,
502
509
  $select: select
@@ -505,6 +512,11 @@ let AsDbReadableController = class AsDbReadableController {
505
512
  }
506
513
  /**
507
514
  * **GET /meta** — returns table/view metadata for UI.
515
+ *
516
+ * The return type includes `Promise<...>` so subclasses can override with an
517
+ * async implementation (e.g. to enrich the payload from an external source).
518
+ * The base cache only covers the base payload — async overrides must cache
519
+ * their own enrichment if needed.
508
520
  */
509
521
  meta() {
510
522
  if (this._metaResponse) return this._metaResponse;
@@ -522,7 +534,7 @@ let AsDbReadableController = class AsDbReadableController {
522
534
  filterable: true
523
535
  };
524
536
  }
525
- this._metaResponse = {
537
+ const response = {
526
538
  searchable: this.readable.isSearchable(),
527
539
  vectorSearchable: this.readable.isVectorSearchable(),
528
540
  searchIndexes: this.readable.getSearchIndexes(),
@@ -532,7 +544,8 @@ let AsDbReadableController = class AsDbReadableController {
532
544
  fields,
533
545
  type: this.getSerializedType()
534
546
  };
535
- return this._metaResponse;
547
+ this._metaResponse = response;
548
+ return response;
536
549
  }
537
550
  };
538
551
  __decorate([
@@ -569,7 +582,7 @@ __decorate([
569
582
  Get("meta"),
570
583
  __decorateMetadata("design:type", Function),
571
584
  __decorateMetadata("design:paramtypes", []),
572
- __decorateMetadata("design:returntype", void 0)
585
+ __decorateMetadata("design:returntype", Object)
573
586
  ], AsDbReadableController.prototype, "meta", null);
574
587
  AsDbReadableController = __decorate([
575
588
  UseValidationErrorTransform(),
@@ -592,12 +605,14 @@ let AsDbController = class AsDbController extends AsDbReadableController {
592
605
  }
593
606
  /**
594
607
  * Intercepts write operations. Return `undefined` to abort.
608
+ * May be async (e.g. to enrich payloads from session / permissions).
595
609
  */
596
610
  onWrite(action, data) {
597
611
  return data;
598
612
  }
599
613
  /**
600
614
  * Intercepts delete operations. Return `undefined` to abort.
615
+ * May be async (e.g. to resolve composite ids from external state).
601
616
  */
602
617
  onRemove(id) {
603
618
  return id;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/moost-db",
3
- "version": "0.1.52",
3
+ "version": "0.1.54",
4
4
  "description": "Generic database controller for Moost with Atscript.",
5
5
  "keywords": [
6
6
  "annotations",
@@ -53,7 +53,7 @@
53
53
  "@moostjs/event-http": "^0.6.7",
54
54
  "@uniqu/core": "^0.1.5",
55
55
  "moost": "^0.6.7",
56
- "@atscript/db": "^0.1.52"
56
+ "@atscript/db": "^0.1.54"
57
57
  },
58
58
  "scripts": {
59
59
  "postinstall": "asc -f dts",