@atscript/moost-db 0.1.39 → 0.1.41
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 -6
- package/dist/index.cjs +329 -317
- package/dist/index.d.cts +204 -0
- package/dist/index.d.mts +204 -0
- package/dist/index.mjs +263 -228
- package/package.json +21 -14
- package/LICENSE +0 -21
- package/dist/index.d.ts +0 -200
package/dist/index.mjs
CHANGED
|
@@ -3,16 +3,65 @@ import { Body, Delete, Get, HttpError, Patch, Post, Put, Query, Url } from "@moo
|
|
|
3
3
|
import { ApplyDecorators, Controller, Inherit, Inject, Intercept, Moost, Param, Provide, TInterceptorPriority, defineInterceptor } from "moost";
|
|
4
4
|
import { parseUrl } from "@uniqu/url";
|
|
5
5
|
import { DbError } from "@atscript/db";
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
//#region src/decorators.ts
|
|
7
|
+
/**
|
|
8
|
+
* DI token under which the {@link AtscriptDbReadable} instance
|
|
9
|
+
* is exposed to the readable controller's constructor via `@Inject`.
|
|
10
|
+
*/
|
|
8
11
|
const READABLE_DEF = "__atscript_db_readable_def";
|
|
12
|
+
/**
|
|
13
|
+
* DI token under which the {@link AtscriptDbTable} instance
|
|
14
|
+
* is exposed to the controller's constructor via `@Inject`.
|
|
15
|
+
* Points to the same token as READABLE_DEF for backward compatibility.
|
|
16
|
+
*/
|
|
9
17
|
const TABLE_DEF = READABLE_DEF;
|
|
18
|
+
/**
|
|
19
|
+
* Combines the boilerplate needed to turn an {@link AsDbController}
|
|
20
|
+
* subclass into a fully wired HTTP controller for a given `@db.table` model.
|
|
21
|
+
*
|
|
22
|
+
* Internally applies three decorators:
|
|
23
|
+
* 1. **Provide** — registers the table instance under {@link TABLE_DEF}.
|
|
24
|
+
* 2. **Controller** — registers the class as a Moost HTTP controller
|
|
25
|
+
* with an optional route prefix. Defaults to `table.tableName`.
|
|
26
|
+
* 3. **Inherit** — copies metadata (routes, guards, etc.) from the
|
|
27
|
+
* parent class so they stay active in the derived controller.
|
|
28
|
+
*
|
|
29
|
+
* @param table The {@link AtscriptDbTable} instance for this controller.
|
|
30
|
+
* @param prefix Optional route prefix. Defaults to `table.tableName`.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* @TableController(usersTable)
|
|
35
|
+
* export class UsersController extends AsDbController<typeof UserModel> {}
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
10
38
|
const TableController = (table, prefix) => ApplyDecorators(Provide(TABLE_DEF, () => table), Controller(prefix || table.tableName), Inherit());
|
|
39
|
+
/**
|
|
40
|
+
* Combines the boilerplate needed to turn an {@link AsDbReadableController}
|
|
41
|
+
* subclass into a fully wired HTTP controller for a given `@db.view` or `@db.table` model.
|
|
42
|
+
*
|
|
43
|
+
* @param readable The {@link AtscriptDbReadable} instance (table or view).
|
|
44
|
+
* @param prefix Optional route prefix. Defaults to `readable.tableName`.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* @ReadableController(activeTasksView)
|
|
49
|
+
* export class ActiveTasksController extends AsDbReadableController<typeof ActiveTasks> {}
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
11
52
|
const ReadableController = (readable, prefix) => ApplyDecorators(Provide(READABLE_DEF, () => readable), Controller(prefix || readable.tableName), Inherit());
|
|
53
|
+
/**
|
|
54
|
+
* Alias for {@link ReadableController} — use with view-backed controllers.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* @ViewController(activeTasksView)
|
|
59
|
+
* export class ActiveTasksController extends AsDbReadableController<typeof ActiveTasks> {}
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
12
62
|
const ViewController = ReadableController;
|
|
13
|
-
|
|
14
63
|
//#endregion
|
|
15
|
-
//#region
|
|
64
|
+
//#region src/validation-interceptor.ts
|
|
16
65
|
const dbErrorCodeToStatus = { CONFLICT: 409 };
|
|
17
66
|
function transformValidationError(error, reply) {
|
|
18
67
|
if (error instanceof ValidatorError) reply(new HttpError(400, {
|
|
@@ -20,7 +69,7 @@ function transformValidationError(error, reply) {
|
|
|
20
69
|
statusCode: 400,
|
|
21
70
|
errors: error.errors
|
|
22
71
|
}));
|
|
23
|
-
else if (error instanceof DbError) {
|
|
72
|
+
else if (error instanceof DbError) {
|
|
24
73
|
const statusCode = dbErrorCodeToStatus[error.code] ?? 400;
|
|
25
74
|
reply(new HttpError(statusCode, {
|
|
26
75
|
message: error.message,
|
|
@@ -31,91 +80,80 @@ else if (error instanceof DbError) {
|
|
|
31
80
|
}
|
|
32
81
|
const validationErrorTransform = () => defineInterceptor({ error: transformValidationError }, TInterceptorPriority.CATCH_ERROR);
|
|
33
82
|
const UseValidationErrorTransform = () => Intercept(validationErrorTransform());
|
|
34
|
-
|
|
35
83
|
//#endregion
|
|
36
|
-
//#region
|
|
37
|
-
function _define_property$1(obj, key, value) {
|
|
38
|
-
if (key in obj) Object.defineProperty(obj, key, {
|
|
39
|
-
value,
|
|
40
|
-
enumerable: true,
|
|
41
|
-
configurable: true,
|
|
42
|
-
writable: true
|
|
43
|
-
});
|
|
44
|
-
else obj[key] = value;
|
|
45
|
-
return obj;
|
|
46
|
-
}
|
|
84
|
+
//#region src/dto/controls.dto.as
|
|
47
85
|
var QueryControlsDto = class {
|
|
86
|
+
static __is_atscript_annotated_type = true;
|
|
87
|
+
static type = {};
|
|
88
|
+
static metadata = /* @__PURE__ */ new Map();
|
|
89
|
+
static id = "QueryControlsDto";
|
|
48
90
|
static toJsonSchema() {
|
|
49
91
|
throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
|
|
50
92
|
}
|
|
51
93
|
};
|
|
52
|
-
_define_property$1(QueryControlsDto, "__is_atscript_annotated_type", true);
|
|
53
|
-
_define_property$1(QueryControlsDto, "type", {});
|
|
54
|
-
_define_property$1(QueryControlsDto, "metadata", new Map());
|
|
55
|
-
_define_property$1(QueryControlsDto, "id", "QueryControlsDto");
|
|
56
94
|
var PagesControlsDto = class {
|
|
95
|
+
static __is_atscript_annotated_type = true;
|
|
96
|
+
static type = {};
|
|
97
|
+
static metadata = /* @__PURE__ */ new Map();
|
|
98
|
+
static id = "PagesControlsDto";
|
|
57
99
|
static toJsonSchema() {
|
|
58
100
|
throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
|
|
59
101
|
}
|
|
60
102
|
};
|
|
61
|
-
_define_property$1(PagesControlsDto, "__is_atscript_annotated_type", true);
|
|
62
|
-
_define_property$1(PagesControlsDto, "type", {});
|
|
63
|
-
_define_property$1(PagesControlsDto, "metadata", new Map());
|
|
64
|
-
_define_property$1(PagesControlsDto, "id", "PagesControlsDto");
|
|
65
103
|
var GetOneControlsDto = class {
|
|
104
|
+
static __is_atscript_annotated_type = true;
|
|
105
|
+
static type = {};
|
|
106
|
+
static metadata = /* @__PURE__ */ new Map();
|
|
107
|
+
static id = "GetOneControlsDto";
|
|
66
108
|
static toJsonSchema() {
|
|
67
109
|
throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
|
|
68
110
|
}
|
|
69
111
|
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
112
|
+
var WithRelationDto = class {
|
|
113
|
+
static __is_atscript_annotated_type = true;
|
|
114
|
+
static type = {};
|
|
115
|
+
static metadata = /* @__PURE__ */ new Map();
|
|
116
|
+
static id = "WithRelationDto";
|
|
75
117
|
static toJsonSchema() {
|
|
76
118
|
throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
|
|
77
119
|
}
|
|
78
120
|
};
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
121
|
+
var WithRelationControlsDto = class {
|
|
122
|
+
static __is_atscript_annotated_type = true;
|
|
123
|
+
static type = {};
|
|
124
|
+
static metadata = /* @__PURE__ */ new Map();
|
|
125
|
+
static id = "WithRelationControlsDto";
|
|
84
126
|
static toJsonSchema() {
|
|
85
127
|
throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
|
|
86
128
|
}
|
|
87
129
|
};
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
130
|
+
var WithFilterDto = class {
|
|
131
|
+
static __is_atscript_annotated_type = true;
|
|
132
|
+
static type = {};
|
|
133
|
+
static metadata = /* @__PURE__ */ new Map();
|
|
134
|
+
static id = "WithFilterDto";
|
|
93
135
|
static toJsonSchema() {
|
|
94
136
|
throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
|
|
95
137
|
}
|
|
96
138
|
};
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
139
|
+
var SortControlDto = class {
|
|
140
|
+
static __is_atscript_annotated_type = true;
|
|
141
|
+
static type = {};
|
|
142
|
+
static metadata = /* @__PURE__ */ new Map();
|
|
143
|
+
static id = "SortControlDto";
|
|
102
144
|
static toJsonSchema() {
|
|
103
145
|
throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
|
|
104
146
|
}
|
|
105
147
|
};
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
148
|
+
var SelectControlDto = class {
|
|
149
|
+
static __is_atscript_annotated_type = true;
|
|
150
|
+
static type = {};
|
|
151
|
+
static metadata = /* @__PURE__ */ new Map();
|
|
152
|
+
static id = "SelectControlDto";
|
|
111
153
|
static toJsonSchema() {
|
|
112
154
|
throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
|
|
113
155
|
}
|
|
114
156
|
};
|
|
115
|
-
_define_property$1(SelectControlDto, "__is_atscript_annotated_type", true);
|
|
116
|
-
_define_property$1(SelectControlDto, "type", {});
|
|
117
|
-
_define_property$1(SelectControlDto, "metadata", new Map());
|
|
118
|
-
_define_property$1(SelectControlDto, "id", "SelectControlDto");
|
|
119
157
|
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("$vector", defineAnnotatedType().designType("string").tags("string").optional().$type).prop("$threshold", defineAnnotatedType().designType("string").tags("string").optional().$type).prop("$with", defineAnnotatedType("array").of(defineAnnotatedType().refTo(WithRelationDto).$type).optional().$type);
|
|
120
158
|
defineAnnotatedType("object", PagesControlsDto).prop("$page", defineAnnotatedType().designType("string").tags("string").annotate("expect.pattern", {
|
|
121
159
|
pattern: "^\\d+$",
|
|
@@ -132,37 +170,61 @@ defineAnnotatedType("object", WithRelationControlsDto).prop("$skip", defineAnnot
|
|
|
132
170
|
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);
|
|
133
171
|
defineAnnotatedType("object", SortControlDto).propPattern(/./, defineAnnotatedType("union").item(defineAnnotatedType().designType("number").value(1).$type).item(defineAnnotatedType().designType("number").value(-1).$type).$type);
|
|
134
172
|
defineAnnotatedType("object", SelectControlDto).propPattern(/./, defineAnnotatedType("union").item(defineAnnotatedType().designType("number").value(1).$type).item(defineAnnotatedType().designType("number").value(0).$type).$type);
|
|
135
|
-
|
|
136
173
|
//#endregion
|
|
137
|
-
//#region
|
|
138
|
-
function
|
|
139
|
-
if (key in obj) Object.defineProperty(obj, key, {
|
|
140
|
-
value,
|
|
141
|
-
enumerable: true,
|
|
142
|
-
configurable: true,
|
|
143
|
-
writable: true
|
|
144
|
-
});
|
|
145
|
-
else obj[key] = value;
|
|
146
|
-
return obj;
|
|
147
|
-
}
|
|
148
|
-
function _ts_decorate$1(decorators, target, key, desc) {
|
|
149
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
150
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
151
|
-
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;
|
|
152
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
153
|
-
}
|
|
154
|
-
function _ts_metadata$1(k, v) {
|
|
174
|
+
//#region \0@oxc-project+runtime@0.115.0/helpers/decorateMetadata.js
|
|
175
|
+
function __decorateMetadata(k, v) {
|
|
155
176
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
156
177
|
}
|
|
157
|
-
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region \0@oxc-project+runtime@0.115.0/helpers/decorateParam.js
|
|
180
|
+
function __decorateParam(paramIndex, decorator) {
|
|
158
181
|
return function(target, key) {
|
|
159
182
|
decorator(target, key, paramIndex);
|
|
160
183
|
};
|
|
161
184
|
}
|
|
162
|
-
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region \0@oxc-project+runtime@0.115.0/helpers/decorate.js
|
|
187
|
+
function __decorate(decorators, target, key, desc) {
|
|
188
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
189
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
190
|
+
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;
|
|
191
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region src/as-db-readable.controller.ts
|
|
195
|
+
var _ref$1, _ref2$1;
|
|
196
|
+
let AsDbReadableController = class AsDbReadableController {
|
|
197
|
+
/** Reference to the underlying readable (table or view). */
|
|
198
|
+
readable;
|
|
199
|
+
/** Application-scoped logger. */
|
|
200
|
+
logger;
|
|
201
|
+
/** Cached serialized type definition (static, computed once). */
|
|
202
|
+
_serializedType;
|
|
203
|
+
/** Cached search index list (static, computed once). */
|
|
204
|
+
_searchIndexes;
|
|
205
|
+
constructor(readable, app) {
|
|
206
|
+
this.readable = readable;
|
|
207
|
+
this._serializedType = serializeAnnotatedType(readable.type);
|
|
208
|
+
this._searchIndexes = readable.getSearchIndexes();
|
|
209
|
+
this.logger = app.getLogger(`db [${readable.tableName}]`);
|
|
210
|
+
this.logger.info(`Initializing ${readable.isView ? "view" : "table"} controller`);
|
|
211
|
+
try {
|
|
212
|
+
const p = this.init();
|
|
213
|
+
if (p instanceof Promise) p.catch((error) => {
|
|
214
|
+
this.logger.error(error);
|
|
215
|
+
});
|
|
216
|
+
} catch (error) {
|
|
217
|
+
this.logger.error(error);
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
163
221
|
/**
|
|
164
222
|
* One-time initialization hook. Override to seed data, register watchers, etc.
|
|
165
|
-
*/
|
|
223
|
+
*/
|
|
224
|
+
init() {}
|
|
225
|
+
_queryControlsValidator;
|
|
226
|
+
_pagesControlsValidator;
|
|
227
|
+
_getOneControlsValidator;
|
|
166
228
|
get queryControlsValidator() {
|
|
167
229
|
if (!this._queryControlsValidator) this._queryControlsValidator = QueryControlsDto.validator();
|
|
168
230
|
return this._queryControlsValidator;
|
|
@@ -178,14 +240,12 @@ var AsDbReadableController = class {
|
|
|
178
240
|
validateControls(controls, type) {
|
|
179
241
|
const v = type === "query" ? this.queryControlsValidator : type === "pages" ? this.pagesControlsValidator : this.getOneControlsValidator;
|
|
180
242
|
if (!v.validate(controls, true)) return v.errors[0]?.message || "Invalid controls";
|
|
181
|
-
return undefined;
|
|
182
243
|
}
|
|
183
244
|
validateInsights(insights) {
|
|
184
245
|
for (const [key] of insights) {
|
|
185
246
|
if (key === "*") continue;
|
|
186
247
|
if (!this.readable.flatMap.has(key)) return `Unknown field "${key}"`;
|
|
187
248
|
}
|
|
188
|
-
return undefined;
|
|
189
249
|
}
|
|
190
250
|
validateParsed(parsed, type) {
|
|
191
251
|
const controlsError = this.validateControls(parsed.controls, type);
|
|
@@ -206,23 +266,25 @@ var AsDbReadableController = class {
|
|
|
206
266
|
}]
|
|
207
267
|
});
|
|
208
268
|
}
|
|
209
|
-
return undefined;
|
|
210
269
|
}
|
|
211
270
|
/**
|
|
212
271
|
* Compute an embedding vector from a search term.
|
|
213
272
|
* Override in subclass to integrate with your embedding provider (OpenAI, etc.).
|
|
214
273
|
* Called when `$vector` is present in query controls.
|
|
215
|
-
*/
|
|
274
|
+
*/
|
|
275
|
+
computeEmbedding(_search, _fieldName) {
|
|
216
276
|
throw new HttpError(501, "Vector search requires computeEmbedding() to be implemented");
|
|
217
277
|
}
|
|
218
278
|
/**
|
|
219
279
|
* Transform filter before querying. Override to add tenant filtering, etc.
|
|
220
|
-
*/
|
|
280
|
+
*/
|
|
281
|
+
transformFilter(filter) {
|
|
221
282
|
return filter;
|
|
222
283
|
}
|
|
223
284
|
/**
|
|
224
285
|
* Transform projection before querying.
|
|
225
|
-
*/
|
|
286
|
+
*/
|
|
287
|
+
transformProjection(projection) {
|
|
226
288
|
return projection;
|
|
227
289
|
}
|
|
228
290
|
parseQueryString(url) {
|
|
@@ -237,13 +299,14 @@ var AsDbReadableController = class {
|
|
|
237
299
|
/**
|
|
238
300
|
* Extracts a composite identifier object from query params.
|
|
239
301
|
* Tries composite primary key first, then compound unique indexes.
|
|
240
|
-
*/
|
|
302
|
+
*/
|
|
303
|
+
extractCompositeId(query) {
|
|
241
304
|
const pkFields = this.readable.primaryKeys;
|
|
242
305
|
if (pkFields.length > 1) {
|
|
243
306
|
const idObj = {};
|
|
244
307
|
let allPresent = true;
|
|
245
308
|
for (const field of pkFields) {
|
|
246
|
-
if (query[field] ===
|
|
309
|
+
if (query[field] === void 0) {
|
|
247
310
|
allPresent = false;
|
|
248
311
|
break;
|
|
249
312
|
}
|
|
@@ -256,7 +319,7 @@ var AsDbReadableController = class {
|
|
|
256
319
|
const idObj = {};
|
|
257
320
|
let allPresent = true;
|
|
258
321
|
for (const indexField of index.fields) {
|
|
259
|
-
if (query[indexField.name] ===
|
|
322
|
+
if (query[indexField.name] === void 0) {
|
|
260
323
|
allPresent = false;
|
|
261
324
|
break;
|
|
262
325
|
}
|
|
@@ -268,19 +331,19 @@ var AsDbReadableController = class {
|
|
|
268
331
|
}
|
|
269
332
|
/**
|
|
270
333
|
* **GET /query** — returns an array of records or a count.
|
|
271
|
-
*/
|
|
334
|
+
*/
|
|
335
|
+
async query(url) {
|
|
272
336
|
const parsed = this.parseQueryString(url);
|
|
273
337
|
const controls = parsed.controls;
|
|
274
|
-
|
|
275
|
-
if (groupBy?.length) {
|
|
338
|
+
if (controls.$groupBy?.length) {
|
|
276
339
|
if (controls.$with?.length) return new HttpError(400, "Cannot combine $with and $groupBy in the same query");
|
|
277
340
|
if (parsed.insights) {
|
|
278
341
|
const insightsError = this.validateInsights(parsed.insights);
|
|
279
342
|
if (insightsError) return new HttpError(400, insightsError);
|
|
280
343
|
}
|
|
281
|
-
const filter
|
|
344
|
+
const filter = this.transformFilter(parsed.filter);
|
|
282
345
|
return this.readable.aggregate({
|
|
283
|
-
filter
|
|
346
|
+
filter,
|
|
284
347
|
controls,
|
|
285
348
|
insights: parsed.insights
|
|
286
349
|
});
|
|
@@ -299,7 +362,7 @@ var AsDbReadableController = class {
|
|
|
299
362
|
const searchTerm = controls.$search;
|
|
300
363
|
const indexName = controls.$index;
|
|
301
364
|
const vectorField = controls.$vector;
|
|
302
|
-
const threshold = controls.$threshold ? Number(controls.$threshold) :
|
|
365
|
+
const threshold = controls.$threshold ? Number(controls.$threshold) : void 0;
|
|
303
366
|
const queryObj = {
|
|
304
367
|
filter,
|
|
305
368
|
controls: {
|
|
@@ -309,8 +372,8 @@ var AsDbReadableController = class {
|
|
|
309
372
|
$threshold: threshold
|
|
310
373
|
}
|
|
311
374
|
};
|
|
312
|
-
if (vectorField !==
|
|
313
|
-
const vector = await this.computeEmbedding(searchTerm, vectorField ||
|
|
375
|
+
if (vectorField !== void 0 && searchTerm) {
|
|
376
|
+
const vector = await this.computeEmbedding(searchTerm, vectorField || void 0);
|
|
314
377
|
if (vectorField) return this.readable.vectorSearch(vectorField, vector, queryObj);
|
|
315
378
|
return this.readable.vectorSearch(vector, queryObj);
|
|
316
379
|
}
|
|
@@ -319,7 +382,8 @@ var AsDbReadableController = class {
|
|
|
319
382
|
}
|
|
320
383
|
/**
|
|
321
384
|
* **GET /pages** — returns paginated records with metadata.
|
|
322
|
-
*/
|
|
385
|
+
*/
|
|
386
|
+
async pages(url) {
|
|
323
387
|
const parsed = this.parseQueryString(url);
|
|
324
388
|
const error = this.validateParsed(parsed, "pages");
|
|
325
389
|
if (error) return error;
|
|
@@ -332,7 +396,7 @@ var AsDbReadableController = class {
|
|
|
332
396
|
const searchTerm = controls.$search;
|
|
333
397
|
const indexName = controls.$index;
|
|
334
398
|
const vectorField = controls.$vector;
|
|
335
|
-
const threshold = controls.$threshold ? Number(controls.$threshold) :
|
|
399
|
+
const threshold = controls.$threshold ? Number(controls.$threshold) : void 0;
|
|
336
400
|
const query = {
|
|
337
401
|
filter,
|
|
338
402
|
controls: {
|
|
@@ -344,12 +408,12 @@ var AsDbReadableController = class {
|
|
|
344
408
|
}
|
|
345
409
|
};
|
|
346
410
|
let result;
|
|
347
|
-
if (vectorField !==
|
|
348
|
-
const vector = await this.computeEmbedding(searchTerm, vectorField ||
|
|
411
|
+
if (vectorField !== void 0 && searchTerm) {
|
|
412
|
+
const vector = await this.computeEmbedding(searchTerm, vectorField || void 0);
|
|
349
413
|
if (vectorField) result = await this.readable.vectorSearchWithCount(vectorField, vector, query);
|
|
350
|
-
else result = await this.readable.vectorSearchWithCount(vector, query);
|
|
414
|
+
else result = await this.readable.vectorSearchWithCount(vector, query);
|
|
351
415
|
} else if (searchTerm && this.readable.isSearchable()) result = await this.readable.searchWithCount(searchTerm, query, indexName);
|
|
352
|
-
else result = await this.readable.findManyWithCount(query);
|
|
416
|
+
else result = await this.readable.findManyWithCount(query);
|
|
353
417
|
return {
|
|
354
418
|
data: result.data,
|
|
355
419
|
page,
|
|
@@ -360,7 +424,8 @@ else result = await this.readable.findManyWithCount(query);
|
|
|
360
424
|
}
|
|
361
425
|
/**
|
|
362
426
|
* **GET /one/:id** — retrieves a single record by ID or unique property.
|
|
363
|
-
*/
|
|
427
|
+
*/
|
|
428
|
+
async getOne(id, url) {
|
|
364
429
|
const parsed = this.parseQueryString(url);
|
|
365
430
|
if (Object.keys(parsed.filter).length > 0) return new HttpError(400, "Filtering is not allowed for \"one\" endpoint");
|
|
366
431
|
const error = this.validateParsed(parsed, "getOne");
|
|
@@ -375,7 +440,8 @@ else result = await this.readable.findManyWithCount(query);
|
|
|
375
440
|
/**
|
|
376
441
|
* **GET /one?field1=val1&field2=val2** — retrieves a single record by composite key
|
|
377
442
|
* (composite primary key or compound unique index).
|
|
378
|
-
*/
|
|
443
|
+
*/
|
|
444
|
+
async getOneComposite(query, url) {
|
|
379
445
|
const idObj = this.extractCompositeId(query);
|
|
380
446
|
if (idObj instanceof HttpError) return idObj;
|
|
381
447
|
const parsed = this.parseQueryString(url);
|
|
@@ -388,7 +454,8 @@ else result = await this.readable.findManyWithCount(query);
|
|
|
388
454
|
}
|
|
389
455
|
/**
|
|
390
456
|
* **GET /meta** — returns table/view metadata for UI.
|
|
391
|
-
*/
|
|
457
|
+
*/
|
|
458
|
+
meta() {
|
|
392
459
|
return {
|
|
393
460
|
searchable: this.readable.isSearchable(),
|
|
394
461
|
vectorSearchable: this.readable.isVectorSearchable(),
|
|
@@ -396,144 +463,116 @@ else result = await this.readable.findManyWithCount(query);
|
|
|
396
463
|
type: this._serializedType
|
|
397
464
|
};
|
|
398
465
|
}
|
|
399
|
-
constructor(readable, app) {
|
|
400
|
-
/** Reference to the underlying readable (table or view). */ _define_property(this, "readable", void 0);
|
|
401
|
-
/** Application-scoped logger. */ _define_property(this, "logger", void 0);
|
|
402
|
-
/** Cached serialized type definition (static, computed once). */ _define_property(this, "_serializedType", void 0);
|
|
403
|
-
/** Cached search index list (static, computed once). */ _define_property(this, "_searchIndexes", void 0);
|
|
404
|
-
_define_property(this, "_queryControlsValidator", void 0);
|
|
405
|
-
_define_property(this, "_pagesControlsValidator", void 0);
|
|
406
|
-
_define_property(this, "_getOneControlsValidator", void 0);
|
|
407
|
-
this.readable = readable;
|
|
408
|
-
this._serializedType = serializeAnnotatedType(readable.type);
|
|
409
|
-
this._searchIndexes = readable.getSearchIndexes();
|
|
410
|
-
this.logger = app.getLogger(`db [${readable.tableName}]`);
|
|
411
|
-
this.logger.info(`Initializing ${readable.isView ? "view" : "table"} controller`);
|
|
412
|
-
try {
|
|
413
|
-
const p = this.init();
|
|
414
|
-
if (p instanceof Promise) p.catch((error) => {
|
|
415
|
-
this.logger.error(error);
|
|
416
|
-
});
|
|
417
|
-
} catch (error) {
|
|
418
|
-
this.logger.error(error);
|
|
419
|
-
throw error;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
466
|
};
|
|
423
|
-
|
|
467
|
+
__decorate([
|
|
424
468
|
Get("query"),
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
469
|
+
__decorateParam(0, Url()),
|
|
470
|
+
__decorateMetadata("design:type", Function),
|
|
471
|
+
__decorateMetadata("design:paramtypes", [String]),
|
|
472
|
+
__decorateMetadata("design:returntype", Promise)
|
|
429
473
|
], AsDbReadableController.prototype, "query", null);
|
|
430
|
-
|
|
474
|
+
__decorate([
|
|
431
475
|
Get("pages"),
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
476
|
+
__decorateParam(0, Url()),
|
|
477
|
+
__decorateMetadata("design:type", Function),
|
|
478
|
+
__decorateMetadata("design:paramtypes", [String]),
|
|
479
|
+
__decorateMetadata("design:returntype", Promise)
|
|
436
480
|
], AsDbReadableController.prototype, "pages", null);
|
|
437
|
-
|
|
481
|
+
__decorate([
|
|
438
482
|
Get("one/:id"),
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
483
|
+
__decorateParam(0, Param("id")),
|
|
484
|
+
__decorateParam(1, Url()),
|
|
485
|
+
__decorateMetadata("design:type", Function),
|
|
486
|
+
__decorateMetadata("design:paramtypes", [String, String]),
|
|
487
|
+
__decorateMetadata("design:returntype", Promise)
|
|
444
488
|
], AsDbReadableController.prototype, "getOne", null);
|
|
445
|
-
|
|
489
|
+
__decorate([
|
|
446
490
|
Get("one"),
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
491
|
+
__decorateParam(0, Query()),
|
|
492
|
+
__decorateParam(1, Url()),
|
|
493
|
+
__decorateMetadata("design:type", Function),
|
|
494
|
+
__decorateMetadata("design:paramtypes", [typeof (_ref2$1 = typeof Record !== "undefined" && Record) === "function" ? _ref2$1 : Object, String]),
|
|
495
|
+
__decorateMetadata("design:returntype", Promise)
|
|
452
496
|
], AsDbReadableController.prototype, "getOneComposite", null);
|
|
453
|
-
|
|
497
|
+
__decorate([
|
|
454
498
|
Get("meta"),
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
499
|
+
__decorateMetadata("design:type", Function),
|
|
500
|
+
__decorateMetadata("design:paramtypes", []),
|
|
501
|
+
__decorateMetadata("design:returntype", void 0)
|
|
458
502
|
], AsDbReadableController.prototype, "meta", null);
|
|
459
|
-
AsDbReadableController =
|
|
503
|
+
AsDbReadableController = __decorate([
|
|
460
504
|
UseValidationErrorTransform(),
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
_ts_metadata$1("design:paramtypes", [typeof AtscriptDbReadable === "undefined" ? Object : AtscriptDbReadable, typeof Moost === "undefined" ? Object : Moost])
|
|
505
|
+
__decorateParam(0, Inject(READABLE_DEF)),
|
|
506
|
+
__decorateMetadata("design:paramtypes", [Object, typeof (_ref$1 = typeof Moost !== "undefined" && Moost) === "function" ? _ref$1 : Object])
|
|
464
507
|
], AsDbReadableController);
|
|
465
|
-
|
|
466
508
|
//#endregion
|
|
467
|
-
//#region
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
473
|
-
}
|
|
474
|
-
function _ts_metadata(k, v) {
|
|
475
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
476
|
-
}
|
|
477
|
-
function _ts_param(paramIndex, decorator) {
|
|
478
|
-
return function(target, key) {
|
|
479
|
-
decorator(target, key, paramIndex);
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
var AsDbController = class extends AsDbReadableController {
|
|
483
|
-
/** Reference to the underlying table (typed for write access). */ get table() {
|
|
509
|
+
//#region src/as-db.controller.ts
|
|
510
|
+
var _ref, _ref2;
|
|
511
|
+
let AsDbController = class AsDbController extends AsDbReadableController {
|
|
512
|
+
/** Reference to the underlying table (typed for write access). */
|
|
513
|
+
get table() {
|
|
484
514
|
return this.readable;
|
|
485
515
|
}
|
|
516
|
+
constructor(table, app) {
|
|
517
|
+
super(table, app);
|
|
518
|
+
}
|
|
486
519
|
/**
|
|
487
520
|
* Intercepts write operations. Return `undefined` to abort.
|
|
488
|
-
*/
|
|
521
|
+
*/
|
|
522
|
+
onWrite(action, data) {
|
|
489
523
|
return data;
|
|
490
524
|
}
|
|
491
525
|
/**
|
|
492
526
|
* Intercepts delete operations. Return `undefined` to abort.
|
|
493
|
-
*/
|
|
527
|
+
*/
|
|
528
|
+
onRemove(id) {
|
|
494
529
|
return id;
|
|
495
530
|
}
|
|
496
531
|
/**
|
|
497
532
|
* **POST /** — inserts one or many records.
|
|
498
|
-
*/
|
|
533
|
+
*/
|
|
534
|
+
async insert(payload) {
|
|
499
535
|
if (Array.isArray(payload)) {
|
|
500
|
-
const data
|
|
501
|
-
if (data
|
|
502
|
-
return await this.table.insertMany(data
|
|
536
|
+
const data = await this.onWrite("insertMany", payload);
|
|
537
|
+
if (data === void 0) return new HttpError(500, "Not saved");
|
|
538
|
+
return await this.table.insertMany(data);
|
|
503
539
|
}
|
|
504
540
|
const data = await this.onWrite("insert", payload);
|
|
505
|
-
if (data ===
|
|
541
|
+
if (data === void 0) return new HttpError(500, "Not saved");
|
|
506
542
|
return await this.table.insertOne(data);
|
|
507
543
|
}
|
|
508
544
|
/**
|
|
509
545
|
* **PUT /** — fully replaces one or many records matched by primary key.
|
|
510
|
-
*/
|
|
546
|
+
*/
|
|
547
|
+
async replace(payload) {
|
|
511
548
|
if (Array.isArray(payload)) {
|
|
512
|
-
const data
|
|
513
|
-
if (data
|
|
514
|
-
return await this.table.bulkReplace(data
|
|
549
|
+
const data = await this.onWrite("replaceMany", payload);
|
|
550
|
+
if (data === void 0) return new HttpError(500, "Not saved");
|
|
551
|
+
return await this.table.bulkReplace(data);
|
|
515
552
|
}
|
|
516
553
|
const data = await this.onWrite("replace", payload);
|
|
517
|
-
if (data ===
|
|
554
|
+
if (data === void 0) return new HttpError(500, "Not saved");
|
|
518
555
|
return await this.table.replaceOne(data);
|
|
519
556
|
}
|
|
520
557
|
/**
|
|
521
558
|
* **PATCH /** — partially updates one or many records matched by primary key.
|
|
522
|
-
*/
|
|
559
|
+
*/
|
|
560
|
+
async update(payload) {
|
|
523
561
|
if (Array.isArray(payload)) {
|
|
524
|
-
const data
|
|
525
|
-
if (data
|
|
526
|
-
return await this.table.bulkUpdate(data
|
|
562
|
+
const data = await this.onWrite("updateMany", payload);
|
|
563
|
+
if (data === void 0) return new HttpError(500, "Not saved");
|
|
564
|
+
return await this.table.bulkUpdate(data);
|
|
527
565
|
}
|
|
528
566
|
const data = await this.onWrite("update", payload);
|
|
529
|
-
if (data ===
|
|
567
|
+
if (data === void 0) return new HttpError(500, "Not saved");
|
|
530
568
|
return await this.table.updateOne(data);
|
|
531
569
|
}
|
|
532
570
|
/**
|
|
533
571
|
* **DELETE /:id** — removes a single record by primary key.
|
|
534
|
-
*/
|
|
572
|
+
*/
|
|
573
|
+
async remove(id) {
|
|
535
574
|
const resolvedId = await this.onRemove(id);
|
|
536
|
-
if (resolvedId ===
|
|
575
|
+
if (resolvedId === void 0) return new HttpError(500, "Not deleted");
|
|
537
576
|
const result = await this.table.deleteOne(resolvedId);
|
|
538
577
|
if (result.deletedCount < 1) return new HttpError(404);
|
|
539
578
|
return result;
|
|
@@ -541,60 +580,56 @@ var AsDbController = class extends AsDbReadableController {
|
|
|
541
580
|
/**
|
|
542
581
|
* **DELETE /?field1=val1&field2=val2** — removes a record by composite key
|
|
543
582
|
* (composite primary key or compound unique index).
|
|
544
|
-
*/
|
|
583
|
+
*/
|
|
584
|
+
async removeComposite(query) {
|
|
545
585
|
const idObj = this.extractCompositeId(query);
|
|
546
586
|
if (idObj instanceof HttpError) return idObj;
|
|
547
587
|
const resolvedId = await this.onRemove(idObj);
|
|
548
|
-
if (resolvedId ===
|
|
588
|
+
if (resolvedId === void 0) return new HttpError(500, "Not deleted");
|
|
549
589
|
const result = await this.table.deleteOne(resolvedId);
|
|
550
590
|
if (result.deletedCount < 1) return new HttpError(404);
|
|
551
591
|
return result;
|
|
552
592
|
}
|
|
553
|
-
constructor(table, app) {
|
|
554
|
-
super(table, app);
|
|
555
|
-
}
|
|
556
593
|
};
|
|
557
|
-
|
|
594
|
+
__decorate([
|
|
558
595
|
Post(""),
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
596
|
+
__decorateParam(0, Body()),
|
|
597
|
+
__decorateMetadata("design:type", Function),
|
|
598
|
+
__decorateMetadata("design:paramtypes", [Object]),
|
|
599
|
+
__decorateMetadata("design:returntype", Promise)
|
|
563
600
|
], AsDbController.prototype, "insert", null);
|
|
564
|
-
|
|
601
|
+
__decorate([
|
|
565
602
|
Put(""),
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
603
|
+
__decorateParam(0, Body()),
|
|
604
|
+
__decorateMetadata("design:type", Function),
|
|
605
|
+
__decorateMetadata("design:paramtypes", [Object]),
|
|
606
|
+
__decorateMetadata("design:returntype", Promise)
|
|
570
607
|
], AsDbController.prototype, "replace", null);
|
|
571
|
-
|
|
608
|
+
__decorate([
|
|
572
609
|
Patch(""),
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
610
|
+
__decorateParam(0, Body()),
|
|
611
|
+
__decorateMetadata("design:type", Function),
|
|
612
|
+
__decorateMetadata("design:paramtypes", [Object]),
|
|
613
|
+
__decorateMetadata("design:returntype", Promise)
|
|
577
614
|
], AsDbController.prototype, "update", null);
|
|
578
|
-
|
|
615
|
+
__decorate([
|
|
579
616
|
Delete(":id"),
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
617
|
+
__decorateParam(0, Param("id")),
|
|
618
|
+
__decorateMetadata("design:type", Function),
|
|
619
|
+
__decorateMetadata("design:paramtypes", [String]),
|
|
620
|
+
__decorateMetadata("design:returntype", Promise)
|
|
584
621
|
], AsDbController.prototype, "remove", null);
|
|
585
|
-
|
|
622
|
+
__decorate([
|
|
586
623
|
Delete(""),
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
624
|
+
__decorateParam(0, Query()),
|
|
625
|
+
__decorateMetadata("design:type", Function),
|
|
626
|
+
__decorateMetadata("design:paramtypes", [typeof (_ref2 = typeof Record !== "undefined" && Record) === "function" ? _ref2 : Object]),
|
|
627
|
+
__decorateMetadata("design:returntype", Promise)
|
|
591
628
|
], AsDbController.prototype, "removeComposite", null);
|
|
592
|
-
AsDbController =
|
|
629
|
+
AsDbController = __decorate([
|
|
593
630
|
Inherit(),
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
_ts_metadata("design:paramtypes", [typeof AtscriptDbTable === "undefined" ? Object : AtscriptDbTable, typeof Moost === "undefined" ? Object : Moost])
|
|
631
|
+
__decorateParam(0, Inject(TABLE_DEF)),
|
|
632
|
+
__decorateMetadata("design:paramtypes", [Object, typeof (_ref = typeof Moost !== "undefined" && Moost) === "function" ? _ref : Object])
|
|
597
633
|
], AsDbController);
|
|
598
|
-
|
|
599
634
|
//#endregion
|
|
600
|
-
export { AsDbController, AsDbReadableController, READABLE_DEF, ReadableController, TABLE_DEF, TableController, UseValidationErrorTransform, ViewController, validationErrorTransform };
|
|
635
|
+
export { AsDbController, AsDbReadableController, READABLE_DEF, ReadableController, TABLE_DEF, TableController, UseValidationErrorTransform, ViewController, validationErrorTransform };
|