@deterministic-code/datasources 0.1.6 → 0.1.11
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.
|
@@ -9,6 +9,7 @@ const empty = () => ({ result: null, rowsAffected: 0 });
|
|
|
9
9
|
const budget = 8000;
|
|
10
10
|
const maxRows = 250;
|
|
11
11
|
const assigned = (value) => value !== null && value !== "" && value !== 0 && value !== 0n;
|
|
12
|
+
const listed = (list, col, fallback) => list === undefined ? fallback : list.includes(col);
|
|
12
13
|
const columnsOf = (rows) => {
|
|
13
14
|
const seen = new Set();
|
|
14
15
|
const columns = [];
|
|
@@ -83,12 +84,12 @@ export class BatchCommandIBulkWriteStrategy {
|
|
|
83
84
|
};
|
|
84
85
|
mappedInsert = (item) => {
|
|
85
86
|
const record = this.reverse(item);
|
|
86
|
-
const statement = this.statements().insert(this.fields(record, (col) => !this.ids.includes(col) || assigned(record[col] ?? null)));
|
|
87
|
+
const statement = this.statements().insert(this.fields(record, (col) => listed(this.options.createProperties, col, !this.ids.includes(col) || assigned(record[col] ?? null))));
|
|
87
88
|
return { table: statement.table, fields: statement.fields };
|
|
88
89
|
};
|
|
89
90
|
mappedUpdate = (item) => {
|
|
90
91
|
const record = this.reverse(item);
|
|
91
|
-
const fields = this.fields(record, (col) => !this.ids.includes(col));
|
|
92
|
+
const fields = this.fields(record, (col) => listed(this.options.updateProperties, col, !this.ids.includes(col)));
|
|
92
93
|
if (fields.length === 0)
|
|
93
94
|
throw new DatasourceError("Update requires at least one non-Id field");
|
|
94
95
|
const statement = this.statements().update(fields, this.idsWhere(record), (name, value) => this.cell(name, value, true));
|
|
@@ -101,7 +102,7 @@ export class BatchCommandIBulkWriteStrategy {
|
|
|
101
102
|
};
|
|
102
103
|
updateCommand = (item, byWhere) => {
|
|
103
104
|
const record = this.reverse(item);
|
|
104
|
-
const fields = this.fields(record, (col) => !this.ids.includes(col));
|
|
105
|
+
const fields = this.fields(record, (col) => listed(this.options.updateProperties, col, !this.ids.includes(col)));
|
|
105
106
|
if (fields.length === 0)
|
|
106
107
|
throw new DatasourceError("Update requires at least one non-Id field");
|
|
107
108
|
const statement = this.statements().update(fields, byWhere ?? this.idsWhere(record), (name, value) => this.cell(name, value, byWhere === undefined));
|
|
@@ -127,8 +128,15 @@ export class BatchCommandIBulkWriteStrategy {
|
|
|
127
128
|
const row = objects.reverseConvert(item);
|
|
128
129
|
return this.options.rowConverter ? this.options.rowConverter.reverseConvert(row) : row;
|
|
129
130
|
};
|
|
131
|
+
writable = (key) => {
|
|
132
|
+
const columns = this.statements().readColumns;
|
|
133
|
+
const map = this.options.propertyMappings;
|
|
134
|
+
return (columns.length === 0 ||
|
|
135
|
+
columns.includes(key) ||
|
|
136
|
+
(map !== undefined && columns.some((name) => map.map(name) === key)));
|
|
137
|
+
};
|
|
130
138
|
fields = (record, include) => Object.entries(record)
|
|
131
|
-
.filter(([key, value]) => include(key) && value !== null && value !== undefined)
|
|
139
|
+
.filter(([key, value]) => include(key) && this.writable(key) && value !== null && value !== undefined)
|
|
132
140
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
133
141
|
.map(([name, value]) => ({ name, value: this.cell(name, value, true) }));
|
|
134
142
|
cell = (property, value, fieldsApplied) => fieldsApplied
|
package/dist/CRUDRepository.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ import type { IReadonlyEnrichmentStrategy } from "./IReadonlyEnrichmentStrategy.
|
|
|
12
12
|
import type { IReadonlyRepository } from "./IReadonlyRepository.js";
|
|
13
13
|
export declare class CRUDRepository<T = Cells> extends ReadonlyRepository<T> implements ICRUDRepository<T> {
|
|
14
14
|
readonly ids: readonly string[];
|
|
15
|
+
private readonly createProperties?;
|
|
16
|
+
private readonly updateProperties?;
|
|
15
17
|
private readonly crudStatements;
|
|
16
18
|
private readonly tree;
|
|
17
19
|
private readonly write;
|
package/dist/CRUDRepository.js
CHANGED
|
@@ -11,8 +11,14 @@ import { UnitOfWorkTransaction } from "./UnitOfWorkTransaction.js";
|
|
|
11
11
|
import { RepositoryTree } from "./RepositoryTree.js";
|
|
12
12
|
import { RepositoryTreeNode } from "./RepositoryTreeNode.js";
|
|
13
13
|
const assigned = (value) => value !== null && value !== "" && value !== 0 && value !== 0n;
|
|
14
|
-
const
|
|
15
|
-
|
|
14
|
+
const listed = (list, col, fallback) => list === undefined ? fallback : list.includes(col);
|
|
15
|
+
const writable = (key, columns, column) => columns.length === 0 || columns.includes(key) || columns.some((name) => column(name) === key);
|
|
16
|
+
const fieldsOf = (record, include, cell, enrichmentInto, columns, column) => Object.entries(record)
|
|
17
|
+
.filter(([key, value]) => include(key) &&
|
|
18
|
+
writable(key, columns, column) &&
|
|
19
|
+
!enrichmentInto(key) &&
|
|
20
|
+
value !== null &&
|
|
21
|
+
value !== undefined)
|
|
16
22
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
17
23
|
.map(([name, value]) => ({ name, value: cell(name, value, true) }));
|
|
18
24
|
const isCells = (id) => typeof id === "object" && id !== null;
|
|
@@ -29,6 +35,8 @@ const identified = (row, column) => {
|
|
|
29
35
|
const scalarOf = (value) => value === undefined || value === null || typeof value === "object" ? undefined : value;
|
|
30
36
|
export class CRUDRepository extends ReadonlyRepository {
|
|
31
37
|
ids;
|
|
38
|
+
createProperties;
|
|
39
|
+
updateProperties;
|
|
32
40
|
crudStatements;
|
|
33
41
|
tree;
|
|
34
42
|
write;
|
|
@@ -40,6 +48,8 @@ export class CRUDRepository extends ReadonlyRepository {
|
|
|
40
48
|
const opened = repositoryParts(typeOrConnection, options);
|
|
41
49
|
super(opened.built);
|
|
42
50
|
this.ids = opened.built.ids;
|
|
51
|
+
this.createProperties = options.createProperties;
|
|
52
|
+
this.updateProperties = options.updateProperties;
|
|
43
53
|
this.crudStatements = opened.statements;
|
|
44
54
|
this.tree = new RepositoryTree(new RepositoryTreeNode(this, ""));
|
|
45
55
|
this.write = options.write ?? new DefaultWriteEnrichmentStrategy();
|
|
@@ -101,7 +111,7 @@ export class CRUDRepository extends ReadonlyRepository {
|
|
|
101
111
|
readSingleById = async (id) => this.readSingle(this.byId(id));
|
|
102
112
|
insert = async (item) => {
|
|
103
113
|
const record = this.reverseConvert(item);
|
|
104
|
-
const fields = fieldsOf(record, (col) => !this.ids.includes(col) || assigned(record[col] ?? null), this.cell, this.enrichmentInto);
|
|
114
|
+
const fields = fieldsOf(record, (col) => listed(this.createProperties, col, !this.ids.includes(col) || assigned(record[col] ?? null)), this.cell, this.enrichmentInto, this.crudStatements.readColumns, this.column);
|
|
105
115
|
const statement = this.crudStatements.insert(fields);
|
|
106
116
|
const response = await execute(this.command(), statement, statement.fields);
|
|
107
117
|
if (this.ids.length === 1 && !fields.some((field) => field.name === this.ids[0]))
|
|
@@ -136,7 +146,7 @@ export class CRUDRepository extends ReadonlyRepository {
|
|
|
136
146
|
idValue = (item) => scalarOf(item[this.ids[0]]);
|
|
137
147
|
save = async (item, byWhere) => {
|
|
138
148
|
const record = this.reverseConvert(item);
|
|
139
|
-
const fields = fieldsOf(record, (col) => !this.ids.includes(col), this.cell, this.enrichmentInto);
|
|
149
|
+
const fields = fieldsOf(record, (col) => listed(this.updateProperties, col, !this.ids.includes(col)), this.cell, this.enrichmentInto, this.crudStatements.readColumns, this.column);
|
|
140
150
|
if (fields.length === 0)
|
|
141
151
|
throw new DatasourceError("Update requires at least one non-Id field");
|
|
142
152
|
const statement = this.crudStatements.update(fields, byWhere ?? this.idWhere(record), (name, value) => this.cell(name, value, byWhere === undefined));
|
|
@@ -149,7 +159,7 @@ export class CRUDRepository extends ReadonlyRepository {
|
|
|
149
159
|
const parameters = listed.length
|
|
150
160
|
? listed
|
|
151
161
|
: DefaultStatementTextRenderer.instance.render(statement).includes("$")
|
|
152
|
-
? fieldsOf(record, () => true, this.cell, this.enrichmentInto)
|
|
162
|
+
? fieldsOf(record, () => true, this.cell, this.enrichmentInto, this.crudStatements.readColumns, this.column)
|
|
153
163
|
: [];
|
|
154
164
|
return execute(this.command(), statement, parameters);
|
|
155
165
|
};
|
|
@@ -3,5 +3,7 @@ import type { Cells } from "./converters/Cell.js";
|
|
|
3
3
|
import type { IWriteEnrichmentStrategy } from "./IWriteEnrichmentStrategy.js";
|
|
4
4
|
export type CRUDRepositoryOptions<T = Cells> = ReadonlyRepositoryMappingOptions<T> & {
|
|
5
5
|
ids?: string[];
|
|
6
|
+
createProperties?: string[];
|
|
7
|
+
updateProperties?: string[];
|
|
6
8
|
write?: IWriteEnrichmentStrategy<T>;
|
|
7
9
|
};
|
package/dist/DriverLoader.js
CHANGED
|
@@ -1,16 +1,34 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { createRequire, registerHooks } from "node:module";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
6
|
import { ProviderNotInstalledError } from "./ProviderNotInstalledError.js";
|
|
7
7
|
const require = createRequire(import.meta.url);
|
|
8
|
-
const
|
|
8
|
+
const requirers = () => [
|
|
9
|
+
createRequire(join(process.cwd(), "package.json")),
|
|
10
|
+
...(process.argv[1] ? [createRequire(process.argv[1])] : []),
|
|
11
|
+
require,
|
|
12
|
+
];
|
|
13
|
+
const missingModule = (error) => error instanceof Error &&
|
|
14
|
+
"code" in error &&
|
|
15
|
+
(error.code === "MODULE_NOT_FOUND" ||
|
|
16
|
+
error.code === "ERR_MODULE_NOT_FOUND" ||
|
|
17
|
+
error.code === "ERR_PACKAGE_PATH_NOT_EXPORTED");
|
|
9
18
|
const virtual = new Map();
|
|
10
19
|
const virtualBySource = new Map();
|
|
11
20
|
let typeScriptHook = false;
|
|
12
21
|
let compiling = false;
|
|
22
|
+
let compilingRoot = "";
|
|
13
23
|
let nextVirtual = 0;
|
|
24
|
+
/* v8 ignore start */
|
|
25
|
+
const underRoot = (url) => {
|
|
26
|
+
if (!url.startsWith("file:"))
|
|
27
|
+
return false;
|
|
28
|
+
const path = fileURLToPath(url);
|
|
29
|
+
return path === compilingRoot || path.startsWith(`${compilingRoot}/`);
|
|
30
|
+
};
|
|
31
|
+
/* v8 ignore stop */
|
|
14
32
|
const installTypeScriptHook = () => {
|
|
15
33
|
if (typeScriptHook)
|
|
16
34
|
return;
|
|
@@ -21,7 +39,7 @@ const installTypeScriptHook = () => {
|
|
|
21
39
|
const parentURL = context.parentURL ? virtual.get(context.parentURL) ?? context.parentURL : undefined;
|
|
22
40
|
const resolved = nextResolve(specifier, parentURL ? { ...context, parentURL } : context);
|
|
23
41
|
/* v8 ignore next */
|
|
24
|
-
if (!compiling || !resolved.url.endsWith(".ts"))
|
|
42
|
+
if (!compiling || !resolved.url.endsWith(".ts") || !underRoot(resolved.url))
|
|
25
43
|
return resolved;
|
|
26
44
|
const existing = virtualBySource.get(resolved.url);
|
|
27
45
|
/* v8 ignore next */
|
|
@@ -33,7 +51,7 @@ const installTypeScriptHook = () => {
|
|
|
33
51
|
return { url, shortCircuit: true };
|
|
34
52
|
},
|
|
35
53
|
load: (url, context, nextLoad) => {
|
|
36
|
-
const original = virtual.get(url) ?? (compiling && url.endsWith(".ts") ? url : undefined);
|
|
54
|
+
const original = virtual.get(url) ?? (compiling && url.endsWith(".ts") && underRoot(url) ? url : undefined);
|
|
37
55
|
/* v8 ignore next */
|
|
38
56
|
if (!original)
|
|
39
57
|
return nextLoad(url, context);
|
|
@@ -58,14 +76,27 @@ const instantiate = (catalog) => {
|
|
|
58
76
|
}
|
|
59
77
|
finally {
|
|
60
78
|
compiling = false;
|
|
79
|
+
compilingRoot = "";
|
|
61
80
|
}
|
|
62
81
|
};
|
|
63
82
|
const instantiateLoaded = (catalog) => {
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
83
|
+
let last;
|
|
84
|
+
for (const req of requirers()) {
|
|
85
|
+
try {
|
|
86
|
+
compilingRoot = dirname(req.resolve(catalog.location));
|
|
87
|
+
const loaded = req(catalog.location);
|
|
88
|
+
const Type = loaded[catalog.module];
|
|
89
|
+
if (typeof Type !== "function")
|
|
90
|
+
throw new ProviderNotInstalledError(catalog.name);
|
|
91
|
+
return new Type();
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
last = error;
|
|
95
|
+
if (error instanceof ProviderNotInstalledError || !missingModule(error))
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
throw last instanceof ProviderNotInstalledError ? last : new ProviderNotInstalledError(catalog.name);
|
|
69
100
|
};
|
|
70
101
|
export class DriverLoader {
|
|
71
102
|
static load = (catalog) => {
|