ultimabase 0.0.0-stage → 0.1.0
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/CHANGELOG.md +7 -0
- package/README.md +4 -2
- package/dist/access.d.ts +62 -0
- package/dist/access.d.ts.map +1 -0
- package/dist/access.js +258 -0
- package/dist/adapter-errors.d.ts +43 -0
- package/dist/adapter-errors.d.ts.map +1 -0
- package/dist/adapter-errors.js +72 -0
- package/dist/adapter-json.d.ts +20 -0
- package/dist/adapter-json.d.ts.map +1 -0
- package/dist/adapter-json.js +2 -0
- package/dist/adapter-migrations.d.ts +90 -0
- package/dist/adapter-migrations.d.ts.map +1 -0
- package/dist/adapter-migrations.js +1 -0
- package/dist/adapter.d.ts +333 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +5 -0
- package/dist/aggregate.d.ts +31 -0
- package/dist/aggregate.d.ts.map +1 -0
- package/dist/aggregate.js +99 -0
- package/dist/app-internals.d.ts +10 -0
- package/dist/app-internals.d.ts.map +1 -0
- package/dist/app-internals.js +12 -0
- package/dist/app-options.d.ts +22 -0
- package/dist/app-options.d.ts.map +1 -0
- package/dist/app-options.js +3 -0
- package/dist/cascade.d.ts +47 -0
- package/dist/cascade.d.ts.map +1 -0
- package/dist/cascade.js +209 -0
- package/dist/cli-config.d.ts +6 -0
- package/dist/cli-config.d.ts.map +1 -0
- package/dist/cli-config.js +45 -0
- package/dist/cli-deploy.d.ts +14 -0
- package/dist/cli-deploy.d.ts.map +1 -0
- package/dist/cli-deploy.js +193 -0
- package/dist/cli-main.d.ts +16 -0
- package/dist/cli-main.d.ts.map +1 -0
- package/dist/cli-main.js +151 -0
- package/dist/cli-migrate.d.ts +20 -0
- package/dist/cli-migrate.d.ts.map +1 -0
- package/dist/cli-migrate.js +105 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +4 -0
- package/dist/complete.d.ts +13 -0
- package/dist/complete.d.ts.map +1 -0
- package/dist/complete.js +60 -0
- package/dist/console-logger.d.ts +3 -0
- package/dist/console-logger.d.ts.map +1 -0
- package/dist/console-logger.js +62 -0
- package/dist/create-many.d.ts +7 -0
- package/dist/create-many.d.ts.map +1 -0
- package/dist/create-many.js +88 -0
- package/dist/decimal.d.ts +23 -0
- package/dist/decimal.d.ts.map +1 -0
- package/dist/decimal.js +50 -0
- package/dist/define-app.d.ts +59 -0
- package/dist/define-app.d.ts.map +1 -0
- package/dist/define-app.js +5 -0
- package/dist/define-enum.d.ts +6 -0
- package/dist/define-enum.d.ts.map +1 -0
- package/dist/define-enum.js +18 -0
- package/dist/define-function.d.ts +25 -0
- package/dist/define-function.d.ts.map +1 -0
- package/dist/define-function.js +111 -0
- package/dist/define-model.d.ts +48 -0
- package/dist/define-model.d.ts.map +1 -0
- package/dist/define-model.js +85 -0
- package/dist/definition.d.ts +179 -0
- package/dist/definition.d.ts.map +1 -0
- package/dist/definition.js +165 -0
- package/dist/delete-many.d.ts +13 -0
- package/dist/delete-many.d.ts.map +1 -0
- package/dist/delete-many.js +58 -0
- package/dist/engine.d.ts +16 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +174 -0
- package/dist/errors.d.ts +50 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +43 -0
- package/dist/exact.d.ts +20 -0
- package/dist/exact.d.ts.map +1 -0
- package/dist/exact.js +1 -0
- package/dist/feed.d.ts +6 -0
- package/dist/feed.d.ts.map +1 -0
- package/dist/feed.js +33 -0
- package/dist/field-codec.d.ts +11 -0
- package/dist/field-codec.d.ts.map +1 -0
- package/dist/field-codec.js +48 -0
- package/dist/field-rules.d.ts +57 -0
- package/dist/field-rules.d.ts.map +1 -0
- package/dist/field-rules.js +1 -0
- package/dist/field-type.d.ts +51 -0
- package/dist/field-type.d.ts.map +1 -0
- package/dist/field-type.js +106 -0
- package/dist/fields.d.ts +295 -0
- package/dist/fields.d.ts.map +1 -0
- package/dist/fields.js +1 -0
- package/dist/function.d.ts +126 -0
- package/dist/function.d.ts.map +1 -0
- package/dist/function.js +1 -0
- package/dist/functions.d.ts +18 -0
- package/dist/functions.d.ts.map +1 -0
- package/dist/functions.js +99 -0
- package/dist/group-by.d.ts +10 -0
- package/dist/group-by.d.ts.map +1 -0
- package/dist/group-by.js +145 -0
- package/dist/group-having.d.ts +8 -0
- package/dist/group-having.d.ts.map +1 -0
- package/dist/group-having.js +97 -0
- package/dist/hooks.d.ts +41 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +149 -0
- package/dist/hosts.d.ts +3 -0
- package/dist/hosts.d.ts.map +1 -0
- package/dist/hosts.js +8 -0
- package/dist/identify.d.ts +15 -0
- package/dist/identify.d.ts.map +1 -0
- package/dist/identify.js +71 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/internal.d.ts +28 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +39 -0
- package/dist/lifecycle.d.ts +21 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +149 -0
- package/dist/list-update.d.ts +12 -0
- package/dist/list-update.d.ts.map +1 -0
- package/dist/list-update.js +52 -0
- package/dist/live.d.ts +37 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +139 -0
- package/dist/manifest.d.ts +11 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +60 -0
- package/dist/memory-aggregate.d.ts +7 -0
- package/dist/memory-aggregate.d.ts.map +1 -0
- package/dist/memory-aggregate.js +107 -0
- package/dist/memory-conditions.d.ts +8 -0
- package/dist/memory-conditions.d.ts.map +1 -0
- package/dist/memory-conditions.js +82 -0
- package/dist/memory-draft.d.ts +34 -0
- package/dist/memory-draft.d.ts.map +1 -0
- package/dist/memory-draft.js +255 -0
- package/dist/memory-json.d.ts +6 -0
- package/dist/memory-json.d.ts.map +1 -0
- package/dist/memory-json.js +86 -0
- package/dist/memory-read.d.ts +45 -0
- package/dist/memory-read.d.ts.map +1 -0
- package/dist/memory-read.js +244 -0
- package/dist/memory-search.d.ts +16 -0
- package/dist/memory-search.d.ts.map +1 -0
- package/dist/memory-search.js +110 -0
- package/dist/memory-values.d.ts +23 -0
- package/dist/memory-values.d.ts.map +1 -0
- package/dist/memory-values.js +82 -0
- package/dist/memory.d.ts +4 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +157 -0
- package/dist/migrate.d.ts +22 -0
- package/dist/migrate.d.ts.map +1 -0
- package/dist/migrate.js +131 -0
- package/dist/model.d.ts +239 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +1 -0
- package/dist/nested-write.d.ts +64 -0
- package/dist/nested-write.d.ts.map +1 -0
- package/dist/nested-write.js +274 -0
- package/dist/number-update.d.ts +18 -0
- package/dist/number-update.d.ts.map +1 -0
- package/dist/number-update.js +96 -0
- package/dist/plugin-app.d.ts +48 -0
- package/dist/plugin-app.d.ts.map +1 -0
- package/dist/plugin-app.js +230 -0
- package/dist/plugin-code.d.ts +17 -0
- package/dist/plugin-code.d.ts.map +1 -0
- package/dist/plugin-code.js +125 -0
- package/dist/plugin-use.d.ts +22 -0
- package/dist/plugin-use.d.ts.map +1 -0
- package/dist/plugin-use.js +161 -0
- package/dist/plugin.d.ts +357 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +17 -0
- package/dist/query-aggregate.d.ts +82 -0
- package/dist/query-aggregate.d.ts.map +1 -0
- package/dist/query-aggregate.js +1 -0
- package/dist/query-args.d.ts +41 -0
- package/dist/query-args.d.ts.map +1 -0
- package/dist/query-args.js +263 -0
- package/dist/query-bulk.d.ts +35 -0
- package/dist/query-bulk.d.ts.map +1 -0
- package/dist/query-bulk.js +1 -0
- package/dist/query-conditions.d.ts +9 -0
- package/dist/query-conditions.d.ts.map +1 -0
- package/dist/query-conditions.js +46 -0
- package/dist/query-context.d.ts +32 -0
- package/dist/query-context.d.ts.map +1 -0
- package/dist/query-context.js +55 -0
- package/dist/query-filter.d.ts +46 -0
- package/dist/query-filter.d.ts.map +1 -0
- package/dist/query-filter.js +1 -0
- package/dist/query-group.d.ts +82 -0
- package/dist/query-group.d.ts.map +1 -0
- package/dist/query-group.js +1 -0
- package/dist/query-json.d.ts +9 -0
- package/dist/query-json.d.ts.map +1 -0
- package/dist/query-json.js +66 -0
- package/dist/query-order.d.ts +15 -0
- package/dist/query-order.d.ts.map +1 -0
- package/dist/query-order.js +115 -0
- package/dist/query-project.d.ts +15 -0
- package/dist/query-project.d.ts.map +1 -0
- package/dist/query-project.js +45 -0
- package/dist/query-search.d.ts +24 -0
- package/dist/query-search.d.ts.map +1 -0
- package/dist/query-search.js +2 -0
- package/dist/query-values.d.ts +28 -0
- package/dist/query-values.d.ts.map +1 -0
- package/dist/query-values.js +91 -0
- package/dist/query-where.d.ts +46 -0
- package/dist/query-where.d.ts.map +1 -0
- package/dist/query-where.js +200 -0
- package/dist/query-write.d.ts +14 -0
- package/dist/query-write.d.ts.map +1 -0
- package/dist/query-write.js +260 -0
- package/dist/query.d.ts +254 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +1 -0
- package/dist/record.d.ts +257 -0
- package/dist/record.d.ts.map +1 -0
- package/dist/record.js +1 -0
- package/dist/recorder.d.ts +32 -0
- package/dist/recorder.d.ts.map +1 -0
- package/dist/recorder.js +152 -0
- package/dist/relation-write.d.ts +41 -0
- package/dist/relation-write.d.ts.map +1 -0
- package/dist/relation-write.js +112 -0
- package/dist/relations.d.ts +42 -0
- package/dist/relations.d.ts.map +1 -0
- package/dist/relations.js +119 -0
- package/dist/rules.d.ts +97 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +71 -0
- package/dist/running.d.ts +29 -0
- package/dist/running.d.ts.map +1 -0
- package/dist/running.js +39 -0
- package/dist/schema-indexes.d.ts +11 -0
- package/dist/schema-indexes.d.ts.map +1 -0
- package/dist/schema-indexes.js +59 -0
- package/dist/schema-virtuals.d.ts +19 -0
- package/dist/schema-virtuals.d.ts.map +1 -0
- package/dist/schema-virtuals.js +100 -0
- package/dist/schema.d.ts +35 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +267 -0
- package/dist/scope.d.ts +46 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +82 -0
- package/dist/scratch.d.ts +14 -0
- package/dist/scratch.d.ts.map +1 -0
- package/dist/scratch.js +10 -0
- package/dist/serve.d.ts +2 -0
- package/dist/serve.d.ts.map +1 -0
- package/dist/serve.js +4 -0
- package/dist/symbols.d.ts +10 -0
- package/dist/symbols.d.ts.map +1 -0
- package/dist/symbols.js +1 -0
- package/dist/transaction.d.ts +28 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +156 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/update-many.d.ts +7 -0
- package/dist/update-many.d.ts.map +1 -0
- package/dist/update-many.js +182 -0
- package/dist/uuid.d.ts +7 -0
- package/dist/uuid.d.ts.map +1 -0
- package/dist/uuid.js +48 -0
- package/dist/validation.d.ts +24 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +72 -0
- package/dist/virtual-read.d.ts +9 -0
- package/dist/virtual-read.d.ts.map +1 -0
- package/dist/virtual-read.js +145 -0
- package/dist/virtual.d.ts +142 -0
- package/dist/virtual.d.ts.map +1 -0
- package/dist/virtual.js +1 -0
- package/dist/write-context.d.ts +46 -0
- package/dist/write-context.d.ts.map +1 -0
- package/dist/write-context.js +102 -0
- package/dist/write-data.d.ts +26 -0
- package/dist/write-data.d.ts.map +1 -0
- package/dist/write-data.js +144 -0
- package/dist/write-plan.d.ts +107 -0
- package/dist/write-plan.d.ts.map +1 -0
- package/dist/write-plan.js +170 -0
- package/dist/write-target.d.ts +17 -0
- package/dist/write-target.d.ts.map +1 -0
- package/dist/write-target.js +59 -0
- package/dist/writes.d.ts +23 -0
- package/dist/writes.d.ts.map +1 -0
- package/dist/writes.js +246 -0
- package/dist/writing.d.ts +10 -0
- package/dist/writing.d.ts.map +1 -0
- package/dist/writing.js +66 -0
- package/package.json +42 -3
- package/src/access.ts +329 -0
- package/src/adapter-errors.ts +89 -0
- package/src/adapter-json.ts +21 -0
- package/src/adapter-migrations.ts +98 -0
- package/src/adapter.ts +363 -0
- package/src/aggregate.ts +136 -0
- package/src/app-internals.ts +26 -0
- package/src/app-options.ts +24 -0
- package/src/cascade.ts +297 -0
- package/src/cli-config.ts +45 -0
- package/src/cli-deploy.ts +235 -0
- package/src/cli-main.ts +165 -0
- package/src/cli-migrate.ts +143 -0
- package/src/cli.ts +5 -0
- package/src/complete.ts +73 -0
- package/src/console-logger.ts +87 -0
- package/src/create-many.ts +126 -0
- package/src/decimal.ts +74 -0
- package/src/define-app.ts +108 -0
- package/src/define-enum.ts +26 -0
- package/src/define-function.ts +188 -0
- package/src/define-model.ts +220 -0
- package/src/definition.ts +352 -0
- package/src/delete-many.ts +76 -0
- package/src/engine.ts +281 -0
- package/src/errors.ts +97 -0
- package/src/exact.ts +49 -0
- package/src/feed.ts +39 -0
- package/src/field-codec.ts +72 -0
- package/src/field-rules.ts +77 -0
- package/src/field-type.ts +219 -0
- package/src/fields.ts +383 -0
- package/src/function.ts +143 -0
- package/src/functions.ts +154 -0
- package/src/group-by.ts +186 -0
- package/src/group-having.ts +143 -0
- package/src/hooks.ts +215 -0
- package/src/hosts.ts +11 -0
- package/src/identify.ts +95 -0
- package/src/index.ts +125 -0
- package/src/internal.ts +68 -0
- package/src/lifecycle.ts +214 -0
- package/src/list-update.ts +71 -0
- package/src/live.ts +199 -0
- package/src/manifest.ts +71 -0
- package/src/memory-aggregate.ts +162 -0
- package/src/memory-conditions.ts +88 -0
- package/src/memory-draft.ts +319 -0
- package/src/memory-json.ts +91 -0
- package/src/memory-read.ts +311 -0
- package/src/memory-search.ts +149 -0
- package/src/memory-values.ts +106 -0
- package/src/memory.ts +173 -0
- package/src/migrate.ts +152 -0
- package/src/model.ts +312 -0
- package/src/nested-write.ts +390 -0
- package/src/number-update.ts +142 -0
- package/src/plugin-app.ts +308 -0
- package/src/plugin-code.ts +158 -0
- package/src/plugin-use.ts +217 -0
- package/src/plugin.ts +400 -0
- package/src/query-aggregate.ts +96 -0
- package/src/query-args.ts +375 -0
- package/src/query-bulk.ts +53 -0
- package/src/query-conditions.ts +53 -0
- package/src/query-context.ts +104 -0
- package/src/query-filter.ts +54 -0
- package/src/query-group.ts +137 -0
- package/src/query-json.ts +90 -0
- package/src/query-order.ts +158 -0
- package/src/query-project.ts +73 -0
- package/src/query-search.ts +31 -0
- package/src/query-values.ts +131 -0
- package/src/query-where.ts +318 -0
- package/src/query-write.ts +360 -0
- package/src/query.ts +400 -0
- package/src/record.ts +379 -0
- package/src/recorder.ts +212 -0
- package/src/relation-write.ts +176 -0
- package/src/relations.ts +165 -0
- package/src/rules.ts +188 -0
- package/src/running.ts +62 -0
- package/src/schema-indexes.ts +88 -0
- package/src/schema-virtuals.ts +134 -0
- package/src/schema.ts +367 -0
- package/src/scope.ts +123 -0
- package/src/scratch.ts +28 -0
- package/src/serve.ts +5 -0
- package/src/symbols.ts +11 -0
- package/src/transaction.ts +211 -0
- package/src/types.ts +79 -0
- package/src/update-many.ts +268 -0
- package/src/uuid.ts +51 -0
- package/src/validation.ts +107 -0
- package/src/virtual-read.ts +198 -0
- package/src/virtual.ts +187 -0
- package/src/write-context.ts +170 -0
- package/src/write-data.ts +188 -0
- package/src/write-plan.ts +273 -0
- package/src/write-target.ts +92 -0
- package/src/writes.ts +361 -0
- package/src/writing.ts +93 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Filter, Nested, Row, SchemaField, Step } from './adapter.ts';
|
|
2
|
+
import type { Truth } from './memory-conditions.ts';
|
|
3
|
+
/** A stored row; a stored `one` key is the target's id or `null`. */
|
|
4
|
+
export type StoredRow = {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly [field: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
export type Store = {
|
|
9
|
+
readonly tables: Map<string, Map<string, StoredRow>>;
|
|
10
|
+
/** `Model.field` → id → the linked ids, kept on both sides (D-64). */
|
|
11
|
+
readonly joins: Map<string, Map<string, Set<string>>>;
|
|
12
|
+
};
|
|
13
|
+
/** A copy of the store, which a write changes and keeps once whole. */
|
|
14
|
+
export declare function clone(store: Store): Store;
|
|
15
|
+
/** Each model's fields by name. */
|
|
16
|
+
export type Fields = ReadonlyMap<string, ReadonlyMap<string, SchemaField>>;
|
|
17
|
+
export declare class Reader {
|
|
18
|
+
readonly store: Store;
|
|
19
|
+
readonly fields: Fields;
|
|
20
|
+
/** A write's change index → the ids its delete removed, for `removedBy`. */
|
|
21
|
+
readonly removed: Map<number, ReadonlySet<string>>;
|
|
22
|
+
constructor(store: Store, fields: Fields);
|
|
23
|
+
table(model: string): Map<string, StoredRow>;
|
|
24
|
+
field(model: string, name: string): SchemaField | undefined;
|
|
25
|
+
/** The rows a relation of `row` points to. */
|
|
26
|
+
related(model: string, field: SchemaField, row: StoredRow): StoredRow[];
|
|
27
|
+
matches(model: string, row: StoredRow, filter: Filter | undefined): Truth;
|
|
28
|
+
private condition;
|
|
29
|
+
/** The row `through` reaches from `row`, and its model, if one (D-134). */
|
|
30
|
+
reach(model: string, row: StoredRow, through?: readonly Step[]): {
|
|
31
|
+
readonly model: string;
|
|
32
|
+
readonly row: StoredRow;
|
|
33
|
+
} | undefined;
|
|
34
|
+
/** A row's sort key: a field, through `one` relations, a count (D-134), a relevance (D-148). */
|
|
35
|
+
private key;
|
|
36
|
+
/** The rows of a `many` relation of `row` that `where` selects. */
|
|
37
|
+
private count;
|
|
38
|
+
/** Each row with its sort keys. */
|
|
39
|
+
private keyed;
|
|
40
|
+
/** Filters, orders and pages rows of `model`, as `read` asks. */
|
|
41
|
+
select(model: string, rows: StoredRow[], read: Nested): StoredRow[];
|
|
42
|
+
/** A row as the adapter returns it, with the relations `read` includes. */
|
|
43
|
+
output(model: string, row: StoredRow, read: Nested): Row;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=memory-read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-read.d.ts","sourceRoot":"","sources":["../src/memory-read.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEX,MAAM,EACN,MAAM,EAEN,GAAG,EACH,WAAW,EACX,IAAI,EACJ,MAAM,cAAc,CAAA;AACrB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAMnD,qEAAqE;AACrE,MAAM,MAAM,SAAS,GAAG;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,KAAK,GAAG;IACnB,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;IACpD,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;CACrD,CAAA;AAED,uEAAuE;AACvE,wBAAgB,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAYzC;AAED,mCAAmC;AACnC,MAAM,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAA;AAE1E,qBAAa,MAAM;IAClB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAY;IAE9D,YAAY,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAGvC;IAED,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAE3C;IAED,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAE1D;IAED,8CAA8C;IAC9C,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,SAAS,GAAG,SAAS,EAAE,CAiBtE;IAED,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,CAmBxE;IAED,OAAO,CAAC,SAAS;IAoDjB,2EAA2E;IAC3E,KAAK,CACJ,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,SAAS,EACd,OAAO,GAAE,SAAS,IAAI,EAAO,GAC3B;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAA;KAAE,GAAG,SAAS,CAgBjE;IAED,gGAAgG;IAChG,OAAO,CAAC,GAAG;IAaX,mEAAmE;IACnE,OAAO,CAAC,KAAK;IAab,mCAAmC;IACnC,OAAO,CAAC,KAAK;IAWb,iEAAiE;IACjE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAmClE;IAED,2EAA2E;IAC3E,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,CA8CvD;CACD"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { and, isFilters, not, or, scalar } from './memory-conditions.js';
|
|
2
|
+
import { compareKeys, copy, sortable } from './memory-values.js';
|
|
3
|
+
import { relevance, searches } from './memory-search.js';
|
|
4
|
+
import { modelOf } from './query-where.js';
|
|
5
|
+
/** A copy of the store, which a write changes and keeps once whole. */
|
|
6
|
+
export function clone(store) {
|
|
7
|
+
return {
|
|
8
|
+
tables: new Map([...store.tables].map(([name, table]) => [name, new Map(table)])),
|
|
9
|
+
joins: new Map([...store.joins].map(([key, side]) => [
|
|
10
|
+
key,
|
|
11
|
+
new Map([...side].map(([id, ids]) => [id, new Set(ids)])),
|
|
12
|
+
])),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export class Reader {
|
|
16
|
+
store;
|
|
17
|
+
fields;
|
|
18
|
+
/** A write's change index → the ids its delete removed, for `removedBy`. */
|
|
19
|
+
removed = new Map();
|
|
20
|
+
constructor(store, fields) {
|
|
21
|
+
this.store = store;
|
|
22
|
+
this.fields = fields;
|
|
23
|
+
}
|
|
24
|
+
table(model) {
|
|
25
|
+
return modelOf(this.store.tables, model);
|
|
26
|
+
}
|
|
27
|
+
field(model, name) {
|
|
28
|
+
return this.fields.get(model)?.get(name);
|
|
29
|
+
}
|
|
30
|
+
/** The rows a relation of `row` points to. */
|
|
31
|
+
related(model, field, row) {
|
|
32
|
+
if (field.kind === 'scalar')
|
|
33
|
+
return [];
|
|
34
|
+
const target = this.table(field.target);
|
|
35
|
+
if (field.kind === 'one' && field.stored) {
|
|
36
|
+
const key = row[field.name];
|
|
37
|
+
const found = typeof key === 'string' ? target.get(key) : undefined;
|
|
38
|
+
return found === undefined ? [] : [found];
|
|
39
|
+
}
|
|
40
|
+
if (field.kind === 'many' && field.join) {
|
|
41
|
+
// A view reads the join of its relation (D-151).
|
|
42
|
+
const name = `${model}.${field.from ?? field.name}`;
|
|
43
|
+
const ids = this.store.joins.get(name)?.get(row.id);
|
|
44
|
+
return [...(ids ?? [])].flatMap((id) => target.get(id) ?? []);
|
|
45
|
+
}
|
|
46
|
+
return [...target.values()].filter((other) => other[field.inverse] === row.id);
|
|
47
|
+
}
|
|
48
|
+
matches(model, row, filter) {
|
|
49
|
+
if (filter === undefined)
|
|
50
|
+
return true;
|
|
51
|
+
const truths = [];
|
|
52
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
53
|
+
if (value === undefined)
|
|
54
|
+
continue;
|
|
55
|
+
if (key === 'AND' || key === 'OR' || key === 'NOT') {
|
|
56
|
+
const parts = (filter[key] ?? []).map((part) => this.matches(model, row, part));
|
|
57
|
+
if (key === 'AND')
|
|
58
|
+
truths.push(and(parts));
|
|
59
|
+
else if (key === 'OR')
|
|
60
|
+
truths.push(or(parts));
|
|
61
|
+
else
|
|
62
|
+
truths.push(and(parts.map(not)));
|
|
63
|
+
}
|
|
64
|
+
else if (isFilters(value)) {
|
|
65
|
+
throw new Error(`${model}.${key} takes a condition, not a list.`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
truths.push(this.condition(model, row, key, value));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return and(truths);
|
|
72
|
+
}
|
|
73
|
+
condition(model, row, name, condition) {
|
|
74
|
+
if (condition.search !== undefined) {
|
|
75
|
+
return searches(this.fields.get(model), row, condition.search);
|
|
76
|
+
}
|
|
77
|
+
const field = this.field(model, name);
|
|
78
|
+
if (field === undefined || field.kind === 'scalar') {
|
|
79
|
+
return scalar(row[name] ?? null, condition, (value) => sortable(value, field));
|
|
80
|
+
}
|
|
81
|
+
const rows = this.related(model, field, row);
|
|
82
|
+
const test = (filter) => rows.map((other) => this.matches(field.target, other, filter));
|
|
83
|
+
const truths = [];
|
|
84
|
+
if (condition.is !== undefined) {
|
|
85
|
+
truths.push(condition.is === null
|
|
86
|
+
? rows.length === 0
|
|
87
|
+
: test(condition.is).includes(true));
|
|
88
|
+
}
|
|
89
|
+
if (condition.isNot !== undefined) {
|
|
90
|
+
truths.push(condition.isNot === null
|
|
91
|
+
? rows.length > 0
|
|
92
|
+
: !test(condition.isNot).includes(true));
|
|
93
|
+
}
|
|
94
|
+
if (condition.some !== undefined) {
|
|
95
|
+
truths.push(test(condition.some).includes(true));
|
|
96
|
+
}
|
|
97
|
+
if (condition.every !== undefined) {
|
|
98
|
+
truths.push(!test(condition.every).includes(false));
|
|
99
|
+
}
|
|
100
|
+
if (condition.none !== undefined) {
|
|
101
|
+
truths.push(!test(condition.none).includes(true));
|
|
102
|
+
}
|
|
103
|
+
if (condition.removedBy !== undefined) {
|
|
104
|
+
// The key names a row an earlier delete of the write removed.
|
|
105
|
+
const removed = this.removed.get(condition.removedBy);
|
|
106
|
+
if (removed === undefined)
|
|
107
|
+
throw new Error('No such delete.');
|
|
108
|
+
const key = row[field.name];
|
|
109
|
+
truths.push(typeof key === 'string' && removed.has(key));
|
|
110
|
+
}
|
|
111
|
+
return and(truths);
|
|
112
|
+
}
|
|
113
|
+
/** The row `through` reaches from `row`, and its model, if one (D-134). */
|
|
114
|
+
reach(model, row, through = []) {
|
|
115
|
+
let at = row;
|
|
116
|
+
let on = model;
|
|
117
|
+
for (const step of through) {
|
|
118
|
+
const field = this.field(on, step.relation);
|
|
119
|
+
if (field === undefined || field.kind === 'scalar')
|
|
120
|
+
return undefined;
|
|
121
|
+
const [next] = this.related(on, field, at);
|
|
122
|
+
at =
|
|
123
|
+
next !== undefined &&
|
|
124
|
+
this.matches(field.target, next, step.where) === true
|
|
125
|
+
? next
|
|
126
|
+
: undefined;
|
|
127
|
+
if (at === undefined)
|
|
128
|
+
return undefined;
|
|
129
|
+
on = field.target;
|
|
130
|
+
}
|
|
131
|
+
return { model: on, row: at };
|
|
132
|
+
}
|
|
133
|
+
/** A row's sort key: a field, through `one` relations, a count (D-134), a relevance (D-148). */
|
|
134
|
+
key(model, row, order) {
|
|
135
|
+
if (order.relevance !== undefined) {
|
|
136
|
+
return relevance(this.fields.get(model), row, order.relevance);
|
|
137
|
+
}
|
|
138
|
+
const reached = this.reach(model, row, order.through);
|
|
139
|
+
if (reached === undefined)
|
|
140
|
+
return null;
|
|
141
|
+
const { model: on, row: at } = reached;
|
|
142
|
+
if (order.count === undefined) {
|
|
143
|
+
return sortable(at[order.field] ?? null, this.field(on, order.field));
|
|
144
|
+
}
|
|
145
|
+
return this.count(on, at, order.field, order.count);
|
|
146
|
+
}
|
|
147
|
+
/** The rows of a `many` relation of `row` that `where` selects. */
|
|
148
|
+
count(model, row, name, where) {
|
|
149
|
+
const field = this.field(model, name);
|
|
150
|
+
if (field === undefined || field.kind === 'scalar')
|
|
151
|
+
return 0;
|
|
152
|
+
return this.related(model, field, row).filter((other) => this.matches(field.target, other, where) === true).length;
|
|
153
|
+
}
|
|
154
|
+
/** Each row with its sort keys. */
|
|
155
|
+
keyed(model, rows, order) {
|
|
156
|
+
return rows.map((row) => ({
|
|
157
|
+
row,
|
|
158
|
+
keys: order.map((each) => this.key(model, row, each)),
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
/** Filters, orders and pages rows of `model`, as `read` asks. */
|
|
162
|
+
select(model, rows, read) {
|
|
163
|
+
const order = read.orderBy ?? [{ field: 'id', direction: 'asc' }];
|
|
164
|
+
const compare = (a, b) => compareKeys(a.keys, b.keys, order);
|
|
165
|
+
const found = this.keyed(model, rows.filter((row) => this.matches(model, row, read.where) === true), order).toSorted(compare);
|
|
166
|
+
const skip = read.skip ?? 0;
|
|
167
|
+
const take = read.take;
|
|
168
|
+
if (take === 0)
|
|
169
|
+
return [];
|
|
170
|
+
let start = 0;
|
|
171
|
+
let end = found.length;
|
|
172
|
+
if (read.cursor !== undefined) {
|
|
173
|
+
const row = [...this.table(model).values()].find((each) => this.matches(model, each, read.cursor) === true);
|
|
174
|
+
if (row === undefined)
|
|
175
|
+
return [];
|
|
176
|
+
const [cursor] = this.keyed(model, [row], order);
|
|
177
|
+
if (cursor === undefined)
|
|
178
|
+
return [];
|
|
179
|
+
if (take === undefined || take > 0) {
|
|
180
|
+
const index = found.findIndex((each) => compare(each, cursor) >= 0);
|
|
181
|
+
start = index === -1 ? found.length : index;
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
end = found.findLastIndex((each) => compare(each, cursor) <= 0);
|
|
185
|
+
end += 1;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const sorted = found.map((each) => each.row);
|
|
189
|
+
if (take === undefined || take > 0) {
|
|
190
|
+
start += skip;
|
|
191
|
+
return sorted.slice(start, take === undefined ? end : start + take);
|
|
192
|
+
}
|
|
193
|
+
end -= skip;
|
|
194
|
+
return end <= 0 ? [] : sorted.slice(Math.max(start, end + take), end);
|
|
195
|
+
}
|
|
196
|
+
/** A row as the adapter returns it, with the relations `read` includes. */
|
|
197
|
+
output(model, row, read) {
|
|
198
|
+
const result = { id: row.id };
|
|
199
|
+
const fields = read.fields === undefined ? undefined : new Set(read.fields);
|
|
200
|
+
const reads = (name) => fields?.has(name) ?? true;
|
|
201
|
+
for (const [key, value] of Object.entries(row)) {
|
|
202
|
+
const field = this.field(model, key);
|
|
203
|
+
if (!reads(key))
|
|
204
|
+
continue;
|
|
205
|
+
if (field?.kind === 'one') {
|
|
206
|
+
result[key] = typeof value === 'string' ? { id: value } : null;
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
result[key] = copy(value);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
for (const field of this.fields.get(model)?.values() ?? []) {
|
|
213
|
+
if (field.kind === 'one' && !field.stored && reads(field.name)) {
|
|
214
|
+
const [other] = this.related(model, field, row);
|
|
215
|
+
result[field.name] = other === undefined ? null : { id: other.id };
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
for (const [name, nested] of Object.entries(read.include ?? {})) {
|
|
219
|
+
const field = this.field(model, name);
|
|
220
|
+
if (field === undefined || field.kind === 'scalar')
|
|
221
|
+
continue;
|
|
222
|
+
const rows = this.related(model, field, row);
|
|
223
|
+
if (field.kind === 'one') {
|
|
224
|
+
const [other] = rows;
|
|
225
|
+
result[name] =
|
|
226
|
+
other !== undefined &&
|
|
227
|
+
this.matches(field.target, other, nested.where) === true
|
|
228
|
+
? this.output(field.target, other, nested)
|
|
229
|
+
: null;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
result[name] = this.select(field.target, rows, nested).map((other) => this.output(field.target, other, nested));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const counts = Object.entries(read.count ?? {});
|
|
236
|
+
if (counts.length > 0) {
|
|
237
|
+
result['_count'] = Object.fromEntries(counts.map(([name, where]) => [
|
|
238
|
+
name,
|
|
239
|
+
this.count(model, row, name, where),
|
|
240
|
+
]));
|
|
241
|
+
}
|
|
242
|
+
return result;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SchemaField } from './adapter.ts';
|
|
2
|
+
type Fields = ReadonlyMap<string, SchemaField> | undefined;
|
|
3
|
+
/** Whether `row` matches the search `text`; a text with no words matches none. */
|
|
4
|
+
export declare function searches(fields: Fields, row: {
|
|
5
|
+
readonly [field: string]: unknown;
|
|
6
|
+
}, text: string): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* How well `row` matches `text`, as `ts_rank` computes it in a `real`: an
|
|
9
|
+
* `and` of words or a phrase ranks their nearness, any other query its
|
|
10
|
+
* words' occurrences.
|
|
11
|
+
*/
|
|
12
|
+
export declare function relevance(fields: Fields, row: {
|
|
13
|
+
readonly [field: string]: unknown;
|
|
14
|
+
}, text: string): number;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=memory-search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-search.d.ts","sourceRoot":"","sources":["../src/memory-search.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAS/C,KAAK,MAAM,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,SAAS,CAAA;AA+D1D,kFAAkF;AAClF,wBAAgB,QAAQ,CACvB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE;IAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EAC1C,IAAI,EAAE,MAAM,GACV,OAAO,CAKT;AAyCD;;;;GAIG;AACH,wBAAgB,SAAS,CACxB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE;IAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EAC1C,IAAI,EAAE,MAAM,GACV,MAAM,CAaR"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { searchedFields } from './query-search.js';
|
|
2
|
+
const words = (text) => text.toLowerCase().match(/[\p{L}\p{N}]+/gu) ?? [];
|
|
3
|
+
/** A quoted phrase, a `-`, an `or`, or a word and what follows it to a space. */
|
|
4
|
+
const tokens = /"([^"]*)"?|-|or(?![\p{L}\p{N}])|[\p{L}\p{N}][^\s"]*/giu;
|
|
5
|
+
/**
|
|
6
|
+
* `websearch_to_tsquery`'s groups of terms: an `or` between two terms
|
|
7
|
+
* separates them, another is a word. A word of several words, `l'arbre`,
|
|
8
|
+
* is a phrase.
|
|
9
|
+
*/
|
|
10
|
+
function parse(text) {
|
|
11
|
+
const groups = [[]];
|
|
12
|
+
let minus = 0;
|
|
13
|
+
let operand = false;
|
|
14
|
+
for (const { 0: token, 1: quoted, index } of text.matchAll(tokens)) {
|
|
15
|
+
if (token === '-') {
|
|
16
|
+
minus += 1;
|
|
17
|
+
operand = false;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const rest = text.slice(index + token.length);
|
|
21
|
+
if (quoted === undefined &&
|
|
22
|
+
token.toLowerCase() === 'or' &&
|
|
23
|
+
operand &&
|
|
24
|
+
/\S/u.test(rest)) {
|
|
25
|
+
groups.push([]);
|
|
26
|
+
operand = false;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const found = words(quoted ?? token);
|
|
30
|
+
if (found.length > 0)
|
|
31
|
+
groups.at(-1)?.push({ words: found, minus });
|
|
32
|
+
minus = 0;
|
|
33
|
+
operand = true;
|
|
34
|
+
}
|
|
35
|
+
return groups.filter((group) => group.length > 0);
|
|
36
|
+
}
|
|
37
|
+
/** The searched fields of `row`, in declaration order, as one document. */
|
|
38
|
+
function documentOf(fields, row) {
|
|
39
|
+
const texts = searchedFields(fields?.values() ?? []).map((name) => row[name]);
|
|
40
|
+
const result = new Map();
|
|
41
|
+
const all = texts.filter((text) => typeof text === 'string').join(' ');
|
|
42
|
+
for (const [at, word] of words(all).entries()) {
|
|
43
|
+
result.set(word, [...(result.get(word) ?? []), at + 1]);
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
/** Whether the words of a phrase follow each other in `found`. */
|
|
48
|
+
function has(found, [first = '', ...rest]) {
|
|
49
|
+
return (found.get(first) ?? []).some((at) => rest.every((word, index) => found.get(word)?.includes(at + index + 1)));
|
|
50
|
+
}
|
|
51
|
+
/** Whether `row` matches the search `text`; a text with no words matches none. */
|
|
52
|
+
export function searches(fields, row, text) {
|
|
53
|
+
const found = documentOf(fields, row);
|
|
54
|
+
return parse(text).some((group) => group.every((term) => has(found, term.words) === (term.minus % 2 === 0)));
|
|
55
|
+
}
|
|
56
|
+
/** An unweighted word's weight in `ts_rank`. */
|
|
57
|
+
const weight = 0.1;
|
|
58
|
+
/** `ts_rank`'s `calc_rank_or`: each word found, by its occurrences. */
|
|
59
|
+
function rankOr(found, items) {
|
|
60
|
+
let sum = 0;
|
|
61
|
+
for (const item of items) {
|
|
62
|
+
const positions = found.get(item) ?? [];
|
|
63
|
+
if (positions.length === 0)
|
|
64
|
+
continue;
|
|
65
|
+
let occurrences = 0;
|
|
66
|
+
for (const at of positions.keys())
|
|
67
|
+
occurrences += weight / (at + 1) ** 2;
|
|
68
|
+
// The sum of 1/i² tends to π²/6.
|
|
69
|
+
sum += occurrences / 1.64493406685;
|
|
70
|
+
}
|
|
71
|
+
return sum / items.length;
|
|
72
|
+
}
|
|
73
|
+
/** How near two positions are in `calc_rank_and`. */
|
|
74
|
+
const nearness = (distance) => distance > 100 ? 1e-30 : 1 / (1.005 + 0.05 * Math.exp(distance / 1.5 - 2));
|
|
75
|
+
/** `ts_rank`'s `calc_rank_and`: each pair of words found, by their distance. */
|
|
76
|
+
function rankAnd(found, items) {
|
|
77
|
+
let rank = -1;
|
|
78
|
+
const lists = items.map((item) => found.get(item) ?? []);
|
|
79
|
+
for (const [index, mine] of lists.entries()) {
|
|
80
|
+
for (const theirs of lists.slice(0, index)) {
|
|
81
|
+
for (const a of mine) {
|
|
82
|
+
for (const b of theirs) {
|
|
83
|
+
if (a === b)
|
|
84
|
+
continue;
|
|
85
|
+
const near = Math.sqrt(weight * weight * nearness(Math.abs(a - b)));
|
|
86
|
+
rank = rank < 0 ? near : 1 - (1 - rank) * (1 - near);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return rank;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* How well `row` matches `text`, as `ts_rank` computes it in a `real`: an
|
|
95
|
+
* `and` of words or a phrase ranks their nearness, any other query its
|
|
96
|
+
* words' occurrences.
|
|
97
|
+
*/
|
|
98
|
+
export function relevance(fields, row, text) {
|
|
99
|
+
const found = documentOf(fields, row);
|
|
100
|
+
const groups = parse(text);
|
|
101
|
+
const terms = groups.flat();
|
|
102
|
+
if (found.size === 0 || terms.length === 0)
|
|
103
|
+
return 0;
|
|
104
|
+
const items = [...new Set(terms.flatMap((term) => term.words))];
|
|
105
|
+
const [only] = terms;
|
|
106
|
+
const and = groups.length === 1 &&
|
|
107
|
+
(terms.length > 1 || (only?.minus === 0 && only.words.length > 1));
|
|
108
|
+
const rank = and && items.length > 1 ? rankAnd(found, items) : rankOr(found, items);
|
|
109
|
+
return Math.fround(rank < 0 ? 1e-20 : rank);
|
|
110
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SchemaField, Sort } from './adapter.ts';
|
|
2
|
+
/** Equality as PostgreSQL's: `-0` is `0`, json keys come in any order. */
|
|
3
|
+
export declare function same(a: unknown, b: unknown): boolean;
|
|
4
|
+
/** A value as it sorts: a decimal as its units, by value (D-145). */
|
|
5
|
+
export declare const sortable: (value: unknown, field: SchemaField | undefined) => unknown;
|
|
6
|
+
/**
|
|
7
|
+
* Strings compare by code point, as PostgreSQL's `C` collation (D-94);
|
|
8
|
+
* dates, numbers and booleans by their number, a decimal's units exactly.
|
|
9
|
+
* Json values are not sorted.
|
|
10
|
+
*/
|
|
11
|
+
export declare function compareValues(a: unknown, b: unknown): number;
|
|
12
|
+
/**
|
|
13
|
+
* `null` sorts as `nulls` says, by default last ascending and first
|
|
14
|
+
* descending, as in PostgreSQL (D-149).
|
|
15
|
+
*/
|
|
16
|
+
export declare function compareKeys(a: readonly unknown[], b: readonly unknown[], order: readonly Sort[]): number;
|
|
17
|
+
/** A stored value the caller may change without changing the store. */
|
|
18
|
+
export declare function copy(value: unknown): unknown;
|
|
19
|
+
/** A text operator; the `where` check lets only strings reach it. */
|
|
20
|
+
export declare function text(value: unknown, operand: unknown, test: (value: string, operand: string) => boolean): boolean;
|
|
21
|
+
/** A string lowered for `mode: 'insensitive'` (D-140), any other value as is. */
|
|
22
|
+
export declare const lower: (value: unknown) => unknown;
|
|
23
|
+
//# sourceMappingURL=memory-values.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-values.d.ts","sourceRoot":"","sources":["../src/memory-values.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAIrD,0EAA0E;AAC1E,wBAAgB,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAcpD;AAQD,qEAAqE;AACrE,eAAO,MAAM,QAAQ,UACb,OAAO,SACP,WAAW,GAAG,SAAS,KAC5B,OAKM,CAAA;AAET;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,MAAM,CAY5D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAC1B,CAAC,EAAE,SAAS,OAAO,EAAE,EACrB,CAAC,EAAE,SAAS,OAAO,EAAE,EACrB,KAAK,EAAE,SAAS,IAAI,EAAE,GACpB,MAAM,CAcR;AAED,uEAAuE;AACvE,wBAAgB,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAK5C;AAED,qEAAqE;AACrE,wBAAgB,IAAI,CACnB,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,GAC/C,OAAO,CAMT;AAED,iFAAiF;AACjF,eAAO,MAAM,KAAK,UAAW,OAAO,KAAG,OACiB,CAAA"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { unitsOf } from './decimal.js';
|
|
2
|
+
import { isObject } from './query-where.js';
|
|
3
|
+
/** Equality as PostgreSQL's: `-0` is `0`, json keys come in any order. */
|
|
4
|
+
export function same(a, b) {
|
|
5
|
+
if (a instanceof Date && b instanceof Date)
|
|
6
|
+
return a.getTime() === b.getTime();
|
|
7
|
+
if (Array.isArray(a) && Array.isArray(b))
|
|
8
|
+
return (a.length === b.length && a.every((item, index) => same(item, b[index])));
|
|
9
|
+
if (isObject(a) && isObject(b)) {
|
|
10
|
+
const keys = Object.keys(a);
|
|
11
|
+
return (keys.length === Object.keys(b).length &&
|
|
12
|
+
keys.every((key) => Object.hasOwn(b, key) && same(a[key], b[key])));
|
|
13
|
+
}
|
|
14
|
+
return a === b;
|
|
15
|
+
}
|
|
16
|
+
/** A surrogate sorts above U+FFFF, as the code point it is part of. */
|
|
17
|
+
const weight = (unit) => {
|
|
18
|
+
if (unit >= 0xd8_00 && unit <= 0xdf_ff)
|
|
19
|
+
return unit + 0x20_00;
|
|
20
|
+
return unit >= 0xe0_00 ? unit - 0x8_00 : unit;
|
|
21
|
+
};
|
|
22
|
+
/** A value as it sorts: a decimal as its units, by value (D-145). */
|
|
23
|
+
export const sortable = (value, field) => field?.kind === 'scalar' &&
|
|
24
|
+
field.type === 'decimal' &&
|
|
25
|
+
typeof value === 'string'
|
|
26
|
+
? unitsOf(value, field.scale ?? 0)
|
|
27
|
+
: value;
|
|
28
|
+
/**
|
|
29
|
+
* Strings compare by code point, as PostgreSQL's `C` collation (D-94);
|
|
30
|
+
* dates, numbers and booleans by their number, a decimal's units exactly.
|
|
31
|
+
* Json values are not sorted.
|
|
32
|
+
*/
|
|
33
|
+
export function compareValues(a, b) {
|
|
34
|
+
if (typeof a === 'bigint' && typeof b === 'bigint') {
|
|
35
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
36
|
+
}
|
|
37
|
+
if (typeof a === 'string' && typeof b === 'string') {
|
|
38
|
+
for (let index = 0; index < Math.min(a.length, b.length); index++) {
|
|
39
|
+
const order = weight(a.charCodeAt(index)) - weight(b.charCodeAt(index));
|
|
40
|
+
if (order !== 0)
|
|
41
|
+
return order;
|
|
42
|
+
}
|
|
43
|
+
return a.length - b.length;
|
|
44
|
+
}
|
|
45
|
+
return Number(a) - Number(b);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* `null` sorts as `nulls` says, by default last ascending and first
|
|
49
|
+
* descending, as in PostgreSQL (D-149).
|
|
50
|
+
*/
|
|
51
|
+
export function compareKeys(a, b, order) {
|
|
52
|
+
for (const [at, { direction, nulls }] of order.entries()) {
|
|
53
|
+
const left = a[at] ?? null;
|
|
54
|
+
const right = b[at] ?? null;
|
|
55
|
+
if (left === null || right === null) {
|
|
56
|
+
if (left === right)
|
|
57
|
+
continue;
|
|
58
|
+
const last = (nulls ?? (direction === 'asc' ? 'last' : 'first')) === 'last';
|
|
59
|
+
return (left === null) === last ? 1 : -1;
|
|
60
|
+
}
|
|
61
|
+
const result = compareValues(left, right);
|
|
62
|
+
if (result !== 0)
|
|
63
|
+
return direction === 'asc' ? result : -result;
|
|
64
|
+
}
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
/** A stored value the caller may change without changing the store. */
|
|
68
|
+
export function copy(value) {
|
|
69
|
+
if (value instanceof Date)
|
|
70
|
+
return new Date(value.getTime());
|
|
71
|
+
return typeof value === 'object' && value !== null
|
|
72
|
+
? structuredClone(value)
|
|
73
|
+
: value;
|
|
74
|
+
}
|
|
75
|
+
/** A text operator; the `where` check lets only strings reach it. */
|
|
76
|
+
export function text(value, operand, test) {
|
|
77
|
+
return (typeof value === 'string' &&
|
|
78
|
+
typeof operand === 'string' &&
|
|
79
|
+
test(value, operand));
|
|
80
|
+
}
|
|
81
|
+
/** A string lowered for `mode: 'insensitive'` (D-140), any other value as is. */
|
|
82
|
+
export const lower = (value) => typeof value === 'string' ? value.toLowerCase() : value;
|
package/dist/memory.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAsC,MAAM,cAAc,CAAA;AA0D/E,0EAA0E;AAC1E,wBAAgB,MAAM,IAAI,OAAO,CA8GhC"}
|