@atscript/moost-db 0.1.33 → 0.1.35

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Atscript
3
+ Copyright (c) 2025-present Artem Maltsev
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/dist/index.cjs CHANGED
@@ -28,8 +28,11 @@ const moost = __toESM(require("moost"));
28
28
  const __uniqu_url = __toESM(require("@uniqu/url"));
29
29
 
30
30
  //#region packages/moost-db/src/decorators.ts
31
- const TABLE_DEF = "__atscript_db_table_def";
31
+ const READABLE_DEF = "__atscript_db_readable_def";
32
+ const TABLE_DEF = READABLE_DEF;
32
33
  const TableController = (table, prefix) => (0, moost.ApplyDecorators)((0, moost.Provide)(TABLE_DEF, () => table), (0, moost.Controller)(prefix || table.tableName), (0, moost.Inherit)());
34
+ const ReadableController = (readable, prefix) => (0, moost.ApplyDecorators)((0, moost.Provide)(READABLE_DEF, () => readable), (0, moost.Controller)(prefix || readable.tableName), (0, moost.Inherit)());
35
+ const ViewController = ReadableController;
33
36
 
34
37
  //#endregion
35
38
  //#region packages/moost-db/src/validation-interceptor.ts
@@ -82,6 +85,33 @@ _define_property$1(GetOneControlsDto, "__is_atscript_annotated_type", true);
82
85
  _define_property$1(GetOneControlsDto, "type", {});
83
86
  _define_property$1(GetOneControlsDto, "metadata", new Map());
84
87
  _define_property$1(GetOneControlsDto, "id", "GetOneControlsDto");
