@kollors/deep-json-server 1.0.0-alpha.2 → 1.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -19
- package/README.ru.md +103 -19
- package/dist/index.d.ts +2 -1
- package/dist/index.js.map +1 -1
- package/dist/src/cli.d.ts +2 -2
- package/dist/src/cli.js +22 -15
- package/dist/src/cli.js.map +1 -1
- package/dist/src/config.d.ts +12 -1
- package/dist/src/config.js +40 -5
- package/dist/src/config.js.map +1 -1
- package/dist/src/constants.d.ts +1 -1
- package/dist/src/constants.js +1 -1
- package/dist/src/database.d.ts +0 -1
- package/dist/src/database.js +12 -10
- package/dist/src/database.js.map +1 -1
- package/dist/src/engine.d.ts +16 -26
- package/dist/src/engine.js +36 -149
- package/dist/src/engine.js.map +1 -1
- package/dist/src/errors.d.ts +1 -1
- package/dist/src/files/contract.d.ts +0 -30
- package/dist/src/files/contract.js +6 -47
- package/dist/src/files/contract.js.map +1 -1
- package/dist/src/files/disk-store.d.ts +2 -1
- package/dist/src/files/disk-store.js +24 -14
- package/dist/src/files/disk-store.js.map +1 -1
- package/dist/src/files/http.d.ts +31 -0
- package/dist/src/files/http.js +44 -0
- package/dist/src/files/http.js.map +1 -0
- package/dist/src/files/index.d.ts +1 -1
- package/dist/src/files/index.js +1 -1
- package/dist/src/files/index.js.map +1 -1
- package/dist/src/files/memory-store.js +8 -7
- package/dist/src/files/memory-store.js.map +1 -1
- package/dist/src/files/openapi.js +2 -4
- package/dist/src/files/openapi.js.map +1 -1
- package/dist/src/files/routes.js +3 -2
- package/dist/src/files/routes.js.map +1 -1
- package/dist/src/graphql/entry.d.ts +3 -0
- package/dist/src/graphql/entry.js +3 -0
- package/dist/src/graphql/entry.js.map +1 -0
- package/dist/src/graphql/preflight.d.ts +3 -3
- package/dist/src/graphql/preflight.js +4 -2
- package/dist/src/graphql/preflight.js.map +1 -1
- package/dist/src/graphql/public.d.ts +3 -0
- package/dist/src/graphql/public.js +11 -0
- package/dist/src/graphql/public.js.map +1 -0
- package/dist/src/graphql/resolvers.d.ts +8 -0
- package/dist/src/graphql/resolvers.js +38 -0
- package/dist/src/graphql/resolvers.js.map +1 -0
- package/dist/src/graphql/routes.js +3 -4
- package/dist/src/graphql/routes.js.map +1 -1
- package/dist/src/graphql/write.d.ts +1 -0
- package/dist/src/graphql/write.js +7 -0
- package/dist/src/graphql/write.js.map +1 -0
- package/dist/src/graphql.d.ts +1 -2
- package/dist/src/graphql.js +18 -27
- package/dist/src/graphql.js.map +1 -1
- package/dist/src/http/errors.d.ts +6 -0
- package/dist/src/http/errors.js +3 -0
- package/dist/src/http/errors.js.map +1 -0
- package/dist/src/model.d.ts +6 -3
- package/dist/src/model.js +51 -14
- package/dist/src/model.js.map +1 -1
- package/dist/src/mutations/write.d.ts +25 -0
- package/dist/src/mutations/write.js +270 -0
- package/dist/src/mutations/write.js.map +1 -0
- package/dist/src/openapi/document.js +58 -12
- package/dist/src/openapi/document.js.map +1 -1
- package/dist/src/openapi/entry.d.ts +3 -0
- package/dist/src/openapi/entry.js +2 -0
- package/dist/src/openapi/entry.js.map +1 -0
- package/dist/src/openapi/helpers.d.ts +17 -0
- package/dist/src/openapi/helpers.js +4 -0
- package/dist/src/openapi/helpers.js.map +1 -0
- package/dist/src/openapi/index.js +6 -4
- package/dist/src/openapi/index.js.map +1 -1
- package/dist/src/openapi/public.d.ts +17 -0
- package/dist/src/openapi/public.js +18 -0
- package/dist/src/openapi/public.js.map +1 -0
- package/dist/src/pagination.d.ts +7 -0
- package/dist/src/pagination.js +12 -0
- package/dist/src/pagination.js.map +1 -0
- package/dist/src/paths.d.ts +6 -0
- package/dist/src/paths.js +47 -0
- package/dist/src/paths.js.map +1 -0
- package/dist/src/query/filter.d.ts +1 -2
- package/dist/src/query/filter.js +2 -0
- package/dist/src/query/filter.js.map +1 -1
- package/dist/src/query/options.js +4 -2
- package/dist/src/query/options.js.map +1 -1
- package/dist/src/records.d.ts +25 -0
- package/dist/src/records.js +50 -0
- package/dist/src/records.js.map +1 -0
- package/dist/src/relation-metadata.d.ts +0 -1
- package/dist/src/relation-metadata.js +0 -1
- package/dist/src/relation-metadata.js.map +1 -1
- package/dist/src/rest/options.d.ts +3 -3
- package/dist/src/rest/options.js +22 -52
- package/dist/src/rest/options.js.map +1 -1
- package/dist/src/rest/projection.d.ts +3 -3
- package/dist/src/rest/projection.js +11 -10
- package/dist/src/rest/projection.js.map +1 -1
- package/dist/src/rest/routes.js +6 -6
- package/dist/src/rest/routes.js.map +1 -1
- package/dist/src/schema.d.ts +6 -15
- package/dist/src/schema.js +7 -17
- package/dist/src/schema.js.map +1 -1
- package/dist/src/server/public.d.ts +3 -0
- package/dist/src/server/public.js +2 -0
- package/dist/src/server/public.js.map +1 -0
- package/dist/src/server.d.ts +3 -2
- package/dist/src/server.js +43 -36
- package/dist/src/server.js.map +1 -1
- package/dist/src/utils.d.ts +0 -7
- package/dist/src/utils.js +0 -4
- package/dist/src/utils.js.map +1 -1
- package/package.json +13 -1
package/dist/src/config.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { dirname, resolve } from 'node:path';
|
|
2
2
|
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { normalizePagination } from './pagination.js';
|
|
3
4
|
import { assertKnownKeys, isObject } from './utils.js';
|
|
4
5
|
const CONFIG_KEYS = new Set(['database', 'files', 'openapi', 'graphql', 'server']);
|
|
5
6
|
const DATABASE_KEYS = new Set(['data', 'path', 'schema']);
|
|
@@ -122,8 +123,7 @@ const normalizeConfig = (config, directoryPath = '.') => {
|
|
|
122
123
|
const maxFileSize = getPositiveInteger(server.maxFileSize, 'config.server.maxFileSize');
|
|
123
124
|
const maxPageSize = getPositiveInteger(server.maxPageSize, 'config.server.maxPageSize');
|
|
124
125
|
const pageSize = getPositiveInteger(server.pageSize, 'config.server.pageSize');
|
|
125
|
-
|
|
126
|
-
throw new Error('pageSize exceeds maxPageSize');
|
|
126
|
+
normalizePagination({ pageSize, maxPageSize });
|
|
127
127
|
const port = server.port;
|
|
128
128
|
if (port != null && (typeof port !== 'number' || !Number.isInteger(port) || port < 0 || port > 65_535)) {
|
|
129
129
|
throw new Error('Ключ config.server.port должен быть целым числом от 0 до 65535');
|
|
@@ -137,7 +137,12 @@ const normalizeConfig = (config, directoryPath = '.') => {
|
|
|
137
137
|
return {
|
|
138
138
|
database,
|
|
139
139
|
files,
|
|
140
|
-
openapi: {
|
|
140
|
+
openapi: {
|
|
141
|
+
enabled: openapi.enabled,
|
|
142
|
+
endpoint: openapiEndpoint,
|
|
143
|
+
path: resolveConfigPath(openapiPath, directoryPath),
|
|
144
|
+
...(info && { info: copyInput(info) }),
|
|
145
|
+
},
|
|
141
146
|
graphql: { path: resolveConfigPath(getString(graphql.path, 'config.graphql.path'), directoryPath), enabled: graphql.enabled, endpoint },
|
|
142
147
|
server: {
|
|
143
148
|
cors: cors,
|
|
@@ -153,7 +158,7 @@ const normalizeConfig = (config, directoryPath = '.') => {
|
|
|
153
158
|
/** Validates configuration and resolves relative paths. */
|
|
154
159
|
export const normalizeServerConfig = (config, directoryPath) => normalizeConfig(config, directoryPath);
|
|
155
160
|
/** Loads an ES module config and resolves paths from its directory. */
|
|
156
|
-
export async function
|
|
161
|
+
export async function readConfigModule(configPath) {
|
|
157
162
|
const resolvedConfigPath = resolve(getString(configPath, 'config', true));
|
|
158
163
|
let config;
|
|
159
164
|
try {
|
|
@@ -169,6 +174,36 @@ export async function readServerConfig(configPath) {
|
|
|
169
174
|
if (!isObject(config)) {
|
|
170
175
|
throw new Error('Конфигурация сервера должна экспортировать JSON-объект через export default');
|
|
171
176
|
}
|
|
172
|
-
return
|
|
177
|
+
return { config, directory: dirname(resolvedConfigPath), path: resolvedConfigPath };
|
|
178
|
+
}
|
|
179
|
+
const sourcePaths = new WeakMap();
|
|
180
|
+
export const configSourcePath = (config) => sourcePaths.get(config);
|
|
181
|
+
export function configure(config, directory, sourcePath) {
|
|
182
|
+
const normalized = normalizeConfig(config, directory);
|
|
183
|
+
if (sourcePath)
|
|
184
|
+
sourcePaths.set(normalized, sourcePath);
|
|
185
|
+
return normalized;
|
|
186
|
+
}
|
|
187
|
+
export function configureGeneration(source, formats, directory, sourcePath, overrides) {
|
|
188
|
+
assertKnownKeys(source, CONFIG_KEYS, 'config');
|
|
189
|
+
const database = getObject(source.database, 'config.database', true);
|
|
190
|
+
if (database.schema === undefined)
|
|
191
|
+
throw new Error('Generation requires an explicit model schema');
|
|
192
|
+
const openapi = formats.includes('openapi');
|
|
193
|
+
const server = openapi ? (getObject(source.server, 'config.server') ?? {}) : {};
|
|
194
|
+
return configure({
|
|
195
|
+
database: { data: {}, schema: database.schema },
|
|
196
|
+
openapi: openapi ? source.openapi : undefined,
|
|
197
|
+
graphql: formats.includes('graphql') ? source.graphql : undefined,
|
|
198
|
+
files: openapi && (overrides.files || source.files != null) ? { data: [] } : undefined,
|
|
199
|
+
server: openapi
|
|
200
|
+
? {
|
|
201
|
+
host: overrides.host ?? server.host,
|
|
202
|
+
port: overrides.port ?? server.port,
|
|
203
|
+
pageSize: server.pageSize,
|
|
204
|
+
maxPageSize: server.maxPageSize,
|
|
205
|
+
}
|
|
206
|
+
: {},
|
|
207
|
+
}, directory, sourcePath);
|
|
173
208
|
}
|
|
174
209
|
//# sourceMappingURL=config.js.map
|
package/dist/src/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/src/constants.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ export declare const DEFAULT_MAX_FILE_SIZE: number;
|
|
|
3
3
|
export declare const DEFAULT_MAX_PAGE_SIZE = 100;
|
|
4
4
|
export declare const DEFAULT_PAGE_SIZE = 10;
|
|
5
5
|
export declare const DEFAULT_PORT = 4001;
|
|
6
|
-
export declare const VERSION = "1.0.0-alpha.
|
|
6
|
+
export declare const VERSION = "1.0.0-alpha.4";
|
package/dist/src/constants.js
CHANGED
|
@@ -3,5 +3,5 @@ export const DEFAULT_MAX_FILE_SIZE = 100 * 1024 * 1024;
|
|
|
3
3
|
export const DEFAULT_MAX_PAGE_SIZE = 100;
|
|
4
4
|
export const DEFAULT_PAGE_SIZE = 10;
|
|
5
5
|
export const DEFAULT_PORT = 4001;
|
|
6
|
-
export const VERSION = '1.0.0-alpha.
|
|
6
|
+
export const VERSION = '1.0.0-alpha.4';
|
|
7
7
|
//# sourceMappingURL=constants.js.map
|
package/dist/src/database.d.ts
CHANGED
|
@@ -16,6 +16,5 @@ export declare const readJsonObjectFile: (path: string, label: string) => Promis
|
|
|
16
16
|
export declare const readDatabaseFile: (databasePath: string, keys?: Map<string, string>) => Promise<DatabaseData>;
|
|
17
17
|
/** Creates a disk- or memory-backed database with serialized updates. */
|
|
18
18
|
export declare const createDatabaseStore: (config: DatabaseConfig, keys?: Map<string, string>) => Promise<DatabaseStore>;
|
|
19
|
-
export declare const getCollection: (database: DatabaseContainer, resource: string) => DatabaseRecord[];
|
|
20
19
|
export declare const findItemIndex: (collection: DatabaseRecord[], id: unknown) => number;
|
|
21
20
|
export declare const createId: (collection: DatabaseRecord[]) => string;
|
package/dist/src/database.js
CHANGED
|
@@ -2,7 +2,8 @@ import { readFile } from 'node:fs/promises';
|
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import { Low } from 'lowdb';
|
|
4
4
|
import { JSONFile } from 'lowdb/node';
|
|
5
|
-
import {
|
|
5
|
+
import { domainError } from './errors.js';
|
|
6
|
+
import { createSerialQueue, createUniqueId, isObject, isSafeKey, isSystemError, resolveDatabasePath } from './utils.js';
|
|
6
7
|
const RESOURCE_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
7
8
|
export const validateJsonValue = (value, path, ancestors = new WeakSet()) => {
|
|
8
9
|
if (value === null || typeof value === 'string' || typeof value === 'boolean') {
|
|
@@ -92,6 +93,14 @@ export const readJsonObjectFile = async (path, label) => {
|
|
|
92
93
|
return value;
|
|
93
94
|
};
|
|
94
95
|
export const readDatabaseFile = async (databasePath, keys) => validateDatabase(await readJsonObjectFile(databasePath, 'Файл базы данных'), keys);
|
|
96
|
+
const validateDraft = (data, keys) => {
|
|
97
|
+
try {
|
|
98
|
+
validateDatabase(data, keys);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
throw domainError('INVALID_INPUT', error.message);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
95
104
|
const createDiskDatabaseStore = async (databasePath, keys) => {
|
|
96
105
|
const resolvedDatabasePath = resolveDatabasePath(databasePath);
|
|
97
106
|
const initialData = await readDatabaseFile(resolvedDatabasePath, keys);
|
|
@@ -108,7 +117,7 @@ const createDiskDatabaseStore = async (databasePath, keys) => {
|
|
|
108
117
|
await counterStore.read();
|
|
109
118
|
const draft = { data: structuredClone(database.data), counters: structuredClone(counterStore.data) };
|
|
110
119
|
const result = operation(draft);
|
|
111
|
-
|
|
120
|
+
validateDraft(draft.data, keys);
|
|
112
121
|
// Reserve generated numbers first: failed data writes may leave gaps, never reused IDs.
|
|
113
122
|
if (JSON.stringify(draft.counters) !== JSON.stringify(counterStore.data)) {
|
|
114
123
|
counterStore.data = draft.counters;
|
|
@@ -128,7 +137,7 @@ const createMemoryDatabaseStore = (sourceData, keys) => {
|
|
|
128
137
|
const update = (operation) => schedule(() => {
|
|
129
138
|
const draft = structuredClone(database);
|
|
130
139
|
const result = operation(draft);
|
|
131
|
-
|
|
140
|
+
validateDraft(draft.data, keys);
|
|
132
141
|
database.data = draft.data;
|
|
133
142
|
database.counters = draft.counters;
|
|
134
143
|
return result;
|
|
@@ -137,13 +146,6 @@ const createMemoryDatabaseStore = (sourceData, keys) => {
|
|
|
137
146
|
};
|
|
138
147
|
/** Creates a disk- or memory-backed database with serialized updates. */
|
|
139
148
|
export const createDatabaseStore = async (config, keys) => config.data != null ? createMemoryDatabaseStore(config.data, keys) : createDiskDatabaseStore(config.path, keys);
|
|
140
|
-
export const getCollection = (database, resource) => {
|
|
141
|
-
const collection = isSafeKey(resource) ? database.data[resource] : undefined;
|
|
142
|
-
if (!Array.isArray(collection)) {
|
|
143
|
-
throw createHttpError(404, 'Ресурс не найден');
|
|
144
|
-
}
|
|
145
|
-
return collection;
|
|
146
|
-
};
|
|
147
149
|
export const findItemIndex = (collection, id) => collection.findIndex((item) => String(item.id) === String(id));
|
|
148
150
|
export const createId = (collection) => createUniqueId((id) => findItemIndex(collection, id) !== -1);
|
|
149
151
|
//# sourceMappingURL=database.js.map
|
package/dist/src/database.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/database.ts"],"names":[],"mappings":"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"}
|
package/dist/src/engine.d.ts
CHANGED
|
@@ -1,47 +1,37 @@
|
|
|
1
1
|
import type { DatabaseStore } from './database.js';
|
|
2
2
|
import { type Entity, type Model, type Node } from './model.js';
|
|
3
|
+
import { type Predicate } from './query/filter.js';
|
|
3
4
|
import { type ListOptions } from './query/options.js';
|
|
4
|
-
import type
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
model: Model;
|
|
16
|
-
indexes: Map<string, Map<string, JsonObject[]>>;
|
|
5
|
+
import { type Context, type Ref } from './records.js';
|
|
6
|
+
import type { DatabaseData } from './types.js';
|
|
7
|
+
export { type Context, isRef, makeContext, type Ref, related, resolveField, rootRef } from './records.js';
|
|
8
|
+
export interface PreparedList {
|
|
9
|
+
page: number;
|
|
10
|
+
pageSize: number;
|
|
11
|
+
predicate?: Predicate;
|
|
12
|
+
rules: Array<{
|
|
13
|
+
direction: 'ASC' | 'DESC';
|
|
14
|
+
keys: string[];
|
|
15
|
+
}>;
|
|
17
16
|
}
|
|
18
17
|
export interface Page {
|
|
19
18
|
data: Ref[];
|
|
20
19
|
total: number;
|
|
21
20
|
}
|
|
22
|
-
export declare const makeContext: (data: DatabaseData, model: Model) => Context;
|
|
23
|
-
export declare const rootRef: (context: Context, entity: Entity, value: JsonObject) => Ref;
|
|
24
|
-
export declare function related(ref: Ref, node: Node): Ref[];
|
|
25
|
-
export declare function resolveField(ref: Ref, node: Node): unknown;
|
|
26
|
-
export declare const isRef: (value: unknown) => value is Ref;
|
|
27
21
|
export declare class Engine {
|
|
28
22
|
readonly store: DatabaseStore;
|
|
29
23
|
model: Model;
|
|
30
24
|
readonly pageSize: number;
|
|
31
25
|
readonly maxPageSize: number;
|
|
26
|
+
private inferredModels;
|
|
32
27
|
constructor(store: DatabaseStore, model: Model, pageSize?: number, maxPageSize?: number);
|
|
28
|
+
private modelFor;
|
|
33
29
|
context(): Promise<Context>;
|
|
34
|
-
entity(collection: string): Entity;
|
|
35
30
|
records(context: Context, entity: Entity): Ref[];
|
|
36
31
|
find(context: Context, entity: Entity, key: unknown): Ref | undefined;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
pageSize: number;
|
|
40
|
-
};
|
|
41
|
-
list(records: Ref[], node: Node, options?: ListOptions): Page;
|
|
32
|
+
prepareOptions(node: Node, options?: ListOptions): PreparedList;
|
|
33
|
+
list(records: Ref[], node: Node, options?: ListOptions, prepared?: PreparedList): Page;
|
|
42
34
|
validateData(data: DatabaseData): void;
|
|
43
|
-
private defaults;
|
|
44
|
-
private preserve;
|
|
45
35
|
mutate<T = Ref>(entity: Entity, mode: 'create' | 'replace' | 'update' | 'delete', key?: unknown, body?: unknown, prepare?: (ref: Ref) => T): Promise<T>;
|
|
46
36
|
private cascade;
|
|
47
37
|
}
|
package/dist/src/engine.js
CHANGED
|
@@ -1,56 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createId, validateDatabase } from './database.js';
|
|
1
|
+
import { DEFAULT_MAX_PAGE_SIZE, DEFAULT_PAGE_SIZE } from './constants.js';
|
|
3
2
|
import { domainError } from './errors.js';
|
|
4
|
-
import {
|
|
3
|
+
import { inferModel, pathParts, readPath, validateRecord } from './model.js';
|
|
4
|
+
import { MutationWriter } from './mutations/write.js';
|
|
5
5
|
import { compileWhere } from './query/filter.js';
|
|
6
6
|
import { badQuery, childrenOf, nodeAt } from './query/options.js';
|
|
7
|
+
import { isRef, keyOf, makeContext, related, resolveField, rootRef, sourceValues } from './records.js';
|
|
7
8
|
import { isObject } from './utils.js';
|
|
8
|
-
export
|
|
9
|
-
export const rootRef = (context, entity, value) => ({ context, entity, node: entity.root, value, root: value, bindings: {} });
|
|
10
|
-
const keyOf = (value) => `${typeof value}:${String(value)}`;
|
|
11
|
-
function sourceValues(ref, node) {
|
|
12
|
-
const path = node.source;
|
|
13
|
-
const binding = Object.keys(ref.bindings)
|
|
14
|
-
.filter((prefix) => path === prefix || path.startsWith(`${prefix}.`))
|
|
15
|
-
.sort((a, b) => b.length - a.length)[0];
|
|
16
|
-
return binding ? readPath(ref.bindings[binding], path === binding ? [] : path.slice(binding.length + 1)) : readPath(ref.root, path);
|
|
17
|
-
}
|
|
18
|
-
export function related(ref, node) {
|
|
19
|
-
const entity = node.relation;
|
|
20
|
-
const indexKey = `${entity.name}:${node.target}`;
|
|
21
|
-
let index = ref.context.indexes.get(indexKey);
|
|
22
|
-
if (!index) {
|
|
23
|
-
index = new Map();
|
|
24
|
-
for (const record of ref.context.data[entity.collection] ?? [])
|
|
25
|
-
for (const value of readPath(record, node.target)) {
|
|
26
|
-
const key = keyOf(value);
|
|
27
|
-
const bucket = index.get(key) ?? [];
|
|
28
|
-
bucket.push(record);
|
|
29
|
-
index.set(key, bucket);
|
|
30
|
-
}
|
|
31
|
-
ref.context.indexes.set(indexKey, index);
|
|
32
|
-
}
|
|
33
|
-
const found = new Set();
|
|
34
|
-
for (const value of sourceValues(ref, node))
|
|
35
|
-
for (const record of index.get(keyOf(value)) ?? [])
|
|
36
|
-
found.add(record);
|
|
37
|
-
return [...found].map((record) => rootRef(ref.context, entity, record));
|
|
38
|
-
}
|
|
39
|
-
export function resolveField(ref, node) {
|
|
40
|
-
if (node.relation) {
|
|
41
|
-
const records = related(ref, node);
|
|
42
|
-
return node.many ? records : (records[0] ?? null);
|
|
43
|
-
}
|
|
44
|
-
const key = childName(node);
|
|
45
|
-
const value = Object.hasOwn(ref.value, key) ? ref.value[key] : undefined;
|
|
46
|
-
if (node.base !== 'object' || value == null)
|
|
47
|
-
return value;
|
|
48
|
-
const wrap = (object) => ({ ...ref, node, value: object, bindings: { ...ref.bindings, [node.path]: object } });
|
|
49
|
-
if (Array.isArray(value))
|
|
50
|
-
return value.every(isObject) ? value.map(wrap) : value;
|
|
51
|
-
return isObject(value) ? wrap(value) : value;
|
|
52
|
-
}
|
|
53
|
-
export const isRef = (value) => isObject(value) && 'context' in value && 'bindings' in value;
|
|
9
|
+
export { isRef, makeContext, related, resolveField, rootRef } from './records.js';
|
|
54
10
|
function filterView(ref) {
|
|
55
11
|
const value = {};
|
|
56
12
|
for (const [name, node] of Object.entries(childrenOf(ref.node)))
|
|
@@ -70,33 +26,39 @@ export class Engine {
|
|
|
70
26
|
model;
|
|
71
27
|
pageSize;
|
|
72
28
|
maxPageSize;
|
|
73
|
-
|
|
29
|
+
inferredModels = new WeakMap();
|
|
30
|
+
constructor(store, model, pageSize = DEFAULT_PAGE_SIZE, maxPageSize = DEFAULT_MAX_PAGE_SIZE) {
|
|
74
31
|
this.store = store;
|
|
75
32
|
this.model = model;
|
|
76
33
|
this.pageSize = pageSize;
|
|
77
34
|
this.maxPageSize = maxPageSize;
|
|
35
|
+
this.inferredModels.set(store.database.data, model);
|
|
36
|
+
}
|
|
37
|
+
modelFor(data) {
|
|
38
|
+
if (this.model.explicit)
|
|
39
|
+
return this.model;
|
|
40
|
+
let model = this.inferredModels.get(data);
|
|
41
|
+
if (!model) {
|
|
42
|
+
model = inferModel(data);
|
|
43
|
+
this.inferredModels.set(data, model);
|
|
44
|
+
}
|
|
45
|
+
return model;
|
|
78
46
|
}
|
|
79
47
|
async context() {
|
|
80
48
|
const data = await this.store.read();
|
|
81
49
|
if (!this.model.explicit)
|
|
82
|
-
this.model =
|
|
50
|
+
this.model = this.modelFor(data);
|
|
83
51
|
return makeContext(data, this.model);
|
|
84
52
|
}
|
|
85
|
-
entity(collection) {
|
|
86
|
-
const entity = this.model.byCollection.get(collection);
|
|
87
|
-
if (!entity)
|
|
88
|
-
throw domainError('NOT_FOUND', 'Resource not found');
|
|
89
|
-
return entity;
|
|
90
|
-
}
|
|
91
53
|
records(context, entity) {
|
|
92
54
|
return (context.data[entity.collection] ?? []).map((value) => rootRef(context, entity, value));
|
|
93
55
|
}
|
|
94
56
|
find(context, entity, key) {
|
|
95
|
-
|
|
57
|
+
const value = (context.data[entity.collection] ?? []).find((record) => String(record[entity.primary]) === String(key));
|
|
58
|
+
return value ? rootRef(context, entity, value) : undefined;
|
|
96
59
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
compileWhere(node, options.where);
|
|
60
|
+
prepareOptions(node, options = {}) {
|
|
61
|
+
const predicate = options.where !== undefined ? compileWhere(node, options.where) : undefined;
|
|
100
62
|
if (options.order !== undefined) {
|
|
101
63
|
if (!Array.isArray(options.order))
|
|
102
64
|
badQuery('order must be an array');
|
|
@@ -119,13 +81,11 @@ export class Engine {
|
|
|
119
81
|
pageSize > this.maxPageSize ||
|
|
120
82
|
!Number.isSafeInteger((page - 1) * pageSize))
|
|
121
83
|
badQuery(`Invalid pager; pageSize must be 1..${this.maxPageSize}`);
|
|
122
|
-
return { page, pageSize };
|
|
84
|
+
return { page, pageSize, predicate, rules: (options.order ?? []).map((rule) => ({ direction: rule.direction, keys: pathParts(rule.field) })) };
|
|
123
85
|
}
|
|
124
|
-
list(records, node, options = {}) {
|
|
125
|
-
const { page, pageSize } =
|
|
126
|
-
const predicate = options.where ? compileWhere(node, options.where) : undefined;
|
|
86
|
+
list(records, node, options = {}, prepared = this.prepareOptions(node, options)) {
|
|
87
|
+
const { page, pageSize, predicate, rules } = prepared;
|
|
127
88
|
const data = predicate ? records.filter((ref) => predicate(filterView(ref))) : [...records];
|
|
128
|
-
const rules = (options.order ?? []).map((rule) => ({ ...rule, keys: pathParts(rule.field) }));
|
|
129
89
|
if (rules.length)
|
|
130
90
|
data.sort((a, b) => {
|
|
131
91
|
for (const rule of rules) {
|
|
@@ -183,55 +143,20 @@ export class Engine {
|
|
|
183
143
|
visit(rootRef(context, entity, record));
|
|
184
144
|
}
|
|
185
145
|
}
|
|
186
|
-
defaults(node, record) {
|
|
187
|
-
for (const [key, child] of Object.entries(node.children)) {
|
|
188
|
-
if (child.relation)
|
|
189
|
-
continue;
|
|
190
|
-
if (!Object.hasOwn(record, key) && child.default !== undefined)
|
|
191
|
-
record[key] = structuredClone(child.default);
|
|
192
|
-
if (child.base === 'object' && record[key] != null) {
|
|
193
|
-
const values = child.many ? record[key] : [record[key]];
|
|
194
|
-
values.forEach((value) => {
|
|
195
|
-
this.defaults(child, value);
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
preserve(node, record, previous) {
|
|
201
|
-
for (const [key, child] of Object.entries(node.children)) {
|
|
202
|
-
if (child.relation)
|
|
203
|
-
continue;
|
|
204
|
-
if ((child.generated || child.readOnly) && previous && Object.hasOwn(previous, key))
|
|
205
|
-
record[key] = structuredClone(previous[key]);
|
|
206
|
-
else if (child.base === 'object' && !child.many) {
|
|
207
|
-
const old = previous?.[key];
|
|
208
|
-
if (isObject(record[key]))
|
|
209
|
-
this.preserve(child, record[key], isObject(old) ? old : undefined);
|
|
210
|
-
else if (record[key] === undefined && isObject(old)) {
|
|
211
|
-
const preserved = {};
|
|
212
|
-
this.preserve(child, preserved, old);
|
|
213
|
-
if (Object.keys(preserved).length)
|
|
214
|
-
record[key] = preserved;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
146
|
async mutate(entity, mode, key, body, prepare) {
|
|
220
147
|
if (mode !== 'delete') {
|
|
221
148
|
if (!isObject(body))
|
|
222
149
|
throw domainError('INVALID_INPUT', 'Request body must be an object');
|
|
223
|
-
if (this.model.explicit)
|
|
224
|
-
validateRecord(entity, body, mode);
|
|
225
|
-
else if (Object.hasOwn(body, 'id'))
|
|
150
|
+
if (!this.model.explicit && Object.hasOwn(body, 'id'))
|
|
226
151
|
throw domainError('INVALID_INPUT', 'id is generated and immutable');
|
|
227
152
|
}
|
|
228
153
|
const outcome = await this.store.update((database) => {
|
|
229
154
|
const finish = (data, record) => {
|
|
230
|
-
const model = this.
|
|
155
|
+
const model = this.modelFor(data);
|
|
231
156
|
const currentEntity = model.byCollection.get(entity.collection);
|
|
232
157
|
const ref = rootRef(makeContext(data, model), currentEntity, record);
|
|
233
158
|
const output = prepare ? prepare(ref) : ref;
|
|
234
|
-
return { model: this.model.explicit ?
|
|
159
|
+
return { model: data === database.data || this.model.explicit ? model : this.modelFor(database.data), output };
|
|
235
160
|
};
|
|
236
161
|
// Reserve the highest existing generated value before any deletion or replacement.
|
|
237
162
|
for (const owner of this.model.entities)
|
|
@@ -245,58 +170,20 @@ export class Engine {
|
|
|
245
170
|
throw domainError('CONFLICT', 'Invalid increment counter');
|
|
246
171
|
counters[name] = maximum;
|
|
247
172
|
}
|
|
248
|
-
const context = makeContext(database.data, this.model);
|
|
249
|
-
const current = mode === 'create' ? undefined : this.find(context, entity, key);
|
|
250
|
-
if (mode !== 'create' && !current)
|
|
251
|
-
throw domainError('NOT_FOUND', 'Record not found');
|
|
252
|
-
database.data[entity.collection] ??= [];
|
|
253
|
-
const collection = database.data[entity.collection];
|
|
254
173
|
if (mode === 'delete') {
|
|
174
|
+
const context = makeContext(database.data, this.model);
|
|
175
|
+
const current = this.find(context, entity, key);
|
|
176
|
+
if (!current)
|
|
177
|
+
throw domainError('NOT_FOUND', 'Record not found');
|
|
255
178
|
const snapshot = structuredClone(database.data);
|
|
256
179
|
this.cascade(context, current);
|
|
257
180
|
this.validateData(database.data);
|
|
258
181
|
return finish(snapshot, current.value);
|
|
259
182
|
}
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
this.preserve(entity.root, record, current?.value);
|
|
264
|
-
}
|
|
265
|
-
if (this.model.explicit) {
|
|
266
|
-
if (mode !== 'update')
|
|
267
|
-
this.defaults(entity.root, record);
|
|
268
|
-
if (mode === 'create')
|
|
269
|
-
for (const [name, field] of Object.entries(entity.root.children)) {
|
|
270
|
-
if (field.generated === 'uuid')
|
|
271
|
-
record[name] = randomUUID();
|
|
272
|
-
if (field.generated === 'increment') {
|
|
273
|
-
database.counters ??= {};
|
|
274
|
-
const counters = database.counters;
|
|
275
|
-
const counterKey = `${entity.collection}.${name}`;
|
|
276
|
-
const largest = counters[counterKey] ?? 0;
|
|
277
|
-
if (!Number.isSafeInteger(largest) || largest >= Number.MAX_SAFE_INTEGER)
|
|
278
|
-
throw domainError('CONFLICT', 'Increment key exhausted');
|
|
279
|
-
record[name] = largest + 1;
|
|
280
|
-
counters[counterKey] = largest + 1;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
else if (mode === 'create')
|
|
285
|
-
record.id = createId(collection);
|
|
286
|
-
const collision = collection.some((v) => v !== current?.value && String(v[entity.primary]) === String(record[entity.primary]));
|
|
287
|
-
if (collision)
|
|
288
|
-
throw domainError('CONFLICT', 'Primary key already exists');
|
|
289
|
-
if (mode === 'create')
|
|
290
|
-
collection.push(record);
|
|
291
|
-
else
|
|
292
|
-
collection[collection.indexOf(current.value)] = record;
|
|
183
|
+
const writer = new MutationWriter(database, this.model, mode === 'replace' ? 'replace' : 'update');
|
|
184
|
+
const record = writer.write(entity, mode, key, body);
|
|
185
|
+
writer.validateRelations();
|
|
293
186
|
this.validateData(database.data);
|
|
294
|
-
try {
|
|
295
|
-
validateDatabase(database.data, new Map(this.model.entities.map((e) => [e.collection, e.primary])));
|
|
296
|
-
}
|
|
297
|
-
catch (error) {
|
|
298
|
-
throw domainError('INVALID_INPUT', error.message);
|
|
299
|
-
}
|
|
300
187
|
return finish(database.data, record);
|
|
301
188
|
});
|
|
302
189
|
this.model = outcome.model;
|