@atscript/moost-db 0.1.112 → 0.1.113

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
@@ -4,6 +4,7 @@ let _moostjs_event_http = require("@moostjs/event-http");
4
4
  let moost = require("moost");
5
5
  let _uniqu_url = require("@uniqu/url");
6
6
  let _atscript_db = require("@atscript/db");
7
+ let _atscript_db_memory = require("@atscript/db-memory");
7
8
  let _wooksjs_event_core = require("@wooksjs/event-core");
8
9
  let _wooksjs_http_body = require("@wooksjs/http-body");
9
10
  //#region src/validation-interceptor.ts
@@ -2052,7 +2053,10 @@ let AsJsonValueHelpController = class AsJsonValueHelpController extends AsValueH
2052
2053
  }
2053
2054
  async query(controls) {
2054
2055
  let rows = this.rows;
2055
- if (controls.filter && Object.keys(controls.filter).length > 0) rows = rows.filter((row) => matchFilter(row, controls.filter));
2056
+ if (controls.filter && Object.keys(controls.filter).length > 0) {
2057
+ const predicate = (0, _atscript_db_memory.buildMemoryPredicate)(controls.filter);
2058
+ rows = rows.filter((row) => predicate(row));
2059
+ }
2056
2060
  const search = controls.controls.$search;
2057
2061
  if (search) {
2058
2062
  const needle = search.toLowerCase();
@@ -2065,18 +2069,68 @@ let AsJsonValueHelpController = class AsJsonValueHelpController extends AsValueH
2065
2069
  return false;
2066
2070
  });
2067
2071
  }
2068
- if (controls.controls.$sort) rows = sortRows(rows, controls.controls.$sort);
2072
+ const sort = this.normalizeSort(controls.controls.$sort);
2073
+ if (sort) rows = (0, _atscript_db_memory.sortRows)(rows, sort);
2069
2074
  const total = rows.length;
2070
2075
  const skip = Math.max(0, Number(controls.controls.$skip ?? 0));
2071
2076
  const limit = Math.max(0, Number(controls.controls.$limit ?? total - skip));
2077
+ const page = rows.slice(skip, skip + limit);
2078
+ const projection = this.normalizeSelect(controls.controls.$select);
2072
2079
  return {
2073
- data: applySelect(rows.slice(skip, skip + limit), controls.controls.$select),
2080
+ data: projection ? page.map((row) => (0, _atscript_db_memory.projectRow)(row, projection, { clone: false })) : page,
2074
2081
  count: total
2075
2082
  };
2076
2083
  }
2077
2084
  async getOne(id) {
2078
2085
  return this._pkIndex?.get(String(id)) ?? null;
2079
2086
  }
