@atscript/moost-db 0.1.163 → 0.1.165

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,10 +1,10 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_db_space_registry = require("./db-space-registry-D5gnC_-6.cjs");
3
3
  let _atscript_typescript_utils = require("@atscript/typescript/utils");
4
+ let _atscript_db = require("@atscript/db");
4
5
  let _moostjs_event_http = require("@moostjs/event-http");
5
6
  let moost = require("moost");
6
7
  let _uniqu_url = require("@uniqu/url");
7
- let _atscript_db = require("@atscript/db");
8
8
  let _wooksjs_event_core = require("@wooksjs/event-core");
9
9
  let _wooksjs_http_body = require("@wooksjs/http-body");
10
10
  let _uniqu_core = require("@uniqu/core");
@@ -14,12 +14,14 @@ let _atscript_db_memory = require("@atscript/db-memory");
14
14
  * The structured error envelope every `moost-db` rejection uses (since
15
15
  * 0.1.128 all of them do): `{ message, statusCode, errors: [{ path, message }] }`
16
16
  * — the same shape the validation interceptor renders for `ValidatorError` /
17
- * `DbError`, so clients parse one format.
17
+ * `DbError`, so clients parse one format. A `DbError` adds its `code` and
18
+ * each entry's `code` / `params` (since 0.1.165).
18
19
  */
19
- function errorEnvelope(statusCode, message, errors) {
20
+ function errorEnvelope(statusCode, message, errors, code) {
20
21
  return new _moostjs_event_http.HttpError(statusCode, {
21
22
  message,
22
23
  statusCode,
24
+ ...code === void 0 ? {} : { code },
23
25
  errors
24
26
  });
25
27
  }
@@ -95,7 +97,15 @@ const dbErrorCodeToStatus = {
95
97
  function transformValidationError(error, reply) {
96
98
  const validation = validatorErrorToHttp(error);
97
99
  if (validation) reply(validation);
98
- else if (error instanceof _atscript_db.DbError) reply(errorEnvelope(dbErrorCodeToStatus[error.code] ?? 400, error.message, error.errors));
100
+ else if (error instanceof _atscript_db.DbError) {
101
+ const errors = error.errors.map(({ path, message, code, params }) => ({
102
+ path,
103
+ message,
104
+ ...code === void 0 ? {} : { code },
105
+ ...params === void 0 ? {} : { params }
106
+ }));
107
+ reply(errorEnvelope(dbErrorCodeToStatus[error.code] ?? 400, error.message, errors, error.code));
108
+ }
99
109
  }
100
110
  const validationErrorTransform = () => (0, moost.defineInterceptor)({ error: transformValidationError }, moost.TInterceptorPriority.BEFORE_ALL);
101
111
  const UseValidationErrorTransform = () => (0, moost.Intercept)(validationErrorTransform());
@@ -191,7 +201,9 @@ var SelectControlDto = class {
191
201
  (0, _atscript_typescript_utils.throwFeatureDisabled)("JSON Schema", "jsonSchema", "emit.jsonSchema");
192
202
  }
193
203
  };
194
- (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("$nulls", (0, _atscript_typescript_utils.defineAnnotatedType)().refTo(NullsControlDto).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("$fuzzy", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$vector", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$threshold", (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).prop("$actions", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("boolean").tags("boolean").optional().$type);
204
+ (0, _atscript_typescript_utils.$ak)("db.index.fulltext", "db.index.plain", "db.index.unique", "db.view.joins", "expect.pattern");
205
+ (0, _atscript_typescript_utils.$nr)("db.agg.avg", "db.agg.count", "db.agg.countDistinct", "db.agg.max", "db.agg.min", "db.agg.sum", "db.alias", "db.amount.currency.ref", "db.column", "db.column.collate", "db.column.derived", "db.column.dimension", "db.column.filterable", "db.column.measure", "db.column.precision", "db.column.renamed", "db.column.searchable", "db.column.sortable", "db.column.version", "db.column.version.exempt", "db.compute", "db.default", "db.default.increment", "db.default.now", "db.default.uuid", "db.depth.limit", "db.encrypted", "db.http.path", "db.ignore", "db.index.fulltext", "db.index.geo", "db.index.plain", "db.index.unique", "db.json", "db.onUpdate.inc", "db.onUpdate.now", "db.patch.strategy", "db.rel.FK", "db.rel.filter", "db.rel.filterable", "db.rel.from", "db.rel.onDelete", "db.rel.onUpdate", "db.rel.to", "db.rel.via", "db.schema", "db.search.filter", "db.search.vector", "db.search.vector.threshold", "db.sort.nulls", "db.space", "db.sync.method", "db.table", "db.table.filterable", "db.table.preferredId.uniqueIndex", "db.table.renamed", "db.table.sortable", "db.unit.ref", "db.view", "db.view.filter", "db.view.for", "db.view.having", "db.view.joins", "db.view.materialized", "db.view.renamed", "db.writeOnly", "meta.default", "meta.id", "meta.readonly", "meta.required");
206
+ (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)().ref(SortControlDto).optional().$type).prop("$nulls", (0, _atscript_typescript_utils.defineAnnotatedType)().ref(NullsControlDto).optional().$type).prop("$select", (0, _atscript_typescript_utils.defineAnnotatedType)("union").item((0, _atscript_typescript_utils.defineAnnotatedType)().ref(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("$fuzzy", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$vector", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$threshold", (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)().ref(WithRelationDto).$type).optional().$type).prop("$actions", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("boolean").tags("boolean").optional().$type);
195
207
  (0, _atscript_typescript_utils.defineAnnotatedType)("object", PagesControlsDto).prop("$page", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").annotate("expect.pattern", {
196
208
  pattern: "^\\d+$",
197
209
  flags: "u",
@@ -200,9 +212,9 @@ var SelectControlDto = class {
200
212
  pattern: "^\\d+$",
201
213
  flags: "u",
202
214
  message: "Expected positive number"
203
- }, true).optional().$type).prop("$sort", (0, _atscript_typescript_utils.defineAnnotatedType)().refTo(SortControlDto).optional().$type).prop("$nulls", (0, _atscript_typescript_utils.defineAnnotatedType)().refTo(NullsControlDto).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("$fuzzy", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$vector", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$threshold", (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).prop("$actions", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("boolean").tags("boolean").optional().$type);
204
- (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).prop("$actions", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("boolean").tags("boolean").optional().$type);
205
- (0, _atscript_typescript_utils.defineAnnotatedType)("object", GeoControlsDto).prop("$center", (0, _atscript_typescript_utils.defineAnnotatedType)("union").item((0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").$type).item((0, _atscript_typescript_utils.defineAnnotatedType)("array").of((0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").$type).$type).item((0, _atscript_typescript_utils.defineAnnotatedType)("array").of((0, _atscript_typescript_utils.defineAnnotatedType)().designType("number").tags("number").$type).$type).optional().$type).prop("$maxDistance", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("number").tags("number").optional().$type).prop("$minDistance", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("number").tags("number").optional().$type).prop("$index", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").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("$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("$page", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").annotate("expect.pattern", {
215
+ }, true).optional().$type).prop("$sort", (0, _atscript_typescript_utils.defineAnnotatedType)().ref(SortControlDto).optional().$type).prop("$nulls", (0, _atscript_typescript_utils.defineAnnotatedType)().ref(NullsControlDto).optional().$type).prop("$select", (0, _atscript_typescript_utils.defineAnnotatedType)("union").item((0, _atscript_typescript_utils.defineAnnotatedType)().ref(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("$fuzzy", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$vector", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$threshold", (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)().ref(WithRelationDto).$type).optional().$type).prop("$actions", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("boolean").tags("boolean").optional().$type);
216
+ (0, _atscript_typescript_utils.defineAnnotatedType)("object", GetOneControlsDto).prop("$select", (0, _atscript_typescript_utils.defineAnnotatedType)("union").item((0, _atscript_typescript_utils.defineAnnotatedType)().ref(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)().ref(WithRelationDto).$type).optional().$type).prop("$actions", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("boolean").tags("boolean").optional().$type);
217
+ (0, _atscript_typescript_utils.defineAnnotatedType)("object", GeoControlsDto).prop("$center", (0, _atscript_typescript_utils.defineAnnotatedType)("union").item((0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").$type).item((0, _atscript_typescript_utils.defineAnnotatedType)("array").of((0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").$type).$type).item((0, _atscript_typescript_utils.defineAnnotatedType)("array").of((0, _atscript_typescript_utils.defineAnnotatedType)().designType("number").tags("number").$type).$type).optional().$type).prop("$maxDistance", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("number").tags("number").optional().$type).prop("$minDistance", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("number").tags("number").optional().$type).prop("$index", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").optional().$type).prop("$select", (0, _atscript_typescript_utils.defineAnnotatedType)("union").item((0, _atscript_typescript_utils.defineAnnotatedType)().ref(SelectControlDto).$type).item((0, _atscript_typescript_utils.defineAnnotatedType)("array").of((0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").$type).$type).optional().$type).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("$page", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").tags("string").annotate("expect.pattern", {
206
218
  pattern: "^\\d+$",
207
219
  flags: "u",
208
220
  message: "Expected positive number"
@@ -210,10 +222,10 @@ var SelectControlDto = class {
210
222
  pattern: "^\\d+$",
211
223
  flags: "u",
212
224
  message: "Expected positive number"
213
- }, true).optional().$type).prop("$with", (0, _atscript_typescript_utils.defineAnnotatedType)("array").of((0, _atscript_typescript_utils.defineAnnotatedType)().refTo(WithRelationDto).$type).optional().$type).prop("$actions", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("boolean").tags("boolean").optional().$type);
214
- (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);
215
- (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("$nulls", (0, _atscript_typescript_utils.defineAnnotatedType)().refTo(NullsControlDto).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);
216
- (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);
225
+ }, true).optional().$type).prop("$with", (0, _atscript_typescript_utils.defineAnnotatedType)("array").of((0, _atscript_typescript_utils.defineAnnotatedType)().ref(WithRelationDto).$type).optional().$type).prop("$actions", (0, _atscript_typescript_utils.defineAnnotatedType)().designType("boolean").tags("boolean").optional().$type);
226
+ (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)().ref(WithFilterDto).optional().$type).prop("controls", (0, _atscript_typescript_utils.defineAnnotatedType)().ref(WithRelationControlsDto).optional().$type).prop("insights", (0, _atscript_typescript_utils.defineAnnotatedType)().ref(WithFilterDto).optional().$type);
227
+ (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)().ref(SortControlDto).optional().$type).prop("$nulls", (0, _atscript_typescript_utils.defineAnnotatedType)().ref(NullsControlDto).optional().$type).prop("$select", (0, _atscript_typescript_utils.defineAnnotatedType)("union").item((0, _atscript_typescript_utils.defineAnnotatedType)().ref(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)().ref(WithRelationDto).$type).optional().$type);
228
+ (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)().ref(WithFilterDto).$type).item((0, _atscript_typescript_utils.defineAnnotatedType)("array").of((0, _atscript_typescript_utils.defineAnnotatedType)().ref(WithFilterDto).$type).$type).$type);
217
229
  (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);