88
+ let WithRelationDto = class WithRelationDto$1 {
89
+ static toJsonSchema() {
90
+ (0, __atscript_typescript_utils.throwFeatureDisabled)("JSON Schema", "jsonSchema", "emit.jsonSchema");
91
+ }
92
+ };
93
+ _define_property$1(WithRelationDto, "__is_atscript_annotated_type", true);
94
+ _define_property$1(WithRelationDto, "type", {});
95
+ _define_property$1(WithRelationDto, "metadata", new Map());
96
+ _define_property$1(WithRelationDto, "id", "WithRelationDto");
97
+ let WithRelationControlsDto = class WithRelationControlsDto$1 {
98
+ static toJsonSchema() {
99
+ (0, __atscript_typescript_utils.throwFeatureDisabled)("JSON Schema", "jsonSchema", "emit.jsonSchema");
100
+ }
101
+ };
102
+ _define_property$1(WithRelationControlsDto, "__is_atscript_annotated_type", true);
103
+ _define_property$1(WithRelationControlsDto, "type", {});
104
+ _define_property$1(WithRelationControlsDto, "metadata", new Map());
105
+ _define_property$1(WithRelationControlsDto, "id", "WithRelationControlsDto");
106
+ let WithFilterDto = class WithFilterDto$1 {
107
+ static toJsonSchema() {
108
+ (0, __atscript_typescript_utils.throwFeatureDisabled)("JSON Schema", "jsonSchema", "emit.jsonSchema");
109
+ }
110
+ };
111
+ _define_property$1(WithFilterDto, "__is_atscript_annotated_type", true);
112
+ _define_property$1(WithFilterDto, "type", {});
113
+ _define_property$1(WithFilterDto, "metadata", new Map());
114
+ _define_property$1(WithFilterDto, "id", "WithFilterDto");
85
115
  let SortControlDto = class SortControlDto$1 {
86
116
  static toJsonSchema() {
87
117
  (0, __atscript_typescript_utils.throwFeatureDisabled)("JSON Schema", "jsonSchema", "emit.jsonSchema");
@@ -100,7 +130,7 @@ _define_property$1(SelectControlDto, "__is_atscript_annotated_type", true);
100
130
  _define_property$1(SelectControlDto, "type", {});
101
131
  _define_property$1(SelectControlDto, "metadata", new Map());
102
132
  _define_property$1(SelectControlDto, "id", "SelectControlDto");
103
- (0, __atscript_typescript_utils.defineAnnotatedType)("object", QueryControlsDto).prop("$skip", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("number").tags("positive", "int", "number").annotate("expect.int", true).annotate("expect.min", { minValue: 0 }).optional().$type).prop("$limit", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("number").tags("positive", "int", "number").annotate("expect.int", true).annotate("expect.min", { minValue: 0 }).optional().$type).prop("$count", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("boolean").tags("boolean").optional().$type).prop("$sort", (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(SortControlDto).optional().$type).prop("$select", (0, __atscript_typescript_utils.defineAnnotatedType)("union").item((0, __atscript_typescript_utils.defineAnnotatedType)().refTo(SelectControlDto).$type).item((0, __atscript_typescript_utils.defineAnnotatedType)("array").of((0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").$type).$type).optional().$type).prop("$search", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$index", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type);
133
+ (0, __atscript_typescript_utils.defineAnnotatedType)("object", QueryControlsDto).prop("$skip", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("number").tags("positive", "int", "number").annotate("expect.int", true).annotate("expect.min", { minValue: 0 }).optional().$type).prop("$limit", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("number").tags("positive", "int", "number").annotate("expect.int", true).annotate("expect.min", { minValue: 0 }).optional().$type).prop("$count", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("boolean").tags("boolean").optional().$type).prop("$sort", (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(SortControlDto).optional().$type).prop("$select", (0, __atscript_typescript_utils.defineAnnotatedType)("union").item((0, __atscript_typescript_utils.defineAnnotatedType)().refTo(SelectControlDto).$type).item((0, __atscript_typescript_utils.defineAnnotatedType)("array").of((0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").$type).$type).optional().$type).prop("$search", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$index", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$with", (0, __atscript_typescript_utils.defineAnnotatedType)("array").of((0, __atscript_typescript_utils.defineAnnotatedType)().refTo(WithRelationDto).$type).optional().$type);
104
134
  (0, __atscript_typescript_utils.defineAnnotatedType)("object", PagesControlsDto).prop("$page", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").annotate("expect.pattern", {
105
135
  pattern: "^\\d+$",
106
136
  flags: "u",
@@ -109,13 +139,16 @@ _define_property$1(SelectControlDto, "id", "SelectControlDto");
109
139
  pattern: "^\\d+$",
110
140
  flags: "u",
111
141
  message: "Expected positive number"
112
- }, true).optional().$type).prop("$sort", (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(SortControlDto).optional().$type).prop("$select", (0, __atscript_typescript_utils.defineAnnotatedType)("union").item((0, __atscript_typescript_utils.defineAnnotatedType)().refTo(SelectControlDto).$type).item((0, __atscript_typescript_utils.defineAnnotatedType)("array").of((0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").$type).$type).optional().$type).prop("$search", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$index", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type);
113
- (0, __atscript_typescript_utils.defineAnnotatedType)("object", GetOneControlsDto).prop("$select", (0, __atscript_typescript_utils.defineAnnotatedType)("union").item((0, __atscript_typescript_utils.defineAnnotatedType)().refTo(SelectControlDto).$type).item((0, __atscript_typescript_utils.defineAnnotatedType)("array").of((0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").$type).$type).optional().$type);
142
+ }, true).optional().$type).prop("$sort", (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(SortControlDto).optional().$type).prop("$select", (0, __atscript_typescript_utils.defineAnnotatedType)("union").item((0, __atscript_typescript_utils.defineAnnotatedType)().refTo(SelectControlDto).$type).item((0, __atscript_typescript_utils.defineAnnotatedType)("array").of((0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").$type).$type).optional().$type).prop("$search", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$index", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$with", (0, __atscript_typescript_utils.defineAnnotatedType)("array").of((0, __atscript_typescript_utils.defineAnnotatedType)().refTo(WithRelationDto).$type).optional().$type);
143
+ (0, __atscript_typescript_utils.defineAnnotatedType)("object", GetOneControlsDto).prop("$select", (0, __atscript_typescript_utils.defineAnnotatedType)("union").item((0, __atscript_typescript_utils.defineAnnotatedType)().refTo(SelectControlDto).$type).item((0, __atscript_typescript_utils.defineAnnotatedType)("array").of((0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").$type).$type).optional().$type).prop("$with", (0, __atscript_typescript_utils.defineAnnotatedType)("array").of((0, __atscript_typescript_utils.defineAnnotatedType)().refTo(WithRelationDto).$type).optional().$type);
144
+ (0, __atscript_typescript_utils.defineAnnotatedType)("object", WithRelationDto).prop("name", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").$type).prop("filter", (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(WithFilterDto).optional().$type).prop("controls", (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(WithRelationControlsDto).optional().$type).prop("insights", (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(WithFilterDto).optional().$type);
145
+ (0, __atscript_typescript_utils.defineAnnotatedType)("object", WithRelationControlsDto).prop("$skip", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("number").tags("positive", "int", "number").annotate("expect.int", true).annotate("expect.min", { minValue: 0 }).optional().$type).prop("$limit", (0, __atscript_typescript_utils.defineAnnotatedType)().designType("number").tags("positive", "int", "number").annotate("expect.int", true).annotate("expect.min", { minValue: 0 }).optional().$type).prop("$sort", (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(SortControlDto).optional().$type).prop("$select", (0, __atscript_typescript_utils.defineAnnotatedType)("union").item((0, __atscript_typescript_utils.defineAnnotatedType)().refTo(SelectControlDto).$type).item((0, __atscript_typescript_utils.defineAnnotatedType)("array").of((0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").$type).$type).optional().$type).prop("$with", (0, __atscript_typescript_utils.defineAnnotatedType)("array").of((0, __atscript_typescript_utils.defineAnnotatedType)().refTo(WithRelationDto).$type).optional().$type);
146
+ (0, __atscript_typescript_utils.defineAnnotatedType)("object", WithFilterDto).propPattern(/./, (0, __atscript_typescript_utils.defineAnnotatedType)("union").item((0, __atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").$type).item((0, __atscript_typescript_utils.defineAnnotatedType)().designType("number").tags("number").$type).item((0, __atscript_typescript_utils.defineAnnotatedType)().designType("boolean").tags("boolean").$type).item((0, __atscript_typescript_utils.defineAnnotatedType)().designType("null").tags("null").$type).item((0, __atscript_typescript_utils.defineAnnotatedType)().refTo(WithFilterDto).$type).item((0, __atscript_typescript_utils.defineAnnotatedType)("array").of((0, __atscript_typescript_utils.defineAnnotatedType)().refTo(WithFilterDto).$type).$type).$type);
114
147
  (0, __atscript_typescript_utils.defineAnnotatedType)("object", SortControlDto).propPattern(/./, (0, __atscript_typescript_utils.defineAnnotatedType)("union").item((0, __atscript_typescript_utils.defineAnnotatedType)().designType("number").value(1).$type).item((0, __atscript_typescript_utils.defineAnnotatedType)().designType("number").value(-1).$type).$type);
115
148
  (0, __atscript_typescript_utils.defineAnnotatedType)("object", SelectControlDto).propPattern(/./, (0, __atscript_typescript_utils.defineAnnotatedType)("union").item((0, __atscript_typescript_utils.defineAnnotatedType)().designType("number").value(1).$type).item((0, __atscript_typescript_utils.defineAnnotatedType)().designType("number").value(0).$type).$type);
116
149
 
117
150
  //#endregion
118
- //#region packages/moost-db/src/as-db.controller.ts
151
+ //#region packages/moost-db/src/as-db-readable.controller.ts
119
152
  function _define_property(obj, key, value) {
120
153
  if (key in obj) Object.defineProperty(obj, key, {
121
154
  value,
@@ -126,21 +159,21 @@ function _define_property(obj, key, value) {
126
159
  else obj[key] = value;
127
160
  return obj;
128
161
  }
129
- function _ts_decorate(decorators, target, key, desc) {
162
+ function _ts_decorate$1(decorators, target, key, desc) {
130
163
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
131
164
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
132
165
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
133
166
  return c > 3 && r && Object.defineProperty(target, key, r), r;
134
167
  }
135
- function _ts_metadata(k, v) {
168
+ function _ts_metadata$1(k, v) {
136
169
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
137
170
  }
138
- function _ts_param(paramIndex, decorator) {
171
+ function _ts_param$1(paramIndex, decorator) {
139
172
  return function(target, key) {
140
173
  decorator(target, key, paramIndex);
141
174
  };
142
175
  }
143
- var AsDbController = class {
176
+ var AsDbReadableController = class {
144
177
  /**
145
178
  * One-time initialization hook. Override to seed data, register watchers, etc.
146
179
  */ init() {}
@@ -162,7 +195,7 @@ var AsDbController = class {
162
195
  return undefined;
163
196
  }
164
197
  validateInsights(insights) {
165
- for (const key of insights.keys()) if (!this.table.flatMap.has(key)) return `Unknown field "${key}"`;
198
+ for (const key of insights.keys()) if (!this.readable.flatMap.has(key)) return `Unknown field "${key}"`;
166
199
  return undefined;
167
200
  }
168
201
  validateParsed(parsed, type) {
@@ -184,16 +217,6 @@ var AsDbController = class {
184
217
  */ transformProjection(projection) {
185
218
  return projection;
186
219
  }
187
- /**
188
- * Intercepts write operations. Return `undefined` to abort.
189
- */ onWrite(action, data) {
190
- return data;
191
- }
192
- /**
193
- * Intercepts delete operations. Return `undefined` to abort.
194
- */ onRemove(id) {
195
- return id;
196
- }
197
220
  parseQueryString(url) {
198
221
  const idx = url.indexOf("?");
199
222
  return (0, __uniqu_url.parseUrl)(idx >= 0 ? url.slice(idx + 1) : "");
@@ -212,7 +235,7 @@ var AsDbController = class {
212
235
  const controls = parsed.controls;
213
236
  const filter = this.transformFilter(parsed.filter);
214
237
  const select = this.transformProjection(controls.$select);
215
- if (controls.$count) return this.table.count({
238
+ if (controls.$count) return this.readable.count({
216
239
  filter,
217
240
  controls: {
218
241
  ...controls,
@@ -221,7 +244,7 @@ var AsDbController = class {
221
244
  });
222
245
  const searchTerm = controls.$search;
223
246
  const indexName = controls.$index;
224
- if (searchTerm && this.table.isSearchable()) return this.table.search(searchTerm, {
247
+ if (searchTerm && this.readable.isSearchable()) return this.readable.search(searchTerm, {
225
248
  filter,
226
249
  controls: {
227
250
  ...controls,
@@ -229,7 +252,7 @@ var AsDbController = class {
229
252
  $limit: controls.$limit || 1e3
230
253
  }
231
254
  }, indexName);
232
- return this.table.findMany({
255
+ return this.readable.findMany({
233
256
  filter,
234
257
  controls: {
235
258
  ...controls,
@@ -262,8 +285,8 @@ var AsDbController = class {
262
285
  }
263
286
  };
264
287
  let result;
265
- if (searchTerm && this.table.isSearchable()) result = await this.table.searchWithCount(searchTerm, query, indexName);
266
- else result = await this.table.findManyWithCount(query);
288
+ if (searchTerm && this.readable.isSearchable()) result = await this.readable.searchWithCount(searchTerm, query, indexName);
289
+ else result = await this.readable.findManyWithCount(query);
267
290
  return {
268
291
  data: result.data,
269
292
  page,
@@ -280,7 +303,109 @@ else result = await this.table.findManyWithCount(query);
280
303
  const error = this.validateParsed(parsed, "getOne");
281
304
  if (error) return error;
282
305
  const select = this.transformProjection(parsed.controls.$select);
283
- return this.returnOne(this.table.findById(id, { $select: select }));
306
+ const controls = {
307
+ ...parsed.controls,
308
+ $select: select
309
+ };
310
+ return this.returnOne(this.readable.findById(id, { controls }));
311
+ }
312
+ /**
313
+ * **GET /meta** — returns table/view metadata for UI.
314
+ */ meta() {
315
+ return {
316
+ searchable: this.readable.isSearchable(),
317
+ searchIndexes: this._searchIndexes,
318
+ type: this._serializedType
319
+ };
320
+ }
321
+ constructor(readable, app) {
322
+ /** Reference to the underlying readable (table or view). */ _define_property(this, "readable", void 0);
323
+ /** Application-scoped logger. */ _define_property(this, "logger", void 0);
324
+ /** Cached serialized type definition (static, computed once). */ _define_property(this, "_serializedType", void 0);
325
+ /** Cached search index list (static, computed once). */ _define_property(this, "_searchIndexes", void 0);
326
+ _define_property(this, "_queryControlsValidator", void 0);
327
+ _define_property(this, "_pagesControlsValidator", void 0);
328
+ _define_property(this, "_getOneControlsValidator", void 0);
329
+ this.readable = readable;
330
+ this._serializedType = (0, __atscript_typescript_utils.serializeAnnotatedType)(readable.type);
331
+ this._searchIndexes = readable.getSearchIndexes();
332
+ this.logger = app.getLogger(`db [${readable.tableName}]`);
333
+ this.logger.info(`Initializing ${readable.isView ? "view" : "table"} controller`);
334
+ try {
335
+ const p = this.init();
336
+ if (p instanceof Promise) p.catch((error) => {
337
+ this.logger.error(error);
338
+ });
339
+ } catch (error) {
340
+ this.logger.error(error);
341
+ throw error;
342
+ }
343
+ }
344
+ };
345
+ _ts_decorate$1([
346
+ (0, __moostjs_event_http.Get)("query"),
347
+ _ts_param$1(0, (0, __moostjs_event_http.Url)()),
348
+ _ts_metadata$1("design:type", Function),
349
+ _ts_metadata$1("design:paramtypes", [String]),
350
+ _ts_metadata$1("design:returntype", Promise)
351
+ ], AsDbReadableController.prototype, "query", null);
352
+ _ts_decorate$1([
353
+ (0, __moostjs_event_http.Get)("pages"),
354
+ _ts_param$1(0, (0, __moostjs_event_http.Url)()),
355
+ _ts_metadata$1("design:type", Function),
356
+ _ts_metadata$1("design:paramtypes", [String]),
357
+ _ts_metadata$1("design:returntype", Promise)
358
+ ], AsDbReadableController.prototype, "pages", null);
359
+ _ts_decorate$1([
360
+ (0, __moostjs_event_http.Get)("one/:id"),
361
+ _ts_param$1(0, (0, moost.Param)("id")),
362
+ _ts_param$1(1, (0, __moostjs_event_http.Url)()),
363
+ _ts_metadata$1("design:type", Function),
364
+ _ts_metadata$1("design:paramtypes", [String, String]),
365
+ _ts_metadata$1("design:returntype", Promise)
366
+ ], AsDbReadableController.prototype, "getOne", null);
367
+ _ts_decorate$1([
368
+ (0, __moostjs_event_http.Get)("meta"),
369
+ _ts_metadata$1("design:type", Function),
370
+ _ts_metadata$1("design:paramtypes", []),
371
+ _ts_metadata$1("design:returntype", void 0)
372
+ ], AsDbReadableController.prototype, "meta", null);
373
+ AsDbReadableController = _ts_decorate$1([
374
+ UseValidationErrorTransform(),
375
+ _ts_param$1(0, (0, moost.Inject)(READABLE_DEF)),
376
+ _ts_metadata$1("design:type", Function),
377
+ _ts_metadata$1("design:paramtypes", [typeof AtscriptDbReadable === "undefined" ? Object : AtscriptDbReadable, typeof moost.Moost === "undefined" ? Object : moost.Moost])
378
+ ], AsDbReadableController);
379
+
380
+ //#endregion
381
+ //#region packages/moost-db/src/as-db.controller.ts
382
+ function _ts_decorate(decorators, target, key, desc) {
383
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
384
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
385
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
386
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
387
+ }
388
+ function _ts_metadata(k, v) {
389
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
390
+ }
391
+ function _ts_param(paramIndex, decorator) {
392
+ return function(target, key) {
393
+ decorator(target, key, paramIndex);
394
+ };
395
+ }
396
+ var AsDbController = class extends AsDbReadableController {
397
+ /** Reference to the underlying table (typed for write access). */ get table() {
398
+ return this.readable;
399
+ }
400
+ /**
401
+ * Intercepts write operations. Return `undefined` to abort.
402
+ */ onWrite(action, data) {
403
+ return data;
404
+ }
405
+ /**
406
+ * Intercepts delete operations. Return `undefined` to abort.
407
+ */ onRemove(id) {
408
+ return id;
284
409
  }
285
410
  /**
286
411
  * **POST /** — inserts one or many records.
@@ -318,61 +443,10 @@ else result = await this.table.findManyWithCount(query);
318
443
  if (result.deletedCount < 1) return new __moostjs_event_http.HttpError(404);
319
444
  return result;
320
445
  }
321
- /**
322
- * **GET /meta** — returns table metadata for UI.
323
- */ meta() {
324
- return {
325
- searchable: this.table.isSearchable(),
326
- searchIndexes: this._searchIndexes,
327
- type: this._serializedType
328
- };
329
- }
330
446
  constructor(table, app) {
331
- /** Reference to the underlying table. */ _define_property(this, "table", void 0);
332
- /** Application-scoped logger. */ _define_property(this, "logger", void 0);
333
- /** Cached serialized type definition (static, computed once). */ _define_property(this, "_serializedType", void 0);
334
- /** Cached search index list (static, computed once). */ _define_property(this, "_searchIndexes", void 0);
335
- _define_property(this, "_queryControlsValidator", void 0);
336
- _define_property(this, "_pagesControlsValidator", void 0);
337
- _define_property(this, "_getOneControlsValidator", void 0);
338
- this.table = table;
339
- this._serializedType = (0, __atscript_typescript_utils.serializeAnnotatedType)(table.type);
340
- this._searchIndexes = table.getSearchIndexes();
341
- this.logger = app.getLogger(`db [${table.tableName}]`);
342
- this.logger.info("Initializing table controller");
343
- try {
344
- const p = this.init();
345
- if (p instanceof Promise) p.catch((error) => {
346
- this.logger.error(error);
347
- });
348
- } catch (error) {
349
- this.logger.error(error);
350
- throw error;
351
- }
447
+ super(table, app);
352
448
  }
353
449
  };
354
- _ts_decorate([
355
- (0, __moostjs_event_http.Get)("query"),
356
- _ts_param(0, (0, __moostjs_event_http.Url)()),
357
- _ts_metadata("design:type", Function),
358
- _ts_metadata("design:paramtypes", [String]),
359
- _ts_metadata("design:returntype", Promise)
360
- ], AsDbController.prototype, "query", null);
361
- _ts_decorate([
362
- (0, __moostjs_event_http.Get)("pages"),
363
- _ts_param(0, (0, __moostjs_event_http.Url)()),
364
- _ts_metadata("design:type", Function),
365
- _ts_metadata("design:paramtypes", [String]),
366
- _ts_metadata("design:returntype", Promise)
367
- ], AsDbController.prototype, "pages", null);
368
- _ts_decorate([
369
- (0, __moostjs_event_http.Get)("one/:id"),
370
- _ts_param(0, (0, moost.Param)("id")),
371
- _ts_param(1, (0, __moostjs_event_http.Url)()),
372
- _ts_metadata("design:type", Function),
373
- _ts_metadata("design:paramtypes", [String, String]),
374
- _ts_metadata("design:returntype", Promise)
375
- ], AsDbController.prototype, "getOne", null);
376
450
  _ts_decorate([
377
451
  (0, __moostjs_event_http.Post)(""),
378
452
  _ts_param(0, (0, __moostjs_event_http.Body)()),
@@ -401,14 +475,8 @@ _ts_decorate([
401
475
  _ts_metadata("design:paramtypes", [String]),
402
476
  _ts_metadata("design:returntype", Promise)
403
477
  ], AsDbController.prototype, "remove", null);
404
- _ts_decorate([
405
- (0, __moostjs_event_http.Get)("meta"),
406
- _ts_metadata("design:type", Function),
407
- _ts_metadata("design:paramtypes", []),
408
- _ts_metadata("design:returntype", void 0)
409
- ], AsDbController.prototype, "meta", null);
410
478
  AsDbController = _ts_decorate([
411
- UseValidationErrorTransform(),
479
+ (0, moost.Inherit)(),
412
480
  _ts_param(0, (0, moost.Inject)(TABLE_DEF)),
413
481
  _ts_metadata("design:type", Function),
414
482
  _ts_metadata("design:paramtypes", [typeof AtscriptDbTable === "undefined" ? Object : AtscriptDbTable, typeof moost.Moost === "undefined" ? Object : moost.Moost])
@@ -421,7 +489,16 @@ Object.defineProperty(exports, 'AsDbController', {
421
489
  return AsDbController;
422
490
  }
423
491
  });
492
+ Object.defineProperty(exports, 'AsDbReadableController', {
493
+ enumerable: true,
494
+ get: function () {
495
+ return AsDbReadableController;
496
+ }
497
+ });
498
+ exports.READABLE_DEF = READABLE_DEF
499
+ exports.ReadableController = ReadableController
424
500
  exports.TABLE_DEF = TABLE_DEF
425
501
  exports.TableController = TableController
426
502
  exports.UseValidationErrorTransform = UseValidationErrorTransform
503
+ exports.ViewController = ViewController
427
504
  exports.validationErrorTransform = validationErrorTransform
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _atscript_typescript_serialize from '@atscript/typescript/serialize';
2
2
  import * as _atscript_utils_db from '@atscript/utils-db';
3
- import { AtscriptDbTable, Uniquery, FilterExpr, UniqueryControls } from '@atscript/utils-db';
3
+ import { AtscriptDbReadable, Uniquery, FilterExpr, UniqueryControls, AtscriptDbTable } from '@atscript/utils-db';
4
4
  import * as _uniqu_url from '@uniqu/url';
5
5
  import { TAtscriptAnnotatedType, TAtscriptDataType, Validator } from '@atscript/typescript/utils';
6
6
  import { HttpError } from '@moostjs/event-http';
@@ -8,27 +8,22 @@ import * as moost from 'moost';
8
8
  import { TConsoleBase, Moost } from 'moost';
9
9
 
10
10
  /**
11
- * Generic database controller for Moost that works with any `AtscriptDbTable` +
12
- * `BaseDbAdapter`. All CRUD routes through the generic table layer — no
13
- * adapter-specific imports.
11
+ * Read-only database controller for Moost that works with any `AtscriptDbReadable`
12
+ * (tables or views). Provides query, pages, getOne, and meta endpoints.
14
13
  *
15
- * Subclass and provide the table via DI:
16
- * ```ts
17
- * ‎@Provide(TABLE_DEF, () => driver.getTable(MyType))
18
- * ‎@TableController(MyType)
19
- * export class MyController extends AsDbController<typeof MyType> {}
20
- * ```
14
+ * For write operations (insert, replace, update, delete), use {@link AsDbController}.
15
+ * For views, use {@link AsDbViewController}.
21
16
  */
22
- declare class AsDbController<T extends TAtscriptAnnotatedType = TAtscriptAnnotatedType, DataType = TAtscriptDataType<T>> {
23
- /** Reference to the underlying table. */
24
- protected table: AtscriptDbTable<T>;
17
+ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscriptAnnotatedType, DataType = TAtscriptDataType<T>> {
18
+ /** Reference to the underlying readable (table or view). */
19
+ protected readable: AtscriptDbReadable<T>;
25
20
  /** Application-scoped logger. */
26
21
  protected logger: TConsoleBase;
27
22
  /** Cached serialized type definition (static, computed once). */
28
23
  private _serializedType;
29
24
  /** Cached search index list (static, computed once). */
30
25
  private _searchIndexes;
31
- constructor(table: AtscriptDbTable<T>, app: Moost);
26
+ constructor(readable: AtscriptDbReadable<T>, app: Moost);
32
27
  /**
33
28
  * One-time initialization hook. Override to seed data, register watchers, etc.
34
29
  */
@@ -50,14 +45,6 @@ declare class AsDbController<T extends TAtscriptAnnotatedType = TAtscriptAnnotat
50
45
  * Transform projection before querying.
51
46
  */
52
47
  protected transformProjection(projection?: UniqueryControls['$select']): UniqueryControls['$select'] | undefined;
53
- /**
54
- * Intercepts write operations. Return `undefined` to abort.
55
- */
56
- protected onWrite(action: 'insert' | 'insertMany' | 'replace' | 'update', data: unknown): unknown | Promise<unknown | undefined>;
57
- /**
58
- * Intercepts delete operations. Return `undefined` to abort.
59
- */
60
- protected onRemove(id: unknown): unknown | Promise<unknown | undefined>;
61
48
  protected parseQueryString(url: string): _uniqu_url.UrlQuery;
62
49
  protected returnOne(result: Promise<DataType | null>): Promise<DataType | HttpError>;
63
50
  /**
@@ -78,6 +65,38 @@ declare class AsDbController<T extends TAtscriptAnnotatedType = TAtscriptAnnotat
78
65
  * **GET /one/:id** — retrieves a single record by ID or unique property.
79
66
  */
80
67
  getOne(id: string, url: string): Promise<DataType | HttpError>;
68
+ /**
69
+ * **GET /meta** — returns table/view metadata for UI.
70
+ */
71
+ meta(): {
72
+ searchable: boolean;
73
+ searchIndexes: _atscript_utils_db.TSearchIndexInfo[];
74
+ type: _atscript_typescript_serialize.TSerializedAnnotatedType;
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Full CRUD database controller for Moost that works with any `AtscriptDbTable` +
80
+ * `BaseDbAdapter`. Extends {@link AsDbReadableController} with write operations.
81
+ *
82
+ * Subclass and provide the table via DI:
83
+ * ```ts
84
+ * ‎@TableController(usersTable)
85
+ * export class UsersController extends AsDbController<typeof UserModel> {}
86
+ * ```
87
+ */
88
+ declare class AsDbController<T extends TAtscriptAnnotatedType = TAtscriptAnnotatedType, DataType = TAtscriptDataType<T>> extends AsDbReadableController<T, DataType> {
89
+ /** Reference to the underlying table (typed for write access). */
90
+ protected get table(): AtscriptDbTable<T>;
91
+ constructor(table: AtscriptDbTable<T>, app: Moost);
92
+ /**
93
+ * Intercepts write operations. Return `undefined` to abort.
94
+ */
95
+ protected onWrite(action: 'insert' | 'insertMany' | 'replace' | 'update', data: unknown): unknown | Promise<unknown | undefined>;
96
+ /**
97
+ * Intercepts delete operations. Return `undefined` to abort.
98
+ */
99
+ protected onRemove(id: unknown): unknown | Promise<unknown | undefined>;
81
100
  /**
82
101
  * **POST /** — inserts one or many records.
83
102
  */
@@ -94,21 +113,19 @@ declare class AsDbController<T extends TAtscriptAnnotatedType = TAtscriptAnnotat
94
113
  * **DELETE /:id** — removes a single record by primary key.
95
114
  */
96
115
  remove(id: string): Promise<HttpError | unknown>;
97
- /**
98
- * **GET /meta** — returns table metadata for UI.
99
- */
100
- meta(): {
101
- searchable: boolean;
102
- searchIndexes: _atscript_utils_db.TSearchIndexInfo[];
103
- type: _atscript_typescript_serialize.TSerializedAnnotatedType;
104
- };
105
116
  }
106
117
 
118
+ /**
119
+ * DI token under which the {@link AtscriptDbReadable} instance
120
+ * is exposed to the readable controller's constructor via `@Inject`.
121
+ */
122
+ declare const READABLE_DEF = "__atscript_db_readable_def";
107
123
  /**
108
124
  * DI token under which the {@link AtscriptDbTable} instance
109
125
  * is exposed to the controller's constructor via `@Inject`.
126
+ * Points to the same token as READABLE_DEF for backward compatibility.
110
127
  */
111
- declare const TABLE_DEF = "__atscript_db_table_def";
128
+ declare const TABLE_DEF = "__atscript_db_readable_def";
112
129
  /**
113
130
  * Combines the boilerplate needed to turn an {@link AsDbController}
114
131
  * subclass into a fully wired HTTP controller for a given `@db.table` model.
@@ -130,8 +147,32 @@ declare const TABLE_DEF = "__atscript_db_table_def";
130
147
  * ```
131
148
  */
132
149
  declare const TableController: (table: AtscriptDbTable, prefix?: string) => MethodDecorator & ClassDecorator & ParameterDecorator & PropertyDecorator;
150
+ /**
151
+ * Combines the boilerplate needed to turn an {@link AsDbReadableController}
152
+ * subclass into a fully wired HTTP controller for a given `@db.view` or `@db.table` model.
153
+ *
154
+ * @param readable The {@link AtscriptDbReadable} instance (table or view).
155
+ * @param prefix Optional route prefix. Defaults to `readable.tableName`.
156
+ *
157
+ * @example
158
+ * ```ts
159
+ * ‎@ReadableController(activeTasksView)
160
+ * export class ActiveTasksController extends AsDbReadableController<typeof ActiveTasks> {}
161
+ * ```
162
+ */
163
+ declare const ReadableController: (readable: AtscriptDbReadable, prefix?: string) => MethodDecorator & ClassDecorator & ParameterDecorator & PropertyDecorator;
164
+ /**
165
+ * Alias for {@link ReadableController} — use with view-backed controllers.
166
+ *
167
+ * @example
168
+ * ```ts
169
+ * ‎@ViewController(activeTasksView)
170
+ * export class ActiveTasksController extends AsDbReadableController<typeof ActiveTasks> {}
171
+ * ```
172
+ */
173
+ declare const ViewController: (readable: AtscriptDbReadable, prefix?: string) => MethodDecorator & ClassDecorator & ParameterDecorator & PropertyDecorator;
133
174
 
134
175
  declare const validationErrorTransform: () => moost.TInterceptorDef;
135
176
  declare const UseValidationErrorTransform: () => ClassDecorator & MethodDecorator;
136
177
 
137
- export { AsDbController, TABLE_DEF, TableController, UseValidationErrorTransform, validationErrorTransform };
178
+ export { AsDbController, AsDbReadableController, READABLE_DEF, ReadableController, TABLE_DEF, TableController, UseValidationErrorTransform, ViewController, validationErrorTransform };
package/dist/index.mjs CHANGED
@@ -4,8 +4,11 @@ import { ApplyDecorators, Controller, Inherit, Inject, Intercept, Moost, Param,
4
4
  import { parseUrl } from "@uniqu/url";
5
5
 
6
6
  //#region packages/moost-db/src/decorators.ts
7
- const TABLE_DEF = "__atscript_db_table_def";
7
+ const READABLE_DEF = "__atscript_db_readable_def";
8
+ const TABLE_DEF = READABLE_DEF;
8
9
  const TableController = (table, prefix) => ApplyDecorators(Provide(TABLE_DEF, () => table), Controller(prefix || table.tableName), Inherit());
10
+ const ReadableController = (readable, prefix) => ApplyDecorators(Provide(READABLE_DEF, () => readable), Controller(prefix || readable.tableName), Inherit());
11
+ const ViewController = ReadableController;
9
12
 
10
13
  //#endregion
11
14
  //#region packages/moost-db/src/validation-interceptor.ts
@@ -58,6 +61,33 @@ _define_property$1(GetOneControlsDto, "__is_atscript_annotated_type", true);
58
61
  _define_property$1(GetOneControlsDto, "type", {});
59
62
  _define_property$1(GetOneControlsDto, "metadata", new Map());
60
63
  _define_property$1(GetOneControlsDto, "id", "GetOneControlsDto");
64
+ let WithRelationDto = class WithRelationDto$1 {
65
+ static toJsonSchema() {
66
+ throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
67
+ }
68
+ };
69
+ _define_property$1(WithRelationDto, "__is_atscript_annotated_type", true);
70
+ _define_property$1(WithRelationDto, "type", {});
71
+ _define_property$1(WithRelationDto, "metadata", new Map());
72
+ _define_property$1(WithRelationDto, "id", "WithRelationDto");
73
+ let WithRelationControlsDto = class WithRelationControlsDto$1 {
74
+ static toJsonSchema() {
75
+ throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
76
+ }
77
+ };
78
+ _define_property$1(WithRelationControlsDto, "__is_atscript_annotated_type", true);
79
+ _define_property$1(WithRelationControlsDto, "type", {});
80
+ _define_property$1(WithRelationControlsDto, "metadata", new Map());
81
+ _define_property$1(WithRelationControlsDto, "id", "WithRelationControlsDto");
82
+ let WithFilterDto = class WithFilterDto$1 {
83
+ static toJsonSchema() {
84
+ throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
85
+ }
86
+ };
87
+ _define_property$1(WithFilterDto, "__is_atscript_annotated_type", true);
88
+ _define_property$1(WithFilterDto, "type", {});
89
+ _define_property$1(WithFilterDto, "metadata", new Map());
90
+ _define_property$1(WithFilterDto, "id", "WithFilterDto");
61
91
  let SortControlDto = class SortControlDto$1 {
62
92
  static toJsonSchema() {
63
93
  throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
@@ -76,7 +106,7 @@ _define_property$1(SelectControlDto, "__is_atscript_annotated_type", true);
76
106
  _define_property$1(SelectControlDto, "type", {});
77
107
  _define_property$1(SelectControlDto, "metadata", new Map());
78
108
  _define_property$1(SelectControlDto, "id", "SelectControlDto");
79
- defineAnnotatedType("object", QueryControlsDto).prop("$skip", defineAnnotatedType().designType("number").tags("positive", "int", "number").annotate("expect.int", true).annotate("expect.min", { minValue: 0 }).optional().$type).prop("$limit", defineAnnotatedType().designType("number").tags("positive", "int", "number").annotate("expect.int", true).annotate("expect.min", { minValue: 0 }).optional().$type).prop("$count", defineAnnotatedType().designType("boolean").tags("boolean").optional().$type).prop("$sort", defineAnnotatedType().refTo(SortControlDto).optional().$type).prop("$select", defineAnnotatedType("union").item(defineAnnotatedType().refTo(SelectControlDto).$type).item(defineAnnotatedType("array").of(defineAnnotatedType().designType("string").tags("string").$type).$type).optional().$type).prop("$search", defineAnnotatedType().designType("string").tags("string").optional().$type).prop("$index", defineAnnotatedType().designType("string").tags("string").optional().$type);
109
+ defineAnnotatedType("object", QueryControlsDto).prop("$skip", defineAnnotatedType().designType("number").tags("positive", "int", "number").annotate("expect.int", true).annotate("expect.min", { minValue: 0 }).optional().$type).prop("$limit", defineAnnotatedType().designType("number").tags("positive", "int", "number").annotate("expect.int", true).annotate("expect.min", { minValue: 0 }).optional().$type).prop("$count", defineAnnotatedType().designType("boolean").tags("boolean").optional().$type).prop("$sort", defineAnnotatedType().refTo(SortControlDto).optional().$type).prop("$select", defineAnnotatedType("union").item(defineAnnotatedType().refTo(SelectControlDto).$type).item(defineAnnotatedType("array").of(defineAnnotatedType().designType("string").tags("string").$type).$type).optional().$type).prop("$search", defineAnnotatedType().designType("string").tags("string").optional().$type).prop("$index", defineAnnotatedType().designType("string").tags("string").optional().$type).prop("$with", defineAnnotatedType("array").of(defineAnnotatedType().refTo(WithRelationDto).$type).optional().$type);
80
110
  defineAnnotatedType("object", PagesControlsDto).prop("$page", defineAnnotatedType().designType("string").tags("string").annotate("expect.pattern", {
81
111
  pattern: "^\\d+$",
82
112
  flags: "u",
@@ -85,13 +115,16 @@ defineAnnotatedType("object", PagesControlsDto).prop("$page", defineAnnotatedTyp
85
115
  pattern: "^\\d+$",
86
116
  flags: "u",
87
117
  message: "Expected positive number"
88
- }, true).optional().$type).prop("$sort", defineAnnotatedType().refTo(SortControlDto).optional().$type).prop("$select", defineAnnotatedType("union").item(defineAnnotatedType().refTo(SelectControlDto).$type).item(defineAnnotatedType("array").of(defineAnnotatedType().designType("string").tags("string").$type).$type).optional().$type).prop("$search", defineAnnotatedType().designType("string").tags("string").optional().$type).prop("$index", defineAnnotatedType().designType("string").tags("string").optional().$type);
89
- defineAnnotatedType("object", GetOneControlsDto).prop("$select", defineAnnotatedType("union").item(defineAnnotatedType().refTo(SelectControlDto).$type).item(defineAnnotatedType("array").of(defineAnnotatedType().designType("string").tags("string").$type).$type).optional().$type);
118
+ }, true).optional().$type).prop("$sort", defineAnnotatedType().refTo(SortControlDto).optional().$type).prop("$select", defineAnnotatedType("union").item(defineAnnotatedType().refTo(SelectControlDto).$type).item(defineAnnotatedType("array").of(defineAnnotatedType().designType("string").tags("string").$type).$type).optional().$type).prop("$search", defineAnnotatedType().designType("string").tags("string").optional().$type).prop("$index", defineAnnotatedType().designType("string").tags("string").optional().$type).prop("$with", defineAnnotatedType("array").of(defineAnnotatedType().refTo(WithRelationDto).$type).optional().$type);
119
+ defineAnnotatedType("object", GetOneControlsDto).prop("$select", defineAnnotatedType("union").item(defineAnnotatedType().refTo(SelectControlDto).$type).item(defineAnnotatedType("array").of(defineAnnotatedType().designType("string").tags("string").$type).$type).optional().$type).prop("$with", defineAnnotatedType("array").of(defineAnnotatedType().refTo(WithRelationDto).$type).optional().$type);
120
+ defineAnnotatedType("object", WithRelationDto).prop("name", defineAnnotatedType().designType("string").tags("string").$type).prop("filter", defineAnnotatedType().refTo(WithFilterDto).optional().$type).prop("controls", defineAnnotatedType().refTo(WithRelationControlsDto).optional().$type).prop("insights", defineAnnotatedType().refTo(WithFilterDto).optional().$type);
121
+ defineAnnotatedType("object", WithRelationControlsDto).prop("$skip", defineAnnotatedType().designType("number").tags("positive", "int", "number").annotate("expect.int", true).annotate("expect.min", { minValue: 0 }).optional().$type).prop("$limit", defineAnnotatedType().designType("number").tags("positive", "int", "number").annotate("expect.int", true).annotate("expect.min", { minValue: 0 }).optional().$type).prop("$sort", defineAnnotatedType().refTo(SortControlDto).optional().$type).prop("$select", defineAnnotatedType("union").item(defineAnnotatedType().refTo(SelectControlDto).$type).item(defineAnnotatedType("array").of(defineAnnotatedType().designType("string").tags("string").$type).$type).optional().$type).prop("$with", defineAnnotatedType("array").of(defineAnnotatedType().refTo(WithRelationDto).$type).optional().$type);
122
+ defineAnnotatedType("object", WithFilterDto).propPattern(/./, defineAnnotatedType("union").item(defineAnnotatedType().designType("string").tags("string").$type).item(defineAnnotatedType().designType("number").tags("number").$type).item(defineAnnotatedType().designType("boolean").tags("boolean").$type).item(defineAnnotatedType().designType("null").tags("null").$type).item(defineAnnotatedType().refTo(WithFilterDto).$type).item(defineAnnotatedType("array").of(defineAnnotatedType().refTo(WithFilterDto).$type).$type).$type);
90
123
  defineAnnotatedType("object", SortControlDto).propPattern(/./, defineAnnotatedType("union").item(defineAnnotatedType().designType("number").value(1).$type).item(defineAnnotatedType().designType("number").value(-1).$type).$type);
91
124
  defineAnnotatedType("object", SelectControlDto).propPattern(/./, defineAnnotatedType("union").item(defineAnnotatedType().designType("number").value(1).$type).item(defineAnnotatedType().designType("number").value(0).$type).$type);
92
125
 
93
126
  //#endregion
94
- //#region packages/moost-db/src/as-db.controller.ts
127
+ //#region packages/moost-db/src/as-db-readable.controller.ts
95
128
  function _define_property(obj, key, value) {
96
129
  if (key in obj) Object.defineProperty(obj, key, {
97
130
  value,
@@ -102,21 +135,21 @@ function _define_property(obj, key, value) {
102
135
  else obj[key] = value;
103
136
  return obj;
104
137
  }
105
- function _ts_decorate(decorators, target, key, desc) {
138
+ function _ts_decorate$1(decorators, target, key, desc) {
106
139
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
107
140
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
108
141
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
109
142
  return c > 3 && r && Object.defineProperty(target, key, r), r;
110
143
  }
111
- function _ts_metadata(k, v) {
144
+ function _ts_metadata$1(k, v) {
112
145
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
113
146
  }
114
- function _ts_param(paramIndex, decorator) {
147
+ function _ts_param$1(paramIndex, decorator) {
115
148
  return function(target, key) {
116
149
  decorator(target, key, paramIndex);
117
150
  };
118
151
  }
119
- var AsDbController = class {
152
+ var AsDbReadableController = class {
120
153
  /**
121
154
  * One-time initialization hook. Override to seed data, register watchers, etc.
122
155
  */ init() {}
@@ -138,7 +171,7 @@ var AsDbController = class {
138
171
  return undefined;
139
172
  }
140
173
  validateInsights(insights) {
141
- for (const key of insights.keys()) if (!this.table.flatMap.has(key)) return `Unknown field "${key}"`;
174
+ for (const key of insights.keys()) if (!this.readable.flatMap.has(key)) return `Unknown field "${key}"`;
142
175
  return undefined;
143
176
  }
144
177
  validateParsed(parsed, type) {
@@ -160,16 +193,6 @@ var AsDbController = class {
160
193
  */ transformProjection(projection) {
161
194
  return projection;
162
195
  }
163
- /**
164
- * Intercepts write operations. Return `undefined` to abort.
165
- */ onWrite(action, data) {
166
- return data;
167
- }
168
- /**
169
- * Intercepts delete operations. Return `undefined` to abort.
170
- */ onRemove(id) {
171
- return id;
172
- }
173
196
  parseQueryString(url) {
174
197
  const idx = url.indexOf("?");
175
198
  return parseUrl(idx >= 0 ? url.slice(idx + 1) : "");
@@ -188,7 +211,7 @@ var AsDbController = class {
188
211
  const controls = parsed.controls;
189
212
  const filter = this.transformFilter(parsed.filter);
190
213
  const select = this.transformProjection(controls.$select);
191
- if (controls.$count) return this.table.count({
214
+ if (controls.$count) return this.readable.count({
192
215
  filter,
193
216
  controls: {
194
217
  ...controls,
@@ -197,7 +220,7 @@ var AsDbController = class {
197
220
  });
198
221
  const searchTerm = controls.$search;
199
222
  const indexName = controls.$index;
200
- if (searchTerm && this.table.isSearchable()) return this.table.search(searchTerm, {
223
+ if (searchTerm && this.readable.isSearchable()) return this.readable.search(searchTerm, {
201
224
  filter,
202
225
  controls: {
203
226
  ...controls,
@@ -205,7 +228,7 @@ var AsDbController = class {
205
228
  $limit: controls.$limit || 1e3
206
229
  }
207
230
  }, indexName);
208
- return this.table.findMany({
231
+ return this.readable.findMany({
209
232
  filter,
210
233
  controls: {
211
234
  ...controls,
@@ -238,8 +261,8 @@ var AsDbController = class {
238
261
  }
239
262
  };
240
263
  let result;
241
- if (searchTerm && this.table.isSearchable()) result = await this.table.searchWithCount(searchTerm, query, indexName);
242
- else result = await this.table.findManyWithCount(query);
264
+ if (searchTerm && this.readable.isSearchable()) result = await this.readable.searchWithCount(searchTerm, query, indexName);
265
+ else result = await this.readable.findManyWithCount(query);
243
266
  return {
244
267
  data: result.data,
245
268
  page,
@@ -256,7 +279,109 @@ else result = await this.table.findManyWithCount(query);
256
279
  const error = this.validateParsed(parsed, "getOne");
257
280
  if (error) return error;
258
281
  const select = this.transformProjection(parsed.controls.$select);
259
- return this.returnOne(this.table.findById(id, { $select: select }));
282
+ const controls = {
283
+ ...parsed.controls,
284
+ $select: select
285
+ };
286
+ return this.returnOne(this.readable.findById(id, { controls }));
287
+ }
288
+ /**
289
+ * **GET /meta** — returns table/view metadata for UI.
290
+ */ meta() {
291
+ return {
292
+ searchable: this.readable.isSearchable(),
293
+ searchIndexes: this._searchIndexes,
294
+ type: this._serializedType
295
+ };
296
+ }
297
+ constructor(readable, app) {
298
+ /** Reference to the underlying readable (table or view). */ _define_property(this, "readable", void 0);
299
+ /** Application-scoped logger. */ _define_property(this, "logger", void 0);
300
+ /** Cached serialized type definition (static, computed once). */ _define_property(this, "_serializedType", void 0);
301
+ /** Cached search index list (static, computed once). */ _define_property(this, "_searchIndexes", void 0);
302
+ _define_property(this, "_queryControlsValidator", void 0);
303
+ _define_property(this, "_pagesControlsValidator", void 0);
304
+ _define_property(this, "_getOneControlsValidator", void 0);
305
+ this.readable = readable;
306
+ this._serializedType = serializeAnnotatedType(readable.type);
307
+ this._searchIndexes = readable.getSearchIndexes();
308
+ this.logger = app.getLogger(`db [${readable.tableName}]`);
309
+ this.logger.info(`Initializing ${readable.isView ? "view" : "table"} controller`);
310
+ try {
311
+ const p = this.init();
312
+ if (p instanceof Promise) p.catch((error) => {
313
+ this.logger.error(error);
314
+ });
315
+ } catch (error) {
316
+ this.logger.error(error);
317
+ throw error;
318
+ }
319
+ }
320
+ };
321
+ _ts_decorate$1([
322
+ Get("query"),
323
+ _ts_param$1(0, Url()),
324
+ _ts_metadata$1("design:type", Function),
325
+ _ts_metadata$1("design:paramtypes", [String]),
326
+ _ts_metadata$1("design:returntype", Promise)
327
+ ], AsDbReadableController.prototype, "query", null);
328
+ _ts_decorate$1([
329
+ Get("pages"),
330
+ _ts_param$1(0, Url()),
331
+ _ts_metadata$1("design:type", Function),
332
+ _ts_metadata$1("design:paramtypes", [String]),
333
+ _ts_metadata$1("design:returntype", Promise)
334
+ ], AsDbReadableController.prototype, "pages", null);
335
+ _ts_decorate$1([
336
+ Get("one/:id"),
337
+ _ts_param$1(0, Param("id")),
338
+ _ts_param$1(1, Url()),
339
+ _ts_metadata$1("design:type", Function),
340
+ _ts_metadata$1("design:paramtypes", [String, String]),
341
+ _ts_metadata$1("design:returntype", Promise)
342
+ ], AsDbReadableController.prototype, "getOne", null);
343
+ _ts_decorate$1([
344
+ Get("meta"),
345
+ _ts_metadata$1("design:type", Function),
346
+ _ts_metadata$1("design:paramtypes", []),
347
+ _ts_metadata$1("design:returntype", void 0)
348
+ ], AsDbReadableController.prototype, "meta", null);
349
+ AsDbReadableController = _ts_decorate$1([
350
+ UseValidationErrorTransform(),
351
+ _ts_param$1(0, Inject(READABLE_DEF)),
352
+ _ts_metadata$1("design:type", Function),
353
+ _ts_metadata$1("design:paramtypes", [typeof AtscriptDbReadable === "undefined" ? Object : AtscriptDbReadable, typeof Moost === "undefined" ? Object : Moost])
354
+ ], AsDbReadableController);
355
+
356
+ //#endregion
357
+ //#region packages/moost-db/src/as-db.controller.ts
358
+ function _ts_decorate(decorators, target, key, desc) {
359
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
360
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
361
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
362
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
363
+ }
364
+ function _ts_metadata(k, v) {
365
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
366
+ }
367
+ function _ts_param(paramIndex, decorator) {
368
+ return function(target, key) {
369
+ decorator(target, key, paramIndex);
370
+ };
371
+ }
372
+ var AsDbController = class extends AsDbReadableController {
373
+ /** Reference to the underlying table (typed for write access). */ get table() {
374
+ return this.readable;
375
+ }
376
+ /**
377
+ * Intercepts write operations. Return `undefined` to abort.
378
+ */ onWrite(action, data) {
379
+ return data;
380
+ }
381
+ /**
382
+ * Intercepts delete operations. Return `undefined` to abort.
383
+ */ onRemove(id) {
384
+ return id;
260
385
  }
261
386
  /**
262
387
  * **POST /** — inserts one or many records.
@@ -294,61 +419,10 @@ else result = await this.table.findManyWithCount(query);
294
419
  if (result.deletedCount < 1) return new HttpError(404);
295
420
  return result;
296
421
  }
297
- /**
298
- * **GET /meta** — returns table metadata for UI.
299
- */ meta() {
300
- return {
301
- searchable: this.table.isSearchable(),
302
- searchIndexes: this._searchIndexes,
303
- type: this._serializedType
304
- };
305
- }
306
422
  constructor(table, app) {
307
- /** Reference to the underlying table. */ _define_property(this, "table", void 0);
308
- /** Application-scoped logger. */ _define_property(this, "logger", void 0);
309
- /** Cached serialized type definition (static, computed once). */ _define_property(this, "_serializedType", void 0);
310
- /** Cached search index list (static, computed once). */ _define_property(this, "_searchIndexes", void 0);
311
- _define_property(this, "_queryControlsValidator", void 0);
312
- _define_property(this, "_pagesControlsValidator", void 0);
313
- _define_property(this, "_getOneControlsValidator", void 0);
314
- this.table = table;
315
- this._serializedType = serializeAnnotatedType(table.type);
316
- this._searchIndexes = table.getSearchIndexes();
317
- this.logger = app.getLogger(`db [${table.tableName}]`);
318
- this.logger.info("Initializing table controller");
319
- try {
320
- const p = this.init();
321
- if (p instanceof Promise) p.catch((error) => {
322
- this.logger.error(error);
323
- });
324
- } catch (error) {
325
- this.logger.error(error);
326
- throw error;
327
- }
423
+ super(table, app);
328
424
  }
329
425
  };
330
- _ts_decorate([
331
- Get("query"),
332
- _ts_param(0, Url()),
333
- _ts_metadata("design:type", Function),
334
- _ts_metadata("design:paramtypes", [String]),
335
- _ts_metadata("design:returntype", Promise)
336
- ], AsDbController.prototype, "query", null);
337
- _ts_decorate([
338
- Get("pages"),
339
- _ts_param(0, Url()),
340
- _ts_metadata("design:type", Function),
341
- _ts_metadata("design:paramtypes", [String]),
342
- _ts_metadata("design:returntype", Promise)
343
- ], AsDbController.prototype, "pages", null);
344
- _ts_decorate([
345
- Get("one/:id"),
346
- _ts_param(0, Param("id")),
347
- _ts_param(1, Url()),
348
- _ts_metadata("design:type", Function),
349
- _ts_metadata("design:paramtypes", [String, String]),
350
- _ts_metadata("design:returntype", Promise)
351
- ], AsDbController.prototype, "getOne", null);
352
426
  _ts_decorate([
353
427
  Post(""),
354
428
  _ts_param(0, Body()),
@@ -377,18 +451,12 @@ _ts_decorate([
377
451
  _ts_metadata("design:paramtypes", [String]),
378
452
  _ts_metadata("design:returntype", Promise)
379
453
  ], AsDbController.prototype, "remove", null);
380
- _ts_decorate([
381
- Get("meta"),
382
- _ts_metadata("design:type", Function),
383
- _ts_metadata("design:paramtypes", []),
384
- _ts_metadata("design:returntype", void 0)
385
- ], AsDbController.prototype, "meta", null);
386
454
  AsDbController = _ts_decorate([
387
- UseValidationErrorTransform(),
455
+ Inherit(),
388
456
  _ts_param(0, Inject(TABLE_DEF)),
389
457
  _ts_metadata("design:type", Function),
390
458
  _ts_metadata("design:paramtypes", [typeof AtscriptDbTable === "undefined" ? Object : AtscriptDbTable, typeof Moost === "undefined" ? Object : Moost])
391
459
  ], AsDbController);
392
460
 
393
461
  //#endregion
394
- export { AsDbController, TABLE_DEF, TableController, UseValidationErrorTransform, validationErrorTransform };
462
+ export { AsDbController, AsDbReadableController, READABLE_DEF, ReadableController, TABLE_DEF, TableController, UseValidationErrorTransform, ViewController, validationErrorTransform };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/moost-db",
3
- "version": "0.1.33",
3
+ "version": "0.1.35",
4
4
  "description": "Generic database controller for Moost with Atscript.",
5
5
  "keywords": [
6
6
  "annotations",
@@ -13,7 +13,7 @@
13
13
  "bugs": {
14
14
  "url": "https://github.com/moostjs/atscript/issues"
15
15
  },
16
- "license": "ISC",
16
+ "license": "MIT",
17
17
  "author": "Artem Maltsev",
18
18
  "repository": {
19
19
  "type": "git",
@@ -35,20 +35,20 @@
35
35
  "./package.json": "./package.json"
36
36
  },
37
37
  "dependencies": {
38
- "@uniqu/url": "^0.0.1"
38
+ "@uniqu/url": "^0.0.5"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@moostjs/event-http": "^0.6.2",
42
42
  "moost": "^0.6.2",
43
43
  "vitest": "3.2.4",
44
- "@atscript/core": "^0.1.33"
44
+ "@atscript/core": "^0.1.35"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "@moostjs/event-http": "^0.6.2",
48
48
  "moost": "^0.6.2",
49
- "@uniqu/core": "^0.0.2",
50
- "@atscript/utils-db": "^0.1.33",
51
- "@atscript/typescript": "^0.1.33"
49
+ "@uniqu/core": "^0.0.5",
50
+ "@atscript/utils-db": "^0.1.35",
51
+ "@atscript/typescript": "^0.1.35"
52
52
  },
53
53
  "scripts": {
54
54
  "pub": "pnpm publish --access public",