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
package/src/index.ts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// The kernel's public surface (D-01).
|
|
2
|
+
export type {
|
|
3
|
+
Adapter,
|
|
4
|
+
Aggregate,
|
|
5
|
+
AggregateRead,
|
|
6
|
+
Arithmetic,
|
|
7
|
+
Change,
|
|
8
|
+
Changed,
|
|
9
|
+
Check,
|
|
10
|
+
Condition,
|
|
11
|
+
CountRead,
|
|
12
|
+
Feed,
|
|
13
|
+
Filter,
|
|
14
|
+
GroupKey,
|
|
15
|
+
ListUpdate,
|
|
16
|
+
Migration,
|
|
17
|
+
Migrations,
|
|
18
|
+
Nested,
|
|
19
|
+
Order,
|
|
20
|
+
Read,
|
|
21
|
+
Row,
|
|
22
|
+
Run,
|
|
23
|
+
ScalarType,
|
|
24
|
+
Schema,
|
|
25
|
+
SchemaField,
|
|
26
|
+
SchemaModel,
|
|
27
|
+
Sort,
|
|
28
|
+
Statement,
|
|
29
|
+
Stored,
|
|
30
|
+
Transaction,
|
|
31
|
+
Write,
|
|
32
|
+
} from './adapter.ts'
|
|
33
|
+
export {
|
|
34
|
+
CheckFailed,
|
|
35
|
+
feedFields,
|
|
36
|
+
feedIds,
|
|
37
|
+
MigrationFailed,
|
|
38
|
+
OutOfRange,
|
|
39
|
+
RelationViolation,
|
|
40
|
+
UniqueViolation,
|
|
41
|
+
} from './adapter.ts'
|
|
42
|
+
export type { Logger, MasterKey } from './app-options.ts'
|
|
43
|
+
export { defineApp } from './define-app.ts'
|
|
44
|
+
export { defineEnum } from './define-enum.ts'
|
|
45
|
+
export type {
|
|
46
|
+
FieldShapes,
|
|
47
|
+
ModelFields,
|
|
48
|
+
ModelIndexes,
|
|
49
|
+
ModelOf,
|
|
50
|
+
} from './define-model.ts'
|
|
51
|
+
export { defineModel } from './define-model.ts'
|
|
52
|
+
export type { ErrorCode, Issue } from './errors.ts'
|
|
53
|
+
export { InvalidQuery, PublicError, Refused } from './errors.ts'
|
|
54
|
+
export type {
|
|
55
|
+
DecimalOptions,
|
|
56
|
+
Enum,
|
|
57
|
+
Field,
|
|
58
|
+
FieldBuilders,
|
|
59
|
+
JsonOptions,
|
|
60
|
+
JsonValue,
|
|
61
|
+
ListOptions,
|
|
62
|
+
Many,
|
|
63
|
+
ManyOptions,
|
|
64
|
+
One,
|
|
65
|
+
ScalarOptions,
|
|
66
|
+
SingleOptions,
|
|
67
|
+
StringOptions,
|
|
68
|
+
} from './fields.ts'
|
|
69
|
+
export { defineFunction, defineType } from './define-function.ts'
|
|
70
|
+
export type {
|
|
71
|
+
FieldType,
|
|
72
|
+
FieldTypeDefinition,
|
|
73
|
+
FieldTypeOptions,
|
|
74
|
+
} from './field-type.ts'
|
|
75
|
+
export { defineFieldType } from './field-type.ts'
|
|
76
|
+
export { isLocalHost } from './hosts.ts'
|
|
77
|
+
export type {
|
|
78
|
+
Client,
|
|
79
|
+
CookieOptions,
|
|
80
|
+
FunctionPlugin,
|
|
81
|
+
FunctionShape,
|
|
82
|
+
Nullable,
|
|
83
|
+
ObjectType,
|
|
84
|
+
OutputSpec,
|
|
85
|
+
ServerFunction,
|
|
86
|
+
} from './function.ts'
|
|
87
|
+
export { memory } from './memory.ts'
|
|
88
|
+
export type { App, FindOperation, IndexShape, Model } from './model.ts'
|
|
89
|
+
export type {
|
|
90
|
+
ExposedFunction,
|
|
91
|
+
ExposedModel,
|
|
92
|
+
ExposedOutput,
|
|
93
|
+
ExposedVirtual,
|
|
94
|
+
ExposedType,
|
|
95
|
+
ModelQueries,
|
|
96
|
+
ModelUse,
|
|
97
|
+
OutputForm,
|
|
98
|
+
PluginOf,
|
|
99
|
+
PluginTypes,
|
|
100
|
+
UseOf,
|
|
101
|
+
} from './plugin.ts'
|
|
102
|
+
export type { Payload, Queries } from './query.ts'
|
|
103
|
+
export { definePlugin } from './plugin.ts'
|
|
104
|
+
export type {
|
|
105
|
+
Caller,
|
|
106
|
+
CallerRule,
|
|
107
|
+
Identity,
|
|
108
|
+
Register,
|
|
109
|
+
UserCallerKeys,
|
|
110
|
+
UserOf,
|
|
111
|
+
} from './rules.ts'
|
|
112
|
+
export { allOf, allow, anyOf, isMaster, master } from './rules.ts'
|
|
113
|
+
export { transaction } from './transaction.ts'
|
|
114
|
+
export type {
|
|
115
|
+
ArgsOf,
|
|
116
|
+
CreateDataOf,
|
|
117
|
+
IncludeOf,
|
|
118
|
+
InputOf,
|
|
119
|
+
OrderByOf,
|
|
120
|
+
OutputOf,
|
|
121
|
+
RecordOf,
|
|
122
|
+
SelectOf,
|
|
123
|
+
UpdateDataOf,
|
|
124
|
+
WhereOf,
|
|
125
|
+
} from './types.ts'
|
package/src/internal.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// What official packages read from an application (D-130), kept off the
|
|
2
|
+
// documented surface: new runs of it on another database, quieter, the
|
|
3
|
+
// running plugins' APIs, what raw SQL and tests on the declared database
|
|
4
|
+
// need (D-137), and what live reads need (D-154).
|
|
5
|
+
import type { Adapter } from './adapter.ts'
|
|
6
|
+
import { internalsOf } from './app-internals.ts'
|
|
7
|
+
import type { Logger } from './app-options.ts'
|
|
8
|
+
import { consoleLogger } from './console-logger.ts'
|
|
9
|
+
import type { Lifecycle } from './lifecycle.ts'
|
|
10
|
+
import { lifecycle } from './lifecycle.ts'
|
|
11
|
+
import { current } from './running.ts'
|
|
12
|
+
|
|
13
|
+
export type { Lifecycle }
|
|
14
|
+
export type { Scratch } from './scratch.ts'
|
|
15
|
+
export { scratchable, scratchOf } from './scratch.ts'
|
|
16
|
+
export { isRow } from './field-codec.ts'
|
|
17
|
+
export { joining } from './transaction.ts'
|
|
18
|
+
export { issueOf } from './write-data.ts'
|
|
19
|
+
export { decimalPattern } from './decimal.ts'
|
|
20
|
+
export type { Recorded } from './recorder.ts'
|
|
21
|
+
export { recording } from './recorder.ts'
|
|
22
|
+
export type { LivePlan } from './live.ts'
|
|
23
|
+
export {
|
|
24
|
+
inMemory,
|
|
25
|
+
liveSchema,
|
|
26
|
+
livePlan,
|
|
27
|
+
matches,
|
|
28
|
+
servedRows,
|
|
29
|
+
sortKeys,
|
|
30
|
+
storedRows,
|
|
31
|
+
} from './live.ts'
|
|
32
|
+
export { compareKeys } from './memory-values.ts'
|
|
33
|
+
|
|
34
|
+
/** `logger` without its info lines. */
|
|
35
|
+
function quieted(logger: Logger): Logger {
|
|
36
|
+
return {
|
|
37
|
+
info: () => undefined,
|
|
38
|
+
warn: logger.warn.bind(logger),
|
|
39
|
+
error: logger.error.bind(logger),
|
|
40
|
+
child: (bindings) => quieted(logger.child(bindings)),
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** The application's database, and new runs of it on another (D-130). */
|
|
45
|
+
export type QuietRuns = {
|
|
46
|
+
readonly declared: Adapter
|
|
47
|
+
/** A run on `database`, without info lines. */
|
|
48
|
+
readonly on: (database: Adapter) => Lifecycle
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Runs of the application `defineApp` returned as `app`, or `undefined` for
|
|
53
|
+
* another value.
|
|
54
|
+
*/
|
|
55
|
+
export function quietRuns(app: unknown): QuietRuns | undefined {
|
|
56
|
+
const options = internalsOf(app)?.options
|
|
57
|
+
if (options === undefined) return undefined
|
|
58
|
+
const logger = quieted(options.logger ?? consoleLogger())
|
|
59
|
+
return {
|
|
60
|
+
declared: options.database,
|
|
61
|
+
on: (database) => lifecycle({ ...options, database, logger }),
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** The running application's plugin API named `name`, if any. */
|
|
66
|
+
export function runningApi(name: string): unknown {
|
|
67
|
+
return current()?.apis.get(name)
|
|
68
|
+
}
|
package/src/lifecycle.ts
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// `start` and `stop` (D-59, D-91): the database, the plugins' APIs, their
|
|
2
|
+
// `start` and `stop`, the operations still running, and `SIGTERM`.
|
|
3
|
+
import type { Adapter, Schema } from './adapter.ts'
|
|
4
|
+
import type { Logger, MasterKey } from './app-options.ts'
|
|
5
|
+
import type { PluginCaller } from './complete.ts'
|
|
6
|
+
import { completer } from './complete.ts'
|
|
7
|
+
import { consoleLogger } from './console-logger.ts'
|
|
8
|
+
import { feedOf } from './feed.ts'
|
|
9
|
+
import type { PluginIdentify } from './identify.ts'
|
|
10
|
+
import { identifier } from './identify.ts'
|
|
11
|
+
import { checkVersions } from './manifest.ts'
|
|
12
|
+
import { checked, synced } from './migrate.ts'
|
|
13
|
+
import type { Installed } from './plugin-app.ts'
|
|
14
|
+
import {
|
|
15
|
+
buildApis,
|
|
16
|
+
installed,
|
|
17
|
+
pluginCallers,
|
|
18
|
+
pluginIdentifiers,
|
|
19
|
+
withContexts,
|
|
20
|
+
} from './plugin-app.ts'
|
|
21
|
+
import type { Running } from './running.ts'
|
|
22
|
+
import { register, unregister, Work } from './running.ts'
|
|
23
|
+
import { resolve } from './schema.ts'
|
|
24
|
+
|
|
25
|
+
export type Lifecycle = {
|
|
26
|
+
readonly start: () => Promise<void>
|
|
27
|
+
readonly stop: () => Promise<void>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type Started = {
|
|
31
|
+
readonly app: Running
|
|
32
|
+
readonly plugins: readonly Installed[]
|
|
33
|
+
readonly onSigterm: () => void
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Stops `plugins` in reverse order, each even when another fails. */
|
|
37
|
+
async function stopped(plugins: readonly Installed[]): Promise<unknown[]> {
|
|
38
|
+
const errors: unknown[] = []
|
|
39
|
+
for (const { code, context } of plugins.toReversed()) {
|
|
40
|
+
if (code.stop === undefined) continue
|
|
41
|
+
try {
|
|
42
|
+
await Reflect.apply(code.stop, undefined, [context])
|
|
43
|
+
} catch (error) {
|
|
44
|
+
context.logger.error({ err: error }, 'The plugin failed to stop.')
|
|
45
|
+
errors.push(error)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return errors
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type LifecycleOptions = {
|
|
52
|
+
readonly database: Adapter
|
|
53
|
+
readonly plugins?: readonly unknown[]
|
|
54
|
+
/** The application's `defineFunction` values (D-27). */
|
|
55
|
+
readonly functions?: readonly unknown[]
|
|
56
|
+
readonly models: readonly unknown[]
|
|
57
|
+
readonly logger?: Logger
|
|
58
|
+
readonly masterKey?: MasterKey
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Once stdout and stderr have written what they were given. */
|
|
62
|
+
const written = () =>
|
|
63
|
+
Promise.all(
|
|
64
|
+
[process.stdout, process.stderr].map(
|
|
65
|
+
(stream) => new Promise((done) => stream.write('', done)),
|
|
66
|
+
),
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
/** The application's schema, or a message on what is wrong with it. */
|
|
70
|
+
export function schemaOf(options: LifecycleOptions): Schema {
|
|
71
|
+
const { plugins } = installed(options.plugins ?? [])
|
|
72
|
+
return resolve(
|
|
73
|
+
options.models,
|
|
74
|
+
plugins.map((plugin) => plugin.code),
|
|
75
|
+
).schema
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** The kernel's logger: the application's, or JSON lines. */
|
|
79
|
+
export const kernelLogger = (options: LifecycleOptions): Logger =>
|
|
80
|
+
(options.logger ?? consoleLogger()).child({ name: 'ultimabase' })
|
|
81
|
+
|
|
82
|
+
/** Syncs a development database, or checks a production one (D-105). */
|
|
83
|
+
async function follow(
|
|
84
|
+
database: Adapter,
|
|
85
|
+
schema: Schema,
|
|
86
|
+
logger: Logger,
|
|
87
|
+
): Promise<void> {
|
|
88
|
+
try {
|
|
89
|
+
await (process.env['NODE_ENV'] === 'production'
|
|
90
|
+
? checked(database, schema, logger)
|
|
91
|
+
: synced(database, schema, logger, false))
|
|
92
|
+
} catch (error) {
|
|
93
|
+
await database.stop()
|
|
94
|
+
throw error
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function lifecycle(options: LifecycleOptions): Lifecycle {
|
|
99
|
+
const { database, models } = options
|
|
100
|
+
let started: Started | undefined
|
|
101
|
+
let stopping: Promise<void> | undefined
|
|
102
|
+
let starting = false
|
|
103
|
+
|
|
104
|
+
const shutDown = async ({ app, plugins, onSigterm }: Started) => {
|
|
105
|
+
process.off('SIGTERM', onSigterm)
|
|
106
|
+
const errors = await stopped(plugins)
|
|
107
|
+
// A plugin's stop may still query; the database closes last.
|
|
108
|
+
await app.work.settled()
|
|
109
|
+
unregister(app)
|
|
110
|
+
started = undefined
|
|
111
|
+
await database.stop()
|
|
112
|
+
app.logger.info('Application stopped.')
|
|
113
|
+
if (errors.length > 0) throw errors[0]
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const stop = async (): Promise<void> => {
|
|
117
|
+
if (stopping !== undefined) return stopping
|
|
118
|
+
if (started === undefined) return
|
|
119
|
+
stopping = shutDown(started).finally(() => {
|
|
120
|
+
stopping = undefined
|
|
121
|
+
})
|
|
122
|
+
return stopping
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const start = async (): Promise<void> => {
|
|
126
|
+
if (started !== undefined || starting) {
|
|
127
|
+
throw new Error('The application is running.')
|
|
128
|
+
}
|
|
129
|
+
// Set before the first await: a second start meanwhile is refused.
|
|
130
|
+
starting = true
|
|
131
|
+
try {
|
|
132
|
+
await launch()
|
|
133
|
+
} finally {
|
|
134
|
+
starting = false
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const launch = async (): Promise<void> => {
|
|
139
|
+
const { plugins: records, apiOrder } = installed(options.plugins ?? [])
|
|
140
|
+
const resolved = resolve(
|
|
141
|
+
models,
|
|
142
|
+
records.map((plugin) => plugin.code),
|
|
143
|
+
)
|
|
144
|
+
const base = options.logger ?? consoleLogger()
|
|
145
|
+
const logger = base.child({ name: 'ultimabase' })
|
|
146
|
+
checkVersions(records, logger)
|
|
147
|
+
// Plugins identify with their contexts, which hold identify.
|
|
148
|
+
const identifiers: PluginIdentify[] = []
|
|
149
|
+
const callers: PluginCaller[] = []
|
|
150
|
+
const complete = completer(callers)
|
|
151
|
+
const identify = identifier(
|
|
152
|
+
options.masterKey,
|
|
153
|
+
logger,
|
|
154
|
+
identifiers,
|
|
155
|
+
complete,
|
|
156
|
+
)
|
|
157
|
+
const { plugins, functions } = withContexts(
|
|
158
|
+
apiOrder,
|
|
159
|
+
base,
|
|
160
|
+
identify,
|
|
161
|
+
resolved,
|
|
162
|
+
options.functions ?? [],
|
|
163
|
+
)
|
|
164
|
+
identifiers.push(...pluginIdentifiers(records, plugins))
|
|
165
|
+
callers.push(...pluginCallers(records, plugins))
|
|
166
|
+
await database.start(resolved.schema, logger, feedOf(records, plugins))
|
|
167
|
+
const apis = new Map<string, unknown>()
|
|
168
|
+
const app: Running = {
|
|
169
|
+
resolved,
|
|
170
|
+
adapter: database,
|
|
171
|
+
logger,
|
|
172
|
+
apis,
|
|
173
|
+
functions: functions.definitions,
|
|
174
|
+
work: new Work(),
|
|
175
|
+
complete,
|
|
176
|
+
}
|
|
177
|
+
const ran: Installed[] = []
|
|
178
|
+
try {
|
|
179
|
+
await follow(database, resolved.schema, logger)
|
|
180
|
+
register(app)
|
|
181
|
+
// An API may read the APIs it needs as it is built (D-89).
|
|
182
|
+
buildApis(plugins, apis)
|
|
183
|
+
for (const plugin of plugins) {
|
|
184
|
+
const { code, context } = plugin
|
|
185
|
+
if (code.start !== undefined) {
|
|
186
|
+
await Reflect.apply(code.start, undefined, [context])
|
|
187
|
+
}
|
|
188
|
+
ran.push(plugin)
|
|
189
|
+
}
|
|
190
|
+
} catch (error) {
|
|
191
|
+
await stopped(ran)
|
|
192
|
+
unregister(app)
|
|
193
|
+
await database.stop()
|
|
194
|
+
throw error
|
|
195
|
+
}
|
|
196
|
+
const onSigterm = () => {
|
|
197
|
+
void stop()
|
|
198
|
+
.catch((error: unknown) => {
|
|
199
|
+
logger.error({ err: error }, 'The application stopped with an error.')
|
|
200
|
+
})
|
|
201
|
+
// The last lines first: a pipe may write them later.
|
|
202
|
+
.then(written)
|
|
203
|
+
.finally(() => {
|
|
204
|
+
// Its listener is gone: the signal now ends the process.
|
|
205
|
+
process.kill(process.pid, 'SIGTERM')
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
process.once('SIGTERM', onSigterm)
|
|
209
|
+
started = { app, plugins, onSigterm }
|
|
210
|
+
logger.info('Application started.')
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return { start, stop }
|
|
214
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// List updates (D-149): `{ set }`, `{ push }`, `{ pushUnique }` or
|
|
2
|
+
// `{ remove }` on a list field, with an element or a list of them, computed
|
|
3
|
+
// on the row as the write finds it, as a number update is (D-132).
|
|
4
|
+
import type { ListUpdate } from './adapter.ts'
|
|
5
|
+
import { InvalidQuery } from './errors.ts'
|
|
6
|
+
import { isObject } from './query-where.ts'
|
|
7
|
+
import type { ModelInfo } from './schema.ts'
|
|
8
|
+
import type { Draft } from './write-data.ts'
|
|
9
|
+
import { invalid, issueOf } from './write-data.ts'
|
|
10
|
+
|
|
11
|
+
const operations = ['set', 'push', 'pushUnique', 'remove'] as const
|
|
12
|
+
type Operation = (typeof operations)[number]
|
|
13
|
+
|
|
14
|
+
const isOperation = (key: unknown): key is Operation =>
|
|
15
|
+
operations.some((operation) => operation === key)
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Takes the operations out of an update's draft: `{ set }` becomes its
|
|
19
|
+
* list, an operation by `undefined` leaves its field as it is (D-84), and
|
|
20
|
+
* each other one comes back to be computed on the row.
|
|
21
|
+
*/
|
|
22
|
+
export function listUpdates(
|
|
23
|
+
model: ModelInfo,
|
|
24
|
+
draft: Draft,
|
|
25
|
+
at: readonly (string | number)[] = [],
|
|
26
|
+
): Map<string, ListUpdate> {
|
|
27
|
+
const lists = new Map<string, ListUpdate>()
|
|
28
|
+
for (const [name, value] of Object.entries(draft)) {
|
|
29
|
+
const field = model.fields.get(name)
|
|
30
|
+
// A field type's value is its own, as for numbers (D-132).
|
|
31
|
+
const plain = field?.kind === 'scalar' && field.list && !field.codec
|
|
32
|
+
if (!plain || !isObject(value)) continue
|
|
33
|
+
const keys = Object.keys(value)
|
|
34
|
+
const used = operations.filter((key) => value[key] !== undefined)
|
|
35
|
+
if (keys.length === 0 || used.length > 1 || !keys.every(isOperation)) {
|
|
36
|
+
const path = ['data', ...at, name].join('.')
|
|
37
|
+
throw new InvalidQuery(
|
|
38
|
+
path,
|
|
39
|
+
`${path} takes a list or one of ${operations.join(', ')}.`,
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
delete draft[name]
|
|
43
|
+
const [operation] = used
|
|
44
|
+
if (operation === undefined) continue
|
|
45
|
+
const given = value[operation]
|
|
46
|
+
const elements: readonly unknown[] = Array.isArray(given) ? given : [given]
|
|
47
|
+
const issue = issueOf(elements, field)
|
|
48
|
+
if (issue !== undefined) {
|
|
49
|
+
throw invalid([{ path: [...at, name], message: issue }])
|
|
50
|
+
}
|
|
51
|
+
if (operation === 'set') draft[name] = elements
|
|
52
|
+
else lists.set(name, { operation, elements })
|
|
53
|
+
}
|
|
54
|
+
return lists
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** A list update's result on `current`, the elements in their order. */
|
|
58
|
+
export function listed(
|
|
59
|
+
current: unknown,
|
|
60
|
+
{ operation, elements }: ListUpdate,
|
|
61
|
+
): unknown[] {
|
|
62
|
+
const from: readonly unknown[] = Array.isArray(current) ? current : []
|
|
63
|
+
if (operation === 'push') return [...from, ...elements]
|
|
64
|
+
if (operation === 'remove') {
|
|
65
|
+
return from.filter((item) => !elements.includes(item))
|
|
66
|
+
}
|
|
67
|
+
const added = elements.filter(
|
|
68
|
+
(item, index) => !from.includes(item) && elements.indexOf(item) === index,
|
|
69
|
+
)
|
|
70
|
+
return [...from, ...added]
|
|
71
|
+
}
|
package/src/live.ts
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// What the realtime plugin asks the kernel (D-154): a live read's effective
|
|
2
|
+
// filter and order, planned once for its caller, and, on a stored row, that
|
|
3
|
+
// filter and the row's sort keys, tested as `memory()` reads.
|
|
4
|
+
import { accessFor, and } from './access.ts'
|
|
5
|
+
import type { Filter, Nested, Order, Read, Row, Schema } from './adapter.ts'
|
|
6
|
+
import { rootFind } from './engine.ts'
|
|
7
|
+
import { decoded, isRow } from './field-codec.ts'
|
|
8
|
+
import { Reader } from './memory-read.ts'
|
|
9
|
+
import { compareKeys, sortable } from './memory-values.ts'
|
|
10
|
+
import { isFilters } from './memory-conditions.ts'
|
|
11
|
+
import { plan, uniqueWhere } from './query-args.ts'
|
|
12
|
+
import { modelOf } from './query-where.ts'
|
|
13
|
+
import { isObject } from './query-values.ts'
|
|
14
|
+
import type { Caller } from './rules.ts'
|
|
15
|
+
import type { Running } from './running.ts'
|
|
16
|
+
import { current } from './running.ts'
|
|
17
|
+
import { QueryScope, planned } from './scope.ts'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The rows a live read follows, and their order, ending with `id`; `filter`
|
|
21
|
+
* is the read's own part of `where`, `rights` the part the caller's read
|
|
22
|
+
* rules and `beforeFind` add, and
|
|
23
|
+
* `include`, `count` and `fields` what its selection reads, as the adapter
|
|
24
|
+
* receives them.
|
|
25
|
+
*/
|
|
26
|
+
export type LivePlan = Pick<Nested, 'include' | 'count' | 'fields'> & {
|
|
27
|
+
readonly where: Filter | undefined
|
|
28
|
+
readonly filter: Filter | undefined
|
|
29
|
+
readonly rights: Filter | undefined
|
|
30
|
+
readonly orderBy: readonly Order[]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function started(): Running {
|
|
34
|
+
const app = current()
|
|
35
|
+
if (app === undefined) throw new Error('No application is running.')
|
|
36
|
+
return app
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const shapeKeys = ['select', 'include', 'omit']
|
|
40
|
+
const liveKeys = new Set(['where', 'orderBy', ...shapeKeys])
|
|
41
|
+
const rowKeys = new Set(shapeKeys)
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* `args` as `caller` reads `model`: its read rules and every `beforeFind`
|
|
45
|
+
* included. A live row's `where` names one row, as `findUnique`'s.
|
|
46
|
+
*/
|
|
47
|
+
export async function livePlan(
|
|
48
|
+
model: string,
|
|
49
|
+
args: unknown,
|
|
50
|
+
caller: Caller,
|
|
51
|
+
row = false,
|
|
52
|
+
): Promise<LivePlan> {
|
|
53
|
+
const app = started()
|
|
54
|
+
const { models } = app.resolved
|
|
55
|
+
const info = modelOf(models, model)
|
|
56
|
+
const access = accessFor(models, caller, app.logger)
|
|
57
|
+
const scope = new QueryScope(models, caller, access)
|
|
58
|
+
const { where: unique, ...shape } = isObject(args) ? args : {}
|
|
59
|
+
return app.work.run(async () =>
|
|
60
|
+
planned(scope, () => {
|
|
61
|
+
const { read } = row
|
|
62
|
+
? plan(models, info, shape, '', 'many', rowKeys, scope)
|
|
63
|
+
: plan(models, info, args, '', 'many', liveKeys, scope)
|
|
64
|
+
const rights = scope.readable(model)
|
|
65
|
+
const where = row
|
|
66
|
+
? uniqueWhere(models, info, unique, 'where', scope)
|
|
67
|
+
: read.where
|
|
68
|
+
const { include, count, fields } = read
|
|
69
|
+
return {
|
|
70
|
+
...(include && { include }),
|
|
71
|
+
...(count && { count }),
|
|
72
|
+
...(fields && { fields }),
|
|
73
|
+
where: and(where, rights),
|
|
74
|
+
filter: where,
|
|
75
|
+
rights,
|
|
76
|
+
orderBy: read.orderBy ?? [{ field: 'id', direction: 'asc' }],
|
|
77
|
+
}
|
|
78
|
+
}),
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** The stored rows `read` finds, as Master, plugin fields undecoded. */
|
|
83
|
+
export async function storedRows(
|
|
84
|
+
model: string,
|
|
85
|
+
read: Nested,
|
|
86
|
+
): Promise<readonly Row[]> {
|
|
87
|
+
const app = started()
|
|
88
|
+
return app.work.run(async () => app.adapter.find({ ...read, model }))
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** The running application's schema, its plugins' models included. */
|
|
92
|
+
export function liveSchema(): Schema {
|
|
93
|
+
return started().resolved.schema
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Whether `filter` reads `model`'s row alone, so `matches` can test it. */
|
|
97
|
+
export function inMemory(model: string, filter: Filter | undefined): boolean {
|
|
98
|
+
const fields = modelOf(started().resolved.models, model).fields
|
|
99
|
+
return Object.entries(filter ?? {}).every(([key, value]) => {
|
|
100
|
+
if (value === undefined) return true
|
|
101
|
+
if (isFilters(value)) return value.every((part) => inMemory(model, part))
|
|
102
|
+
// A search ranks as each database does (D-148).
|
|
103
|
+
if (value.search !== undefined || value.removedBy !== undefined) {
|
|
104
|
+
return false
|
|
105
|
+
}
|
|
106
|
+
const field = fields.get(key)
|
|
107
|
+
return field === undefined || field.kind === 'scalar'
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const readers = new WeakMap<Running, Reader>()
|
|
112
|
+
|
|
113
|
+
function readerOf(app: Running): Reader {
|
|
114
|
+
const known = readers.get(app)
|
|
115
|
+
if (known !== undefined) return known
|
|
116
|
+
const fields = new Map(
|
|
117
|
+
app.resolved.schema.models.map((model) => [
|
|
118
|
+
model.name,
|
|
119
|
+
new Map(model.fields.map((field) => [field.name, field])),
|
|
120
|
+
]),
|
|
121
|
+
)
|
|
122
|
+
const reader = new Reader({ tables: new Map(), joins: new Map() }, fields)
|
|
123
|
+
readers.set(app, reader)
|
|
124
|
+
return reader
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Whether the stored `row` of `model` passes `filter`, which `inMemory` takes. */
|
|
128
|
+
export function matches(
|
|
129
|
+
model: string,
|
|
130
|
+
row: Row,
|
|
131
|
+
filter: Filter | undefined,
|
|
132
|
+
): boolean {
|
|
133
|
+
return readerOf(started()).matches(model, row, filter) === true
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Whether rows alone answer `read`: one level, unpaged, read in memory. */
|
|
137
|
+
const servable = (read: Read): boolean =>
|
|
138
|
+
read.include === undefined &&
|
|
139
|
+
read.count === undefined &&
|
|
140
|
+
read.distinct === undefined &&
|
|
141
|
+
read.cursor === undefined &&
|
|
142
|
+
read.skip === undefined &&
|
|
143
|
+
read.take === undefined &&
|
|
144
|
+
(read.orderBy ?? []).every(
|
|
145
|
+
(order) => (order.through ?? order.count ?? order.relevance) === undefined,
|
|
146
|
+
) &&
|
|
147
|
+
inMemory(read.model, read.where)
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The stored `rows` that pass `read`, in its order; the find that asked for
|
|
151
|
+
* them keeps the fields its shape selects.
|
|
152
|
+
*/
|
|
153
|
+
function served(read: Read, rows: Iterable<Row>): Row[] {
|
|
154
|
+
const { model, orderBy = [] } = read
|
|
155
|
+
const kept = [...rows].filter((row) => matches(model, row, read.where))
|
|
156
|
+
const keys = new Map(kept.map((row) => [row, sortKeys(model, row, orderBy)]))
|
|
157
|
+
const key = (row: Row): unknown[] => keys.get(row) ?? []
|
|
158
|
+
kept.sort((a, b) => compareKeys(key(a), key(b), orderBy))
|
|
159
|
+
return kept
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* `findMany(args)` on `model` as `caller`, its rows taken from the stored
|
|
164
|
+
* `rows` when they alone answer it, else from the database. `rows` holds
|
|
165
|
+
* every row its `where` finds.
|
|
166
|
+
*/
|
|
167
|
+
export async function servedRows(
|
|
168
|
+
model: string,
|
|
169
|
+
args: unknown,
|
|
170
|
+
caller: Caller,
|
|
171
|
+
rows: ReadonlyMap<string, Row>,
|
|
172
|
+
): Promise<readonly Row[]> {
|
|
173
|
+
const { models } = started().resolved
|
|
174
|
+
const found = await rootFind(
|
|
175
|
+
model,
|
|
176
|
+
args,
|
|
177
|
+
{ as: caller },
|
|
178
|
+
async (store, read) =>
|
|
179
|
+
servable(read)
|
|
180
|
+
? decoded(models, read, served(read, rows.values()))
|
|
181
|
+
: store.find(read),
|
|
182
|
+
)
|
|
183
|
+
return Array.isArray(found) ? found.filter(isRow) : []
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** The sort keys of the stored `row`, for an order on its own fields. */
|
|
187
|
+
export function sortKeys(
|
|
188
|
+
model: string,
|
|
189
|
+
row: Row,
|
|
190
|
+
orderBy: readonly Order[],
|
|
191
|
+
): unknown[] {
|
|
192
|
+
const reader = readerOf(started())
|
|
193
|
+
return orderBy.map((order) => {
|
|
194
|
+
if (order.through ?? order.count ?? order.relevance) {
|
|
195
|
+
throw new Error(`The order by ${order.field} reads another row.`)
|
|
196
|
+
}
|
|
197
|
+
return sortable(row[order.field] ?? null, reader.field(model, order.field))
|
|
198
|
+
})
|
|
199
|
+
}
|