218
230
  (0, _atscript_typescript_utils.defineAnnotatedType)("object", NullsControlDto).propPattern(/./, (0, _atscript_typescript_utils.defineAnnotatedType)("union").item((0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").value("first").$type).item((0, _atscript_typescript_utils.defineAnnotatedType)().designType("string").value("last").$type).$type);
219
231
  (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);
@@ -2179,15 +2191,19 @@ function walk(node, def, shallow) {
2179
2191
  const sProp = sType.props[name];
2180
2192
  if (!sProp) continue;
2181
2193
  if ((0, _atscript_db.isNavRelation)(prop)) continue;
2194
+ const member = !prop.ref && sProp.ref === void 0 ? (0, _atscript_db.soleUnionMember)(prop) : void 0;
2195
+ if (member?.ref?.field) {
2196
+ const terminal = resolveTerminalRef({
2197
+ ...prop,
2198
+ ref: member.ref
2199
+ });
2200
+ if (terminal) applyTerminal(sProp, terminal, shallow, true);
2201
+ }
2182
2202
  if (prop.ref?.field && sProp.ref && !("type" in sProp.ref.type)) {
2183
2203
  const terminal = resolveTerminalRef(prop);
2184
2204
  if (terminal) {
2185
2205
  const direct = prop.ref.type();
2186
- if (terminal.type !== direct || terminal.field !== prop.ref.field) sProp.ref = {
2187
- field: terminal.field,
2188
- type: shallow(terminal.type)
2189
- };
2190
- if (terminal.fk && sProp.metadata["db.rel.FK"] === void 0) sProp.metadata["db.rel.FK"] = true;
2206
+ applyTerminal(sProp, terminal, shallow, terminal.type !== direct || terminal.field !== prop.ref.field);
2191
2207
  }
2192
2208
  }
2193
2209
  walk(sProp, prop, shallow);
@@ -2200,6 +2216,17 @@ function walk(node, def, shallow) {
2200
2216
  if (sType.kind === "array" && sType.of && of) walk(sType.of, of, shallow);
2201
2217
  }
2202
2218
  }
2219
+ /**
2220
+ * Points a serialized prop at its terminal field (when `repoint`) and
2221
+ * inherits the chain's FK marker.
2222
+ */
2223
+ function applyTerminal(sProp, terminal, shallow, repoint) {
2224
+ if (repoint) sProp.ref = {
2225
+ field: terminal.field,
2226
+ type: shallow(terminal.type)
2227
+ };
2228
+ if (terminal.fk && sProp.metadata["db.rel.FK"] === void 0) sProp.metadata["db.rel.FK"] = true;
2229
+ }
2203
2230
  //#endregion
2204
2231
  //#region src/meta/meta-cache.ts
2205
2232
  /**
@@ -2996,11 +3023,13 @@ let AsReadableController = _AsReadableController = class AsReadableController {
2996
3023
  * an unhandled 500. Quote such values: `?name='json-w1'`.
2997
3024
  */
2998
3025
  parseUrlOr400(queryString) {
3026
+ let parsed;
2999
3027
  try {
3000
- return (0, _uniqu_url.parseUrl)(queryString);
3028
+ parsed = (0, _uniqu_url.parseUrl)(queryString);
3001
3029
  } catch (error) {
3002
3030
  throw badRequest("", `Malformed query string: ${error instanceof Error ? error.message : String(error)}`);
3003
3031
  }
3032
+ return nestParsedWith(parsed);
3004
3033
  }
3005
3034
  /**
3006
3035
  * Parse a URL keeping only `$*` control keywords; report whether any
@@ -3312,6 +3341,38 @@ function applyMetaHeaders(response, caching) {
3312
3341
  }
3313
3342
  response.setHeader(varyKey, tokens.join(", "));
3314
3343
  }
3344
+ /**
3345
+ * A dotted `$with` (`$with=a.b(…)`) rewritten into its nested form
3346
+ * (`$with=a($with=b(…))`) right after parsing (since 0.1.165), so every
3347
+ * per-level step — relation-name checks, write-only vetoes, seals, row-scope
3348
+ * overlays — sees one relation per level. The intermediate levels get the
3349
+ * `$with` insight their nested form records. Unchanged when no entry is dotted.
3350
+ */
3351
+ function nestParsedWith(parsed) {
3352
+ const controls = parsed.controls;
3353
+ const withRels = controls?.$with;
3354
+ if (!Array.isArray(withRels) || withRels.length === 0) return parsed;
3355
+ const nested = (0, _atscript_db.nestDottedWith)(withRels);
3356
+ if (nested === withRels) return parsed;
3357
+ const insights = parsed.insights;
3358
+ if (insights) for (const path of insights.keys()) {
3359
+ if (!insights.get(path)?.has("$with")) continue;
3360
+ const segments = path.split(".");
3361
+ for (let i = 1; i < segments.length; i++) {
3362
+ const prefix = segments.slice(0, i).join(".");
3363
+ let ops = insights.get(prefix);
3364
+ if (!ops) insights.set(prefix, ops = /* @__PURE__ */ new Set());
3365
+ ops.add("$with");
3366
+ }
3367
+ }
3368
+ return {
3369
+ ...parsed,
3370
+ controls: {
3371
+ ...controls,
3372
+ $with: nested
3373
+ }
3374
+ };
3375
+ }
3315
3376
  //#endregion
3316
3377
  //#region src/actions/verdict.ts
3317
3378
  /** Assert that a `disabled` predicate returned an array of the expected length; throws HTTP 500 otherwise. */
@@ -5509,12 +5570,16 @@ let AsDbReadableController = _AsDbReadableController = class AsDbReadableControl
5509
5570
  return this._indexFieldPathsCache ??= [...this._searchIndexFieldPaths(), ...this._geoIndexFieldPaths()];
5510
5571
  }
5511
5572
  _searchIndexFieldPaths() {
5512
- const out = (typeof this.readable.getSearchIndexes === "function" ? this.readable.getSearchIndexes() : []).map((info) => ({
5513
- name: info.name,
5514
- type: info.type === "vector" ? "vector" : "text",
5515
- fields: info.fields ?? this._invertibleFields,
5516
- isDefault: info.isDefault === true
5517
- }));
5573
+ const out = (typeof this.readable.getSearchIndexes === "function" ? this.readable.getSearchIndexes() : []).map((info) => {
5574
+ const entry = {
5575
+ name: info.name,
5576
+ type: info.type === "vector" ? "vector" : "text",
5577
+ fields: info.fields ?? this._invertibleFields,
5578
+ isDefault: info.isDefault === true
5579
+ };
5580
+ if (info.aliases?.length) entry.aliases = info.aliases;
5581
+ return entry;
5582
+ });
5518
5583
  for (const type of ["text", "vector"]) {
5519
5584
  const ofType = out.filter((entry) => entry.type === type);
5520
5585
  if (ofType.some((entry) => entry.isDefault)) continue;
@@ -5603,7 +5668,8 @@ let AsDbReadableController = _AsDbReadableController = class AsDbReadableControl
5603
5668
  }
5604
5669
  if (!this.readable.isSearchable()) return void 0;
5605
5670
  if (name) {
5606
- const entry = this.indexFieldPaths().find((e) => e.type === "text" && e.name === name);
5671
+ const text = this.indexFieldPaths().filter((e) => e.type === "text");
5672
+ const entry = text.find((e) => e.name === name) ?? text.find((e) => e.aliases?.includes(name) === true);
5607
5673
  if (!entry || !this._indexVisible(entry)) return badRequest("$index", (0, _atscript_db.searchIndexNotFoundMessage)(name));
5608
5674
  return;
5609
5675
  }
package/dist/index.d.cts CHANGED
@@ -1125,6 +1125,12 @@ interface TDbDecorateContext {
1125
1125
  interface TDbIndexFieldPaths {
1126
1126
  /** The name a request addresses the index by (`$index` for text and geo, `$vector` for vector). */
1127
1127
  name: string;
1128
+ /**
1129
+ * Other names that address the same index (the adapter's deprecated
1130
+ * `TSearchIndexInfo.aliases`); omitted when there are none.
1131
+ * @since 0.1.165
1132
+ */
1133
+ aliases?: readonly string[];
1128
1134
  type: "text" | "vector" | "geo";
1129
1135
  /**
1130
1136
  * Logical field paths the index reads. An index whose coverage cannot be
@@ -3128,14 +3134,22 @@ declare function getDbEndpoint(target: object, method: string | symbol): TDbRequ
3128
3134
  interface THttpErrorEntry {
3129
3135
  path: string;
3130
3136
  message: string;
3137
+ /**
3138
+ * Machine-readable reason of the entry (since 0.1.165) — a `DbError`
3139
+ * entry's code (`UNIQUE`, `FK_MISSING`, `FK_RESTRICT`).
3140
+ */
3141
+ code?: string;
3142
+ /** Values the message names, for translating it (since 0.1.165). */
3143
+ params?: Record<string, unknown>;
3131
3144
  }
3132
3145
  /**
3133
3146
  * The structured error envelope every `moost-db` rejection uses (since
3134
3147
  * 0.1.128 all of them do): `{ message, statusCode, errors: [{ path, message }] }`
3135
3148
  * — the same shape the validation interceptor renders for `ValidatorError` /
3136
- * `DbError`, so clients parse one format.
3149
+ * `DbError`, so clients parse one format. A `DbError` adds its `code` and
3150
+ * each entry's `code` / `params` (since 0.1.165).
3137
3151
  */
3138
- declare function errorEnvelope(statusCode: number, message: string, errors: THttpErrorEntry[]): HttpError;
3152
+ declare function errorEnvelope(statusCode: number, message: string, errors: THttpErrorEntry[], code?: string): HttpError;
3139
3153
  /**
3140
3154
  * A 400 with a single `errors` entry: `path` names the offending logical
3141
3155
  * path / body position, `message` the reason, `top` the envelope's top-level
package/dist/index.d.mts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { a as resolveDbSpace, i as provideDbSpace, n as clearDbSpaces, r as closeDbSpaces, t as DEFAULT_DB_SPACE } from "./db-space-registry-Cvd8s9ql.mjs";
2
2
  import { TAtscriptAnnotatedType, TAtscriptDataType, TSerializeOptions, TSerializedAnnotatedType, TValidatorOptions, Validator } from "@atscript/typescript/utils";
3
+ import { AggregateFn, AtscriptDbReadable, AtscriptDbTable, BucketUnit, FilterExpr, FlatOf, NullsPlacement, TCrudOp, TCrudOp as TCrudOp$1, TCrudPermissions, TCrudPermissions as TCrudPermissions$1, TDbActionInfo, TDbActionInfo as TDbActionInfo$1, TDbActionIntent, TDbActionIntent as TDbActionIntent$1, TDbActionLevel, TDbActionLevel as TDbActionLevel$1, TDbActionProcessor, TDbActionTargetSummary, TDbActionTargetSummary as TDbActionTargetSummary$1, TDbAvailableActions, TDbAvailableActions as TDbAvailableActions$1, TDbFieldMeta, TDbRemoveGuardContext, TDbRemoveGuardContext as TDbRemoveGuardContext$1, TDbWriteAction, TDbWriteAction as TDbWriteAction$1, TDbWriteCheckContext, TDbWriteCheckContext as TDbWriteCheckContext$1, TDbWriteGuardContext, TDbWriteGuardContext as TDbWriteGuardContext$1, TFilterPredicate, TIdResolveOptions, TIdentification, TMetaResponse, TQueryPathOp, TQueryPathOp as TQueryPathOp$1, TQueryPathRefs, TQueryPathSource, TTransactionOptions, Uniquery, UniqueryControls, collectQueryPaths } from "@atscript/db";
3
4
  import { HttpError, MoostHttp } from "@moostjs/event-http";
4
5
  import { Mate, Moost, TConsoleBase, TMateParamMeta, TMoostMetadata } from "moost";
5
6
  import { parseUrl } from "@uniqu/url";
6
- import { AggregateFn, AtscriptDbReadable, AtscriptDbTable, BucketUnit, FilterExpr, FlatOf, NullsPlacement, TCrudOp, TCrudOp as TCrudOp$1, TCrudPermissions, TCrudPermissions as TCrudPermissions$1, TDbActionInfo, TDbActionInfo as TDbActionInfo$1, TDbActionIntent, TDbActionIntent as TDbActionIntent$1, TDbActionLevel, TDbActionLevel as TDbActionLevel$1, TDbActionProcessor, TDbActionTargetSummary, TDbActionTargetSummary as TDbActionTargetSummary$1, TDbAvailableActions, TDbAvailableActions as TDbAvailableActions$1, TDbFieldMeta, TDbRemoveGuardContext, TDbRemoveGuardContext as TDbRemoveGuardContext$1, TDbWriteAction, TDbWriteAction as TDbWriteAction$1, TDbWriteCheckContext, TDbWriteCheckContext as TDbWriteCheckContext$1, TDbWriteGuardContext, TDbWriteGuardContext as TDbWriteGuardContext$1, TFilterPredicate, TIdResolveOptions, TIdentification, TMetaResponse, TQueryPathOp, TQueryPathOp as TQueryPathOp$1, TQueryPathRefs, TQueryPathSource, TTransactionOptions, Uniquery, UniqueryControls, collectQueryPaths } from "@atscript/db";
7
7
  import { EventContext } from "@wooksjs/event-core";
8
8
 
9
9
  //#region src/meta/meta-cache.d.ts
@@ -1125,6 +1125,12 @@ interface TDbDecorateContext {
1125
1125
  interface TDbIndexFieldPaths {
1126
1126
  /** The name a request addresses the index by (`$index` for text and geo, `$vector` for vector). */
1127
1127
  name: string;
1128
+ /**
1129
+ * Other names that address the same index (the adapter's deprecated
1130
+ * `TSearchIndexInfo.aliases`); omitted when there are none.
1131
+ * @since 0.1.165
1132
+ */
1133
+ aliases?: readonly string[];
1128
1134
  type: "text" | "vector" | "geo";
1129
1135
  /**
1130
1136
  * Logical field paths the index reads. An index whose coverage cannot be
@@ -3128,14 +3134,22 @@ declare function getDbEndpoint(target: object, method: string | symbol): TDbRequ
3128
3134
  interface THttpErrorEntry {
3129
3135
  path: string;
3130
3136
  message: string;
3137
+ /**
3138
+ * Machine-readable reason of the entry (since 0.1.165) — a `DbError`
3139
+ * entry's code (`UNIQUE`, `FK_MISSING`, `FK_RESTRICT`).
3140
+ */
3141
+ code?: string;
3142
+ /** Values the message names, for translating it (since 0.1.165). */
3143
+ params?: Record<string, unknown>;
3131
3144
  }
3132
3145
  /**
3133
3146
  * The structured error envelope every `moost-db` rejection uses (since
3134
3147
  * 0.1.128 all of them do): `{ message, statusCode, errors: [{ path, message }] }`
3135
3148
  * — the same shape the validation interceptor renders for `ValidatorError` /
3136
- * `DbError`, so clients parse one format.
3149
+ * `DbError`, so clients parse one format. A `DbError` adds its `code` and
3150
+ * each entry's `code` / `params` (since 0.1.165).
3137
3151
  */
3138
- declare function errorEnvelope(statusCode: number, message: string, errors: THttpErrorEntry[]): HttpError;
3152
+ declare function errorEnvelope(statusCode: number, message: string, errors: THttpErrorEntry[], code?: string): HttpError;
3139
3153
  /**
3140
3154
  * A 400 with a single `errors` entry: `path` names the offending logical
3141
3155
  * path / body position, `message` the reason, `top` the envelope's top-level
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import { a as resolveDbSpace, i as provideDbSpace, n as clearDbSpaces, r as closeDbSpaces, t as DEFAULT_DB_SPACE } from "./db-space-registry-Cdb0FGCn.mjs";
2
- import { ValidatorError, defineAnnotatedType, isAnnotatedType, serializeAnnotatedType, throwFeatureDisabled } from "@atscript/typescript/utils";
2
+ import { $ak, $nr, ValidatorError, defineAnnotatedType, isAnnotatedType, serializeAnnotatedType, throwFeatureDisabled } from "@atscript/typescript/utils";
3
+ import { ADAPTER_FILTER_REASON, ALL_AGGREGATE_FNS, DbError, ENCRYPTED_REASON, acceptedOperatorsHint, aliasTargetOf, andFilters, bucketSourceVerdict, canFilterLeaf, checkHavingKeys, classifyQueryPath, collectQueryPaths, collectQueryPaths as collectQueryPaths$1, containsRelationFilter, findAncestorInSet, geoIndexNotFoundMessage, groupSourceVerdict, hasRelationOp, isEmptyObject, isJsonValueField, isNavRelation, isPlainObject, isRelationOp, narrowerFilterOps, nestDottedWith, normalizeComputedSelect, numericOperandProblem, reconcileCas, resolveDesignType, searchIndexNotFoundMessage, searchMemberKind, selfOrAncestor, soleUnionMember, unsupportedOperatorMessage, vectorIndexNotFoundMessage } from "@atscript/db";
3
4
  import { Body, Delete, Get, HttpError, MoostHttp, Patch, Post, Put, Query, Url, httpKind, prerenderJson } from "@moostjs/event-http";
4
5
  import { ApplyDecorators, Controller, Inherit, Inject, Intercept, Moost, Optional, Param, Pipe, Provide, Resolve, TInterceptorPriority, TPipePriority, current, defineBeforeInterceptor, defineInterceptor, definePipeFn, getMoostMate, useControllerContext, withControllerContext } from "moost";
5
6
  import { parseUrl } from "@uniqu/url";
6
- import { ADAPTER_FILTER_REASON, ALL_AGGREGATE_FNS, DbError, ENCRYPTED_REASON, acceptedOperatorsHint, aliasTargetOf, andFilters, bucketSourceVerdict, canFilterLeaf, checkHavingKeys, classifyQueryPath, collectQueryPaths, collectQueryPaths as collectQueryPaths$1, containsRelationFilter, findAncestorInSet, geoIndexNotFoundMessage, groupSourceVerdict, hasRelationOp, isEmptyObject, isJsonValueField, isNavRelation, isPlainObject, isRelationOp, narrowerFilterOps, normalizeComputedSelect, numericOperandProblem, reconcileCas, resolveDesignType, searchIndexNotFoundMessage, searchMemberKind, selfOrAncestor, unsupportedOperatorMessage, vectorIndexNotFoundMessage } from "@atscript/db";
7
7
  import { cached, current as current$1, defineWook, key, routeParamsKey, useRouteParams } from "@wooksjs/event-core";
8
8
  import { useBody } from "@wooksjs/http-body";
9
9
  import { BUCKET_UNITS } from "@uniqu/core";
@@ -13,12 +13,14 @@ import { buildMemoryPredicate, projectRow, sortRows } from "@atscript/db-memory"
13
13
  * The structured error envelope every `moost-db` rejection uses (since
14
14
  * 0.1.128 all of them do): `{ message, statusCode, errors: [{ path, message }] }`
15
15
  * — the same shape the validation interceptor renders for `ValidatorError` /
16
- * `DbError`, so clients parse one format.
16
+ * `DbError`, so clients parse one format. A `DbError` adds its `code` and
17
+ * each entry's `code` / `params` (since 0.1.165).
17
18
  */
18
- function errorEnvelope(statusCode, message, errors) {
19
+ function errorEnvelope(statusCode, message, errors, code) {
19
20
  return new HttpError(statusCode, {
20
21
  message,
21
22
  statusCode,
23
+ ...code === void 0 ? {} : { code },
22
24
  errors
23
25
  });
24
26
  }
@@ -94,7 +96,15 @@ const dbErrorCodeToStatus = {
94
96
  function transformValidationError(error, reply) {
95
97
  const validation = validatorErrorToHttp(error);
96
98
  if (validation) reply(validation);
97
- else if (error instanceof DbError) reply(errorEnvelope(dbErrorCodeToStatus[error.code] ?? 400, error.message, error.errors));
99
+ else if (error instanceof DbError) {
100
+ const errors = error.errors.map(({ path, message, code, params }) => ({
101
+ path,
102
+ message,
103
+ ...code === void 0 ? {} : { code },
104
+ ...params === void 0 ? {} : { params }
105
+ }));
106
+ reply(errorEnvelope(dbErrorCodeToStatus[error.code] ?? 400, error.message, errors, error.code));
107
+ }
98
108
  }
99
109
  const validationErrorTransform = () => defineInterceptor({ error: transformValidationError }, TInterceptorPriority.BEFORE_ALL);
100
110
  const UseValidationErrorTransform = () => Intercept(validationErrorTransform());
@@ -190,7 +200,9 @@ var SelectControlDto = class {
190
200
  throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
191
201
  }
192
202
  };
193
- 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("$nulls", defineAnnotatedType().refTo(NullsControlDto).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("$fuzzy", 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).prop("$actions", defineAnnotatedType().designType("boolean").tags("boolean").optional().$type);
203
+ $ak("db.index.fulltext", "db.index.plain", "db.index.unique", "db.view.joins", "expect.pattern");
204
+ $nr("db.agg.avg", "db.agg.count", "db.agg.countDistinct", "db.agg.max", "db.agg.min", "db.agg.sum", "db.alias", "db.amount.currency.ref", "db.column", "db.column.collate", "db.column.derived", "db.column.dimension", "db.column.filterable", "db.column.measure", "db.column.precision", "db.column.renamed", "db.column.searchable", "db.column.sortable", "db.column.version", "db.column.version.exempt", "db.compute", "db.default", "db.default.increment", "db.default.now", "db.default.uuid", "db.depth.limit", "db.encrypted", "db.http.path", "db.ignore", "db.index.fulltext", "db.index.geo", "db.index.plain", "db.index.unique", "db.json", "db.onUpdate.inc", "db.onUpdate.now", "db.patch.strategy", "db.rel.FK", "db.rel.filter", "db.rel.filterable", "db.rel.from", "db.rel.onDelete", "db.rel.onUpdate", "db.rel.to", "db.rel.via", "db.schema", "db.search.filter", "db.search.vector", "db.search.vector.threshold", "db.sort.nulls", "db.space", "db.sync.method", "db.table", "db.table.filterable", "db.table.preferredId.uniqueIndex", "db.table.renamed", "db.table.sortable", "db.unit.ref", "db.view", "db.view.filter", "db.view.for", "db.view.having", "db.view.joins", "db.view.materialized", "db.view.renamed", "db.writeOnly", "meta.default", "meta.id", "meta.readonly", "meta.required");
205
+ 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().ref(SortControlDto).optional().$type).prop("$nulls", defineAnnotatedType().ref(NullsControlDto).optional().$type).prop("$select", defineAnnotatedType("union").item(defineAnnotatedType().ref(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("$fuzzy", 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().ref(WithRelationDto).$type).optional().$type).prop("$actions", defineAnnotatedType().designType("boolean").tags("boolean").optional().$type);
194
206
  defineAnnotatedType("object", PagesControlsDto).prop("$page", defineAnnotatedType().designType("string").tags("string").annotate("expect.pattern", {
195
207
  pattern: "^\\d+$",
196
208
  flags: "u",
@@ -199,9 +211,9 @@ defineAnnotatedType("object", PagesControlsDto).prop("$page", defineAnnotatedTyp
199
211
  pattern: "^\\d+$",
200
212
  flags: "u",
201
213
  message: "Expected positive number"
202
- }, true).optional().$type).prop("$sort", defineAnnotatedType().refTo(SortControlDto).optional().$type).prop("$nulls", defineAnnotatedType().refTo(NullsControlDto).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("$fuzzy", 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).prop("$actions", defineAnnotatedType().designType("boolean").tags("boolean").optional().$type);
203
- 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).prop("$actions", defineAnnotatedType().designType("boolean").tags("boolean").optional().$type);
204
- defineAnnotatedType("object", GeoControlsDto).prop("$center", defineAnnotatedType("union").item(defineAnnotatedType().designType("string").tags("string").$type).item(defineAnnotatedType("array").of(defineAnnotatedType().designType("string").tags("string").$type).$type).item(defineAnnotatedType("array").of(defineAnnotatedType().designType("number").tags("number").$type).$type).optional().$type).prop("$maxDistance", defineAnnotatedType().designType("number").tags("number").optional().$type).prop("$minDistance", defineAnnotatedType().designType("number").tags("number").optional().$type).prop("$index", defineAnnotatedType().designType("string").tags("string").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("$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("$page", defineAnnotatedType().designType("string").tags("string").annotate("expect.pattern", {
214
+ }, true).optional().$type).prop("$sort", defineAnnotatedType().ref(SortControlDto).optional().$type).prop("$nulls", defineAnnotatedType().ref(NullsControlDto).optional().$type).prop("$select", defineAnnotatedType("union").item(defineAnnotatedType().ref(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("$fuzzy", 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().ref(WithRelationDto).$type).optional().$type).prop("$actions", defineAnnotatedType().designType("boolean").tags("boolean").optional().$type);
215
+ defineAnnotatedType("object", GetOneControlsDto).prop("$select", defineAnnotatedType("union").item(defineAnnotatedType().ref(SelectControlDto).$type).item(defineAnnotatedType("array").of(defineAnnotatedType().designType("string").tags("string").$type).$type).optional().$type).prop("$with", defineAnnotatedType("array").of(defineAnnotatedType().ref(WithRelationDto).$type).optional().$type).prop("$actions", defineAnnotatedType().designType("boolean").tags("boolean").optional().$type);
216
+ defineAnnotatedType("object", GeoControlsDto).prop("$center", defineAnnotatedType("union").item(defineAnnotatedType().designType("string").tags("string").$type).item(defineAnnotatedType("array").of(defineAnnotatedType().designType("string").tags("string").$type).$type).item(defineAnnotatedType("array").of(defineAnnotatedType().designType("number").tags("number").$type).$type).optional().$type).prop("$maxDistance", defineAnnotatedType().designType("number").tags("number").optional().$type).prop("$minDistance", defineAnnotatedType().designType("number").tags("number").optional().$type).prop("$index", defineAnnotatedType().designType("string").tags("string").optional().$type).prop("$select", defineAnnotatedType("union").item(defineAnnotatedType().ref(SelectControlDto).$type).item(defineAnnotatedType("array").of(defineAnnotatedType().designType("string").tags("string").$type).$type).optional().$type).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("$page", defineAnnotatedType().designType("string").tags("string").annotate("expect.pattern", {
205
217
  pattern: "^\\d+$",
206
218
  flags: "u",
207
219
  message: "Expected positive number"
@@ -209,10 +221,10 @@ defineAnnotatedType("object", GeoControlsDto).prop("$center", defineAnnotatedTyp
209
221
  pattern: "^\\d+$",
210
222
  flags: "u",
211
223
  message: "Expected positive number"
212
- }, true).optional().$type).prop("$with", defineAnnotatedType("array").of(defineAnnotatedType().refTo(WithRelationDto).$type).optional().$type).prop("$actions", defineAnnotatedType().designType("boolean").tags("boolean").optional().$type);
213
- 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);
214
- 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("$nulls", defineAnnotatedType().refTo(NullsControlDto).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);
215
- 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);
224
+ }, true).optional().$type).prop("$with", defineAnnotatedType("array").of(defineAnnotatedType().ref(WithRelationDto).$type).optional().$type).prop("$actions", defineAnnotatedType().designType("boolean").tags("boolean").optional().$type);
225
+ defineAnnotatedType("object", WithRelationDto).prop("name", defineAnnotatedType().designType("string").tags("string").$type).prop("filter", defineAnnotatedType().ref(WithFilterDto).optional().$type).prop("controls", defineAnnotatedType().ref(WithRelationControlsDto).optional().$type).prop("insights", defineAnnotatedType().ref(WithFilterDto).optional().$type);
226
+ 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().ref(SortControlDto).optional().$type).prop("$nulls", defineAnnotatedType().ref(NullsControlDto).optional().$type).prop("$select", defineAnnotatedType("union").item(defineAnnotatedType().ref(SelectControlDto).$type).item(defineAnnotatedType("array").of(defineAnnotatedType().designType("string").tags("string").$type).$type).optional().$type).prop("$with", defineAnnotatedType("array").of(defineAnnotatedType().ref(WithRelationDto).$type).optional().$type);
227
+ 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().ref(WithFilterDto).$type).item(defineAnnotatedType("array").of(defineAnnotatedType().ref(WithFilterDto).$type).$type).$type);
216
228
  defineAnnotatedType("object", SortControlDto).propPattern(/./, defineAnnotatedType("union").item(defineAnnotatedType().designType("number").value(1).$type).item(defineAnnotatedType().designType("number").value(-1).$type).$type);
217
229
  defineAnnotatedType("object", NullsControlDto).propPattern(/./, defineAnnotatedType("union").item(defineAnnotatedType().designType("string").value("first").$type).item(defineAnnotatedType().designType("string").value("last").$type).$type);
218
230
  defineAnnotatedType("object", SelectControlDto).propPattern(/./, defineAnnotatedType("union").item(defineAnnotatedType().designType("number").value(1).$type).item(defineAnnotatedType().designType("number").value(0).$type).$type);
@@ -2178,15 +2190,19 @@ function walk(node, def, shallow) {
2178
2190
  const sProp = sType.props[name];
2179
2191
  if (!sProp) continue;
2180
2192
  if (isNavRelation(prop)) continue;
2193
+ const member = !prop.ref && sProp.ref === void 0 ? soleUnionMember(prop) : void 0;
2194
+ if (member?.ref?.field) {
2195
+ const terminal = resolveTerminalRef({
2196
+ ...prop,
2197
+ ref: member.ref
2198
+ });
2199
+ if (terminal) applyTerminal(sProp, terminal, shallow, true);
2200
+ }
2181
2201
  if (prop.ref?.field && sProp.ref && !("type" in sProp.ref.type)) {
2182
2202
  const terminal = resolveTerminalRef(prop);
2183
2203
  if (terminal) {
2184
2204
  const direct = prop.ref.type();
2185
- if (terminal.type !== direct || terminal.field !== prop.ref.field) sProp.ref = {
2186
- field: terminal.field,
2187
- type: shallow(terminal.type)
2188
- };
2189
- if (terminal.fk && sProp.metadata["db.rel.FK"] === void 0) sProp.metadata["db.rel.FK"] = true;
2205
+ applyTerminal(sProp, terminal, shallow, terminal.type !== direct || terminal.field !== prop.ref.field);
2190
2206
  }
2191
2207
  }
2192
2208
  walk(sProp, prop, shallow);
@@ -2199,6 +2215,17 @@ function walk(node, def, shallow) {
2199
2215
  if (sType.kind === "array" && sType.of && of) walk(sType.of, of, shallow);
2200
2216
  }
2201
2217
  }
2218
+ /**
2219
+ * Points a serialized prop at its terminal field (when `repoint`) and
2220
+ * inherits the chain's FK marker.
2221
+ */
2222
+ function applyTerminal(sProp, terminal, shallow, repoint) {
2223
+ if (repoint) sProp.ref = {
2224
+ field: terminal.field,
2225
+ type: shallow(terminal.type)
2226
+ };
2227
+ if (terminal.fk && sProp.metadata["db.rel.FK"] === void 0) sProp.metadata["db.rel.FK"] = true;
2228
+ }
2202
2229
  //#endregion
2203
2230
  //#region src/meta/meta-cache.ts
2204
2231
  /**
@@ -2995,11 +3022,13 @@ let AsReadableController = _AsReadableController = class AsReadableController {
2995
3022
  * an unhandled 500. Quote such values: `?name='json-w1'`.
2996
3023
  */
2997
3024
  parseUrlOr400(queryString) {
3025
+ let parsed;
2998
3026
  try {
2999
- return parseUrl(queryString);
3027
+ parsed = parseUrl(queryString);
3000
3028
  } catch (error) {
3001
3029
  throw badRequest("", `Malformed query string: ${error instanceof Error ? error.message : String(error)}`);
3002
3030
  }
3031
+ return nestParsedWith(parsed);
3003
3032
  }
3004
3033
  /**
3005
3034
  * Parse a URL keeping only `$*` control keywords; report whether any
@@ -3311,6 +3340,38 @@ function applyMetaHeaders(response, caching) {
3311
3340
  }
3312
3341
  response.setHeader(varyKey, tokens.join(", "));
3313
3342
  }
3343
+ /**
3344
+ * A dotted `$with` (`$with=a.b(…)`) rewritten into its nested form
3345
+ * (`$with=a($with=b(…))`) right after parsing (since 0.1.165), so every
3346
+ * per-level step — relation-name checks, write-only vetoes, seals, row-scope
3347
+ * overlays — sees one relation per level. The intermediate levels get the
3348
+ * `$with` insight their nested form records. Unchanged when no entry is dotted.
3349
+ */
3350
+ function nestParsedWith(parsed) {
3351
+ const controls = parsed.controls;
3352
+ const withRels = controls?.$with;
3353
+ if (!Array.isArray(withRels) || withRels.length === 0) return parsed;
3354
+ const nested = nestDottedWith(withRels);
3355
+ if (nested === withRels) return parsed;
3356
+ const insights = parsed.insights;
3357
+ if (insights) for (const path of insights.keys()) {
3358
+ if (!insights.get(path)?.has("$with")) continue;
3359
+ const segments = path.split(".");
3360
+ for (let i = 1; i < segments.length; i++) {
3361
+ const prefix = segments.slice(0, i).join(".");
3362
+ let ops = insights.get(prefix);
3363
+ if (!ops) insights.set(prefix, ops = /* @__PURE__ */ new Set());
3364
+ ops.add("$with");
3365
+ }
3366
+ }
3367
+ return {
3368
+ ...parsed,
3369
+ controls: {
3370
+ ...controls,
3371
+ $with: nested
3372
+ }
3373
+ };
3374
+ }
3314
3375
  //#endregion
3315
3376
  //#region src/actions/verdict.ts
3316
3377
  /** Assert that a `disabled` predicate returned an array of the expected length; throws HTTP 500 otherwise. */
@@ -5506,12 +5567,16 @@ let AsDbReadableController = _AsDbReadableController = class AsDbReadableControl
5506
5567
  return this._indexFieldPathsCache ??= [...this._searchIndexFieldPaths(), ...this._geoIndexFieldPaths()];
5507
5568
  }