2087
+ /**
2088
+ * Ports the value-help `$sort` grammar to the shared engine's `{ field: 1 |
2089
+ * -1 }` shape (order-preserving for multi-key sorts). Accepts:
2090
+ * - a string `"field:asc,-other"` (comma-separated; `-` prefix or `:desc` → descending),
2091
+ * - an array of such strings / `{ field: dir }` objects,
2092
+ * - a `{ field: 'asc' | 'desc' | 1 | -1 }` object.
2093
+ * Returns `undefined` when nothing sortable was parsed (engine skips sorting).
2094
+ */
2095
+ normalizeSort(sort) {
2096
+ const out = {};
2097
+ const push = (name, explicit) => {
2098
+ const clean = name.replace(/^[-+]/, "");
2099
+ const dir = explicit ?? (name.startsWith("-") ? -1 : 1);
2100
+ if (clean) out[clean] = dir;
2101
+ };
2102
+ if (typeof sort === "string") for (const part of sort.split(",")) {
2103
+ const trimmed = part.trim();
2104
+ if (!trimmed) continue;
2105
+ const [name, dir] = trimmed.split(":");
2106
+ push(name, dir === "desc" ? -1 : dir === "asc" ? 1 : void 0);
2107
+ }
2108
+ else {
2109
+ const entries = Array.isArray(sort) ? sort : sort && typeof sort === "object" ? [sort] : [];
2110
+ for (const entry of entries) if (typeof entry === "string") push(entry);
2111
+ else if (entry && typeof entry === "object") for (const [name, d] of Object.entries(entry)) push(name, d === "desc" || d === -1 ? -1 : 1);
2112
+ }
2113
+ return Object.keys(out).length > 0 ? out : void 0;
2114
+ }
2115
+ /**
2116
+ * Normalizes the raw `parseUrl` `$select` form to the engine's `{ path: 0 |
2117
+ * 1 }` projection map:
2118
+ * - `string[]` (e.g. from `?$select=a,b`) → inclusion map `{ a: 1, b: 1 }`,
2119
+ * - a plain `{ path: 0 | 1 }` object → passed through (0 / falsy → exclude),
2120
+ * - anything else / empty → `undefined` (no projection; whole rows returned).
2121
+ */
2122
+ normalizeSelect(select) {
2123
+ if (Array.isArray(select)) {
2124
+ const out = {};
2125
+ for (const field of select) if (typeof field === "string" && field) out[field] = 1;
2126
+ return Object.keys(out).length > 0 ? out : void 0;
2127
+ }
2128
+ if (select && typeof select === "object") {
2129
+ const out = {};
2130
+ for (const [path, v] of Object.entries(select)) out[path] = v === 0 || v === false ? 0 : 1;
2131
+ return Object.keys(out).length > 0 ? out : void 0;
2132
+ }
2133
+ }
2080
2134
  };