5508
5569
  _searchIndexFieldPaths() {
5509
- const out = (typeof this.readable.getSearchIndexes === "function" ? this.readable.getSearchIndexes() : []).map((info) => ({
5510
- name: info.name,
5511
- type: info.type === "vector" ? "vector" : "text",
5512
- fields: info.fields ?? this._invertibleFields,
5513
- isDefault: info.isDefault === true
5514
- }));
5570
+ const out = (typeof this.readable.getSearchIndexes === "function" ? this.readable.getSearchIndexes() : []).map((info) => {
5571
+ const entry = {
5572
+ name: info.name,
5573
+ type: info.type === "vector" ? "vector" : "text",
5574
+ fields: info.fields ?? this._invertibleFields,
5575
+ isDefault: info.isDefault === true
5576
+ };
5577
+ if (info.aliases?.length) entry.aliases = info.aliases;
5578
+ return entry;
5579
+ });
5515
5580
  for (const type of ["text", "vector"]) {
5516
5581
  const ofType = out.filter((entry) => entry.type === type);
5517
5582
  if (ofType.some((entry) => entry.isDefault)) continue;
@@ -5600,7 +5665,8 @@ let AsDbReadableController = _AsDbReadableController = class AsDbReadableControl
5600
5665
  }
5601
5666
  if (!this.readable.isSearchable()) return void 0;
5602
5667
  if (name) {
5603
- const entry = this.indexFieldPaths().find((e) => e.type === "text" && e.name === name);
5668
+ const text = this.indexFieldPaths().filter((e) => e.type === "text");
5669
+ const entry = text.find((e) => e.name === name) ?? text.find((e) => e.aliases?.includes(name) === true);
5604
5670
  if (!entry || !this._indexVisible(entry)) return badRequest("$index", searchIndexNotFoundMessage(name));
5605
5671
  return;
5606
5672
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/moost-db",
3
- "version": "0.1.163",
3
+ "version": "0.1.165",
4
4
  "description": "Generic database controller for Moost with Atscript.",
5
5
  "keywords": [
6
6
  "annotations",
@@ -44,29 +44,29 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@uniqu/url": "^0.1.15",
47
- "@atscript/db-memory": "^0.1.163"
47
+ "@atscript/db-memory": "^0.1.165"
48
48
  },
49
49
  "devDependencies": {
50
- "@atscript/core": "^0.1.109",
51
- "@atscript/typescript": "^0.1.109",
52
- "@moostjs/event-http": "^0.6.53",
50
+ "@atscript/core": "^0.2.1",
51
+ "@atscript/typescript": "^0.2.1",
52
+ "@moostjs/event-http": "^0.7.0",
53
53
  "@uniqu/core": "^0.1.15",
54
- "@wooksjs/event-core": "^0.7.31",
55
- "@wooksjs/event-http": "^0.7.31",
56
- "@wooksjs/http-body": "^0.7.31",
54
+ "@wooksjs/event-core": "^0.8.0",
55
+ "@wooksjs/event-http": "^0.8.0",
56
+ "@wooksjs/http-body": "^0.8.0",
57
57
  "better-sqlite3": "^12.6.2",
58
- "moost": "^0.6.53",
59
- "unplugin-atscript": "^0.1.109",
60
- "@atscript/db-sqlite": "^0.1.163"
58
+ "moost": "^0.7.0",
59
+ "unplugin-atscript": "^0.2.1",
60
+ "@atscript/db-sqlite": "^0.1.165"
61
61
  },
62
62
  "peerDependencies": {
63
- "@atscript/typescript": "^0.1.109",
64
- "@moostjs/event-http": "^0.6.53",
63
+ "@atscript/typescript": "^0.2.1",
64
+ "@moostjs/event-http": "^0.7.0",
65
65
  "@uniqu/core": "^0.1.15",
66
- "@wooksjs/event-core": "^0.7.31",
67
- "@wooksjs/http-body": "^0.7.31",
68
- "moost": "^0.6.53",
69
- "@atscript/db": "^0.1.163"
66
+ "@wooksjs/event-core": "^0.8.0",
67
+ "@wooksjs/http-body": "^0.8.0",
68
+ "moost": "^0.7.0",
69
+ "@atscript/db": "^0.1.165"
70
70
  },
71
71
  "scripts": {
72
72
  "build": "vp pack",