2081
2135
  AsJsonValueHelpController = __decorate([(0, moost.Inherit)(), __decorateMetadata("design:paramtypes", [
2082
2136
  Object,
@@ -2084,114 +2138,6 @@ AsJsonValueHelpController = __decorate([(0, moost.Inherit)(), __decorateMetadata
2084
2138
  typeof moost.Moost === "undefined" ? Object : moost.Moost,
2085
2139
  String
2086
2140
  ])], AsJsonValueHelpController);
2087
- function matchFilter(row, filter) {
2088
- if (!filter || typeof filter !== "object") return true;
2089
- for (const [key, value] of Object.entries(filter)) {
2090
- if (key === "$and") {
2091
- if (!Array.isArray(value)) continue;
2092
- if (!value.every((clause) => matchFilter(row, clause))) return false;
2093
- continue;
2094
- }
2095
- if (key === "$or") {
2096
- if (!Array.isArray(value)) continue;
2097
- if (!value.some((clause) => matchFilter(row, clause))) return false;
2098
- continue;
2099
- }
2100
- if (key === "$nor") {
2101
- if (!Array.isArray(value)) continue;
2102
- if (value.some((clause) => matchFilter(row, clause))) return false;
2103
- continue;
2104
- }
2105
- if (key === "$not") {
2106
- if (matchFilter(row, value)) return false;
2107
- continue;
2108
- }
2109
- if (key.startsWith("$")) continue;
2110
- const fieldValue = row[key];
2111
- if (!matchFieldPredicate(fieldValue, value)) return false;
2112
- }
2113
- return true;
2114
- }
2115
- function matchFieldPredicate(fieldValue, predicate) {
2116
- if (predicate === null || typeof predicate !== "object" || Array.isArray(predicate)) return fieldValue === predicate;
2117
- for (const [op, operand] of Object.entries(predicate)) switch (op) {
2118
- case "$eq":
2119
- if (fieldValue !== operand) return false;
2120
- break;
2121
- case "$ne":
2122
- if (fieldValue === operand) return false;
2123
- break;
2124
- case "$in":
2125
- if (!Array.isArray(operand) || !operand.includes(fieldValue)) return false;
2126
- break;
2127
- case "$nin":
2128
- if (!Array.isArray(operand) || operand.includes(fieldValue)) return false;
2129
- break;
2130
- case "$gt":
2131
- if (!(fieldValue > operand)) return false;
2132
- break;
2133
- case "$gte":
2134
- if (!(fieldValue >= operand)) return false;
2135
- break;
2136
- case "$lt":
2137
- if (!(fieldValue < operand)) return false;
2138
- break;
2139
- case "$lte":
2140
- if (!(fieldValue <= operand)) return false;
2141
- break;
2142
- case "$regex": {
2143
- const re = operand instanceof RegExp ? operand : new RegExp(String(operand));
2144
- if (typeof fieldValue !== "string" || !re.test(fieldValue)) return false;
2145
- break;
2146
- }
2147
- default: if (fieldValue !== operand) return false;
2148
- }
2149
- return true;
2150
- }
2151
- function sortRows(rows, sort) {
2152
- const keys = [];
2153
- const push = (name, explicit) => {
2154
- const clean = name.replace(/^[-+]/, "");
2155
- const dir = explicit ?? (name.startsWith("-") ? -1 : 1);
2156
- if (clean) keys.push({
2157
- name: clean,
2158
- dir
2159
- });
2160
- };
2161
- if (typeof sort === "string") for (const part of sort.split(",")) {
2162
- const trimmed = part.trim();
2163
- if (!trimmed) continue;
2164
- const [name, dir] = trimmed.split(":");
2165
- push(name, dir === "desc" ? -1 : dir === "asc" ? 1 : void 0);
2166
- }
2167
- else if (Array.isArray(sort)) {
2168
- for (const entry of sort) if (typeof entry === "string") push(entry);
2169
- else if (entry && typeof entry === "object") for (const [name, d] of Object.entries(entry)) push(name, d === "desc" || d === -1 ? -1 : 1);
2170
- } else if (sort && typeof sort === "object") for (const [name, d] of Object.entries(sort)) push(name, d === "desc" || d === -1 ? -1 : 1);
2171
- if (keys.length === 0) return rows;
2172
- const out = rows.slice();
2173
- out.sort((a, b) => {
2174
- for (const { name, dir } of keys) {
2175
- const av = a[name];
2176
- const bv = b[name];
2177
- if (av === bv) continue;
2178
- if (av === void 0 || av === null) return -1 * dir;
2179
- if (bv === void 0 || bv === null) return 1 * dir;
2180
- if (av < bv) return -1 * dir;
2181
- if (av > bv) return 1 * dir;
2182
- }
2183
- return 0;
2184
- });
2185
- return out;
2186
- }
2187
- function applySelect(rows, select) {
2188
- if (!select?.length) return rows;
2189
- return rows.map((row) => {
2190
- const out = {};
2191
- for (const key of select) out[key] = row[key];
2192
- return out;
2193
- });
2194
- }
2195
2141
  //#endregion
2196
2142
  //#region src/actions/action-disabled-error.ts
2197
2143
  function buildMessage(action, ids) {
package/dist/index.d.cts CHANGED
@@ -470,18 +470,32 @@ declare abstract class AsValueHelpController<T extends TAtscriptAnnotatedType =
470
470
  * filter/sort/search/paginate over the provided rows, respecting the
471
471
  * `@ui.dict.*` capability annotations on the bound interface.
472
472
  *
473
+ * Filter/sort/projection are delegated to the shared JS-native engine from
474
+ * `@atscript/db-memory` (the same one every in-memory table uses) so a static
475
+ * value-help source behaves identically to the SQL/Mongo adapters instead of
476
+ * carrying a second, weaker implementation.
477
+ *
473
478
  * **Semantics:**
474
479
  * - Filter is interpreted as a subset of MongoDB-style comparison operators
475
- * (`$eq`, `$ne`, `$in`, `$nin`, `$gt`, `$gte`, `$lt`, `$lte`, `$regex`) and
476
- * logical combinators (`$and`, `$or`, `$not`, `$nor`). Unknown operators
477
- * fall through to strict equality.
478
- * - Sort is stable, multi-key, lexicographic. Direction via `-` prefix on the
479
- * field name or `{ [field]: 'asc' | 'desc' }`.
480
+ * (`$eq`, `$ne`, `$in`, `$nin`, `$gt`, `$gte`, `$lt`, `$lte`, `$regex`,
481
+ * `$exists`) and logical combinators (`$and`, `$or`, `$not`). Field names may
482
+ * be dot-paths (`a.b.c`) that descend into nested objects. Any operator the
483
+ * engine does not implement raises `DbError('INVALID_QUERY')`, which the
484
+ * validation interceptor surfaces as HTTP 400 (it is NOT silently ignored).
485
+ * - Null model is Mongo-like: `{ field: null }` / `$eq: null` matches an
486
+ * explicit `null` OR a missing field; `$ne: null` matches only a concrete,
487
+ * present, non-null value.
488
+ * - `$regex` honours `/pattern/flags` literals, so `$regex: '/foo/i'` is a real
489
+ * case-insensitive match.
490
+ * - Sort is stable, multi-key, lexicographic (insertion order preserved among
491
+ * ties). Direction via `-` prefix on the field name or `{ [field]: 'asc' |
492
+ * 'desc' | 1 | -1 }`.
480
493
  * - Search is case-insensitive substring matching across every field listed in
481
- * {@link searchableFields}.
482
- * - Type coercion: comparisons compare raw JS values (no implicit string-to-
483
- * number coercion); strings are compared case-insensitively only for
484
- * `$search`, not for filter operators.
494
+ * {@link searchableFields}. This is value-help's own concern — the shared
495
+ * engine has no `$search`.
496
+ * - Projection (`$select`) supports inclusion (`[fields]` / `{ f: 1 }`) and
497
+ * exclusion (`{ f: 0 }`) with dot-path nesting; the primary key is NOT auto-
498
+ * added (a value-help projection returns exactly the selected fields).
485
499
  *
486
500
  * **Constructor:**
487
501
  * ```ts
@@ -503,6 +517,23 @@ declare class AsJsonValueHelpController<T extends TAtscriptAnnotatedType = TAtsc
503
517
  count: number;
504
518
  }>;
505
519
  protected getOne(id: string | number): Promise<DataType | null>;
520
+ /**
521
+ * Ports the value-help `$sort` grammar to the shared engine's `{ field: 1 |
522
+ * -1 }` shape (order-preserving for multi-key sorts). Accepts:
523
+ * - a string `"field:asc,-other"` (comma-separated; `-` prefix or `:desc` → descending),
524
+ * - an array of such strings / `{ field: dir }` objects,
525
+ * - a `{ field: 'asc' | 'desc' | 1 | -1 }` object.
526
+ * Returns `undefined` when nothing sortable was parsed (engine skips sorting).
527
+ */
528
+ private normalizeSort;
529
+ /**
530
+ * Normalizes the raw `parseUrl` `$select` form to the engine's `{ path: 0 |
531
+ * 1 }` projection map:
532
+ * - `string[]` (e.g. from `?$select=a,b`) → inclusion map `{ a: 1, b: 1 }`,
533
+ * - a plain `{ path: 0 | 1 }` object → passed through (0 / falsy → exclude),
534
+ * - anything else / empty → `undefined` (no projection; whole rows returned).
535
+ */
536
+ private normalizeSelect;
506
537
  }
507
538
  //#endregion
508
539
  //#region src/decorators.d.ts
package/dist/index.d.mts CHANGED
@@ -470,18 +470,32 @@ declare abstract class AsValueHelpController<T extends TAtscriptAnnotatedType =
470
470
  * filter/sort/search/paginate over the provided rows, respecting the
471
471
  * `@ui.dict.*` capability annotations on the bound interface.
472
472
  *
473
+ * Filter/sort/projection are delegated to the shared JS-native engine from
474
+ * `@atscript/db-memory` (the same one every in-memory table uses) so a static
475
+ * value-help source behaves identically to the SQL/Mongo adapters instead of
476
+ * carrying a second, weaker implementation.
477
+ *
473
478
  * **Semantics:**
474
479
  * - Filter is interpreted as a subset of MongoDB-style comparison operators
475
- * (`$eq`, `$ne`, `$in`, `$nin`, `$gt`, `$gte`, `$lt`, `$lte`, `$regex`) and
476
- * logical combinators (`$and`, `$or`, `$not`, `$nor`). Unknown operators
477
- * fall through to strict equality.
478
- * - Sort is stable, multi-key, lexicographic. Direction via `-` prefix on the
479
- * field name or `{ [field]: 'asc' | 'desc' }`.
480
+ * (`$eq`, `$ne`, `$in`, `$nin`, `$gt`, `$gte`, `$lt`, `$lte`, `$regex`,
481
+ * `$exists`) and logical combinators (`$and`, `$or`, `$not`). Field names may
482
+ * be dot-paths (`a.b.c`) that descend into nested objects. Any operator the
483
+ * engine does not implement raises `DbError('INVALID_QUERY')`, which the
484
+ * validation interceptor surfaces as HTTP 400 (it is NOT silently ignored).
485
+ * - Null model is Mongo-like: `{ field: null }` / `$eq: null` matches an
486
+ * explicit `null` OR a missing field; `$ne: null` matches only a concrete,
487
+ * present, non-null value.
488
+ * - `$regex` honours `/pattern/flags` literals, so `$regex: '/foo/i'` is a real
489
+ * case-insensitive match.
490
+ * - Sort is stable, multi-key, lexicographic (insertion order preserved among
491
+ * ties). Direction via `-` prefix on the field name or `{ [field]: 'asc' |
492
+ * 'desc' | 1 | -1 }`.
480
493
  * - Search is case-insensitive substring matching across every field listed in
481
- * {@link searchableFields}.
482
- * - Type coercion: comparisons compare raw JS values (no implicit string-to-
483
- * number coercion); strings are compared case-insensitively only for
484
- * `$search`, not for filter operators.
494
+ * {@link searchableFields}. This is value-help's own concern — the shared
495
+ * engine has no `$search`.
496
+ * - Projection (`$select`) supports inclusion (`[fields]` / `{ f: 1 }`) and
497
+ * exclusion (`{ f: 0 }`) with dot-path nesting; the primary key is NOT auto-
498
+ * added (a value-help projection returns exactly the selected fields).
485
499
  *
486
500
  * **Constructor:**
487
501
  * ```ts
@@ -503,6 +517,23 @@ declare class AsJsonValueHelpController<T extends TAtscriptAnnotatedType = TAtsc
503
517
  count: number;
504
518
  }>;
505
519
  protected getOne(id: string | number): Promise<DataType | null>;
520
+ /**
521
+ * Ports the value-help `$sort` grammar to the shared engine's `{ field: 1 |
522
+ * -1 }` shape (order-preserving for multi-key sorts). Accepts:
523
+ * - a string `"field:asc,-other"` (comma-separated; `-` prefix or `:desc` → descending),
524
+ * - an array of such strings / `{ field: dir }` objects,
525
+ * - a `{ field: 'asc' | 'desc' | 1 | -1 }` object.
526
+ * Returns `undefined` when nothing sortable was parsed (engine skips sorting).
527
+ */
528
+ private normalizeSort;
529
+ /**
530
+ * Normalizes the raw `parseUrl` `$select` form to the engine's `{ path: 0 |
531
+ * 1 }` projection map:
532
+ * - `string[]` (e.g. from `?$select=a,b`) → inclusion map `{ a: 1, b: 1 }`,
533
+ * - a plain `{ path: 0 | 1 }` object → passed through (0 / falsy → exclude),
534
+ * - anything else / empty → `undefined` (no projection; whole rows returned).
535
+ */
536
+ private normalizeSelect;
506
537
  }
507
538
  //#endregion
508
539
  //#region src/decorators.d.ts
package/dist/index.mjs CHANGED
@@ -3,6 +3,7 @@ import { Body, Delete, Get, HttpError, Patch, Post, Put, Query, Url } from "@moo
3
3
  import { ApplyDecorators, Controller, Inherit, Inject, Intercept, Moost, Param, Provide, Resolve, TInterceptorPriority, defineBeforeInterceptor, defineInterceptor, getMoostMate, useControllerContext } from "moost";
4
4
  import { parseUrl } from "@uniqu/url";
5
5
  import { DbError } from "@atscript/db";
6
+ import { buildMemoryPredicate, projectRow, sortRows } from "@atscript/db-memory";
6
7
  import { cached, current, defineWook, key } from "@wooksjs/event-core";
7
8
  import { useBody } from "@wooksjs/http-body";
8
9
  //#region src/validation-interceptor.ts
@@ -2051,7 +2052,10 @@ let AsJsonValueHelpController = class AsJsonValueHelpController extends AsValueH
2051
2052
  }
2052
2053
  async query(controls) {
2053
2054
  let rows = this.rows;
2054
- if (controls.filter && Object.keys(controls.filter).length > 0) rows = rows.filter((row) => matchFilter(row, controls.filter));
2055
+ if (controls.filter && Object.keys(controls.filter).length > 0) {
2056
+ const predicate = buildMemoryPredicate(controls.filter);
2057
+ rows = rows.filter((row) => predicate(row));
2058
+ }
2055
2059
  const search = controls.controls.$search;
2056
2060
  if (search) {
2057
2061
  const needle = search.toLowerCase();
@@ -2064,18 +2068,68 @@ let AsJsonValueHelpController = class AsJsonValueHelpController extends AsValueH
2064
2068
  return false;
2065
2069
  });
2066
2070
  }
2067
- if (controls.controls.$sort) rows = sortRows(rows, controls.controls.$sort);
2071
+ const sort = this.normalizeSort(controls.controls.$sort);
2072
+ if (sort) rows = sortRows(rows, sort);
2068
2073
  const total = rows.length;
2069
2074
  const skip = Math.max(0, Number(controls.controls.$skip ?? 0));
2070
2075
  const limit = Math.max(0, Number(controls.controls.$limit ?? total - skip));
2076
+ const page = rows.slice(skip, skip + limit);
2077
+ const projection = this.normalizeSelect(controls.controls.$select);
2071
2078
  return {
2072
- data: applySelect(rows.slice(skip, skip + limit), controls.controls.$select),
2079
+ data: projection ? page.map((row) => projectRow(row, projection, { clone: false })) : page,
2073
2080
  count: total
2074
2081
  };
2075
2082
  }
2076
2083
  async getOne(id) {
2077
2084
  return this._pkIndex?.get(String(id)) ?? null;
2078
2085
  }
2086
+ /**
2087
+ * Ports the value-help `$sort` grammar to the shared engine's `{ field: 1 |
2088
+ * -1 }` shape (order-preserving for multi-key sorts). Accepts:
2089
+ * - a string `"field:asc,-other"` (comma-separated; `-` prefix or `:desc` → descending),
2090
+ * - an array of such strings / `{ field: dir }` objects,
2091
+ * - a `{ field: 'asc' | 'desc' | 1 | -1 }` object.
2092
+ * Returns `undefined` when nothing sortable was parsed (engine skips sorting).
2093
+ */
2094
+ normalizeSort(sort) {
2095
+ const out = {};
2096
+ const push = (name, explicit) => {
2097
+ const clean = name.replace(/^[-+]/, "");
2098
+ const dir = explicit ?? (name.startsWith("-") ? -1 : 1);
2099
+ if (clean) out[clean] = dir;
2100
+ };
2101
+ if (typeof sort === "string") for (const part of sort.split(",")) {
2102
+ const trimmed = part.trim();
2103
+ if (!trimmed) continue;
2104
+ const [name, dir] = trimmed.split(":");
2105
+ push(name, dir === "desc" ? -1 : dir === "asc" ? 1 : void 0);
2106
+ }
2107
+ else {
2108
+ const entries = Array.isArray(sort) ? sort : sort && typeof sort === "object" ? [sort] : [];
2109
+ for (const entry of entries) if (typeof entry === "string") push(entry);
2110
+ else if (entry && typeof entry === "object") for (const [name, d] of Object.entries(entry)) push(name, d === "desc" || d === -1 ? -1 : 1);
2111
+ }
2112
+ return Object.keys(out).length > 0 ? out : void 0;
2113
+ }
2114
+ /**
2115
+ * Normalizes the raw `parseUrl` `$select` form to the engine's `{ path: 0 |
2116
+ * 1 }` projection map:
2117
+ * - `string[]` (e.g. from `?$select=a,b`) → inclusion map `{ a: 1, b: 1 }`,
2118
+ * - a plain `{ path: 0 | 1 }` object → passed through (0 / falsy → exclude),
2119
+ * - anything else / empty → `undefined` (no projection; whole rows returned).
2120
+ */
2121
+ normalizeSelect(select) {
2122
+ if (Array.isArray(select)) {
2123
+ const out = {};
2124
+ for (const field of select) if (typeof field === "string" && field) out[field] = 1;
2125
+ return Object.keys(out).length > 0 ? out : void 0;
2126
+ }
2127
+ if (select && typeof select === "object") {
2128
+ const out = {};
2129
+ for (const [path, v] of Object.entries(select)) out[path] = v === 0 || v === false ? 0 : 1;
2130
+ return Object.keys(out).length > 0 ? out : void 0;
2131
+ }
2132
+ }
2079
2133
  };
2080
2134
  AsJsonValueHelpController = __decorate([Inherit(), __decorateMetadata("design:paramtypes", [
2081
2135
  Object,
@@ -2083,114 +2137,6 @@ AsJsonValueHelpController = __decorate([Inherit(), __decorateMetadata("design:pa
2083
2137
  typeof Moost === "undefined" ? Object : Moost,
2084
2138
  String
2085
2139
  ])], AsJsonValueHelpController);
2086
- function matchFilter(row, filter) {
2087
- if (!filter || typeof filter !== "object") return true;
2088
- for (const [key, value] of Object.entries(filter)) {
2089
- if (key === "$and") {
2090
- if (!Array.isArray(value)) continue;
2091
- if (!value.every((clause) => matchFilter(row, clause))) return false;
2092
- continue;
2093
- }
2094
- if (key === "$or") {
2095
- if (!Array.isArray(value)) continue;
2096
- if (!value.some((clause) => matchFilter(row, clause))) return false;
2097
- continue;
2098
- }
2099
- if (key === "$nor") {
2100
- if (!Array.isArray(value)) continue;
2101
- if (value.some((clause) => matchFilter(row, clause))) return false;
2102
- continue;
2103
- }
2104
- if (key === "$not") {
2105
- if (matchFilter(row, value)) return false;
2106
- continue;
2107
- }
2108
- if (key.startsWith("$")) continue;
2109
- const fieldValue = row[key];
2110
- if (!matchFieldPredicate(fieldValue, value)) return false;
2111
- }
2112
- return true;
2113
- }
2114
- function matchFieldPredicate(fieldValue, predicate) {
2115
- if (predicate === null || typeof predicate !== "object" || Array.isArray(predicate)) return fieldValue === predicate;
2116
- for (const [op, operand] of Object.entries(predicate)) switch (op) {
2117
- case "$eq":
2118
- if (fieldValue !== operand) return false;
2119
- break;
2120
- case "$ne":
2121
- if (fieldValue === operand) return false;
2122
- break;
2123
- case "$in":
2124
- if (!Array.isArray(operand) || !operand.includes(fieldValue)) return false;
2125
- break;
2126
- case "$nin":
2127
- if (!Array.isArray(operand) || operand.includes(fieldValue)) return false;
2128
- break;
2129
- case "$gt":
2130
- if (!(fieldValue > operand)) return false;
2131
- break;
2132
- case "$gte":
2133
- if (!(fieldValue >= operand)) return false;
2134
- break;
2135
- case "$lt":
2136
- if (!(fieldValue < operand)) return false;
2137
- break;
2138
- case "$lte":
2139
- if (!(fieldValue <= operand)) return false;
2140
- break;
2141
- case "$regex": {
2142
- const re = operand instanceof RegExp ? operand : new RegExp(String(operand));
2143
- if (typeof fieldValue !== "string" || !re.test(fieldValue)) return false;
2144
- break;
2145
- }
2146
- default: if (fieldValue !== operand) return false;
2147
- }
2148
- return true;
2149
- }
2150
- function sortRows(rows, sort) {
2151
- const keys = [];
2152
- const push = (name, explicit) => {
2153
- const clean = name.replace(/^[-+]/, "");
2154
- const dir = explicit ?? (name.startsWith("-") ? -1 : 1);
2155
- if (clean) keys.push({
2156
- name: clean,
2157
- dir
2158
- });
2159
- };
2160
- if (typeof sort === "string") for (const part of sort.split(",")) {
2161
- const trimmed = part.trim();
2162
- if (!trimmed) continue;
2163
- const [name, dir] = trimmed.split(":");
2164
- push(name, dir === "desc" ? -1 : dir === "asc" ? 1 : void 0);
2165
- }
2166
- else if (Array.isArray(sort)) {
2167
- for (const entry of sort) if (typeof entry === "string") push(entry);
2168
- else if (entry && typeof entry === "object") for (const [name, d] of Object.entries(entry)) push(name, d === "desc" || d === -1 ? -1 : 1);
2169
- } else if (sort && typeof sort === "object") for (const [name, d] of Object.entries(sort)) push(name, d === "desc" || d === -1 ? -1 : 1);
2170
- if (keys.length === 0) return rows;
2171
- const out = rows.slice();
2172
- out.sort((a, b) => {
2173
- for (const { name, dir } of keys) {
2174
- const av = a[name];
2175
- const bv = b[name];
2176
- if (av === bv) continue;
2177
- if (av === void 0 || av === null) return -1 * dir;
2178
- if (bv === void 0 || bv === null) return 1 * dir;
2179
- if (av < bv) return -1 * dir;
2180
- if (av > bv) return 1 * dir;
2181
- }
2182
- return 0;
2183
- });
2184
- return out;
2185
- }
2186
- function applySelect(rows, select) {
2187
- if (!select?.length) return rows;
2188
- return rows.map((row) => {
2189
- const out = {};
2190
- for (const key of select) out[key] = row[key];
2191
- return out;
2192
- });
2193
- }
2194
2140
  //#endregion
2195
2141
  //#region src/actions/action-disabled-error.ts
2196
2142
  function buildMessage(action, ids) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/moost-db",
3
- "version": "0.1.112",
3
+ "version": "0.1.113",
4
4
  "description": "Generic database controller for Moost with Atscript.",
5
5
  "keywords": [
6
6
  "annotations",
@@ -38,7 +38,8 @@
38
38
  "access": "public"
39
39
  },
40
40
  "dependencies": {
41
- "@uniqu/url": "^0.1.6"
41
+ "@uniqu/url": "^0.1.6",
42
+ "@atscript/db-memory": "^0.1.113"
42
43
  },
43
44
  "devDependencies": {
44
45
  "@atscript/core": "^0.1.80",
@@ -58,7 +59,7 @@
58
59
  "@wooksjs/event-core": "^0.7.19",
59
60
  "@wooksjs/http-body": "^0.7.19",
60
61
  "moost": "^0.6.29",
61
- "@atscript/db": "^0.1.112"
62
+ "@atscript/db": "^0.1.113"
62
63
  },
63
64
  "scripts": {
64
65
  "postinstall": "asc -f dts",