@deterministic-code/datasources-cli 0.1.13 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/detect.js +21 -7
- package/dist/generate/CSharpRepositories.js +18 -14
- package/dist/generate/DeterministicProvider.js +23 -7
- package/dist/generate/RepositoryModel.js +10 -4
- package/dist/generate/RepositoryPlan.js +12 -5
- package/dist/generate/RustRepositories.js +42 -31
- package/dist/generate/TypeScriptRepositories.js +22 -18
- package/dist/generate/applyGenerate.js +9 -2
- package/dist/generate/applyMigrations.js +5 -13
- package/dist/generate/casing.js +28 -0
- package/dist/generate/migrateUp.js +2 -8
- package/dist/generate/sqlFlags.js +27 -0
- package/dist/migrateInit.js +4 -3
- package/dist/parse.js +102 -25
- package/dist/run.js +42 -67
- package/dist/setup.js +7 -9
- package/dist/version/applyVersion.js +11 -14
- package/dist/version/delta.js +0 -50
- package/dist/version/render.js +1 -11
- package/dist/wireRegister.js +29 -11
- package/dist/wireRustProviders.js +42 -0
- package/node_modules/@deterministic-code/csharp-generators/dist/import-generator.js +16 -12
- package/node_modules/@deterministic-code/csharp-generators/src/import-generator.test.ts +22 -11
- package/node_modules/@deterministic-code/csharp-generators/src/import-generator.ts +21 -13
- package/node_modules/@deterministic-code/datasources-code-generators/dist/nestedSelectTypes.js +2 -6
- package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/infer-reference-types.d.ts +2 -0
- package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/infer-reference-types.js +37 -0
- package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/reference-target.d.ts +2 -0
- package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/reference-target.js +6 -0
- package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/sql-schema.d.ts +1 -1
- package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/sql-schema.js +3 -6
- package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/version-migrations.js +25 -14
- package/node_modules/@deterministic-code/datasources-code-generators/package.json +4 -2
- package/node_modules/@deterministic-code/deterministic-generators-common/README.md +61 -1
- package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/dist/specification-parser.js +128 -1
- package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/specification-parser.ts +1 -0
- package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/version-snapshot.ts +154 -0
- package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/yaml-node.ts +2 -2
- package/node_modules/@deterministic-code/rust-generators/dist/import-generator.js +25 -15
- package/node_modules/@deterministic-code/rust-generators/src/import-generator.test.ts +11 -0
- package/node_modules/@deterministic-code/rust-generators/src/import-generator.ts +36 -18
- package/node_modules/@deterministic-code/typescript-generators/dist/generate-frontend-types.js +6 -1
- package/node_modules/@deterministic-code/typescript-generators/dist/generate-frontend-validators.js +6 -1
- package/node_modules/@deterministic-code/typescript-generators/dist/generate-routes.js +1 -1
- package/node_modules/@deterministic-code/typescript-generators/dist/generate-services.js +1 -1
- package/node_modules/@deterministic-code/typescript-generators/dist/import-generator.js +29 -21
- package/node_modules/@deterministic-code/typescript-generators/src/emit.ts +2 -5
- package/node_modules/@deterministic-code/typescript-generators/src/generate-frontend-types.ts +7 -1
- package/node_modules/@deterministic-code/typescript-generators/src/generate-frontend-validators.ts +7 -1
- package/node_modules/@deterministic-code/typescript-generators/src/generate-routes.ts +1 -1
- package/node_modules/@deterministic-code/typescript-generators/src/generate-services.ts +1 -1
- package/node_modules/@deterministic-code/typescript-generators/src/import-generator.test.ts +16 -0
- package/node_modules/@deterministic-code/typescript-generators/src/import-generator.ts +37 -22
- package/package.json +2 -2
package/dist/wireRegister.js
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
import { dirname, isAbsolute, join, relative, sep } from "node:path";
|
|
2
|
+
import { createCasingStrategy } from "@deterministic-code/generators-common/casing-strategy";
|
|
2
3
|
import { csharpTarget } from "./detect.js";
|
|
4
|
+
import { repositoriesPrefix } from "./generate/casing.js";
|
|
5
|
+
import { rustIdent } from "./generate/RepositoryModel.js";
|
|
3
6
|
const posix = (path) => path.split(sep).join("/");
|
|
4
7
|
const specFrom = (from, to) => {
|
|
5
8
|
const rel = posix(relative(dirname(from), to));
|
|
6
9
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
7
10
|
};
|
|
8
11
|
const hookPath = (cwd, dialect, src) => join(cwd, src ? "src" : ".", dialect === "typescript" ? "datasources-register.ts" : "datasources_register.rs");
|
|
9
|
-
const
|
|
10
|
-
|
|
12
|
+
const registryRel = (dialect, settings) => {
|
|
13
|
+
const casing = createCasingStrategy(dialect, settings);
|
|
14
|
+
const dir = repositoriesPrefix(dialect, casing);
|
|
15
|
+
return dialect === "typescript" ? `${dir}/${casing.convertFileName("repository_registry")}.ts` : `${dir}/mod.rs`;
|
|
16
|
+
};
|
|
17
|
+
const hookContents = (dialect, hook, output, settings = {}) => {
|
|
18
|
+
const casing = createCasingStrategy(dialect, settings);
|
|
19
|
+
return dialect === "typescript" ? `import "${specFrom(hook, join(output, registryRel(dialect, settings)))}";
|
|
20
|
+
` : `#[path = "${specFrom(hook, join(output, registryRel(dialect, settings)))}"]
|
|
11
21
|
pub mod repositories;
|
|
12
|
-
pub use repositories
|
|
22
|
+
pub use repositories::${rustIdent(casing.convertFileName("repository_registry"))}::Repositories;
|
|
13
23
|
`;
|
|
24
|
+
};
|
|
14
25
|
const cargoWithCtor = (cargo) => /^\s*ctor\s*=/m.test(cargo) ? void 0 : cargo.includes("[dependencies]") ? cargo.replace("[dependencies]", `[dependencies]
|
|
15
26
|
ctor = "0.4"`) : `${cargo.trimEnd()}
|
|
16
27
|
|
|
@@ -30,7 +41,7 @@ const optional = async (fs, path) => {
|
|
|
30
41
|
}
|
|
31
42
|
};
|
|
32
43
|
const outputRoot = (cwd, output) => isAbsolute(output) ? output : join(cwd, output);
|
|
33
|
-
const registryPath = (root, dialect) =>
|
|
44
|
+
const registryPath = (root, dialect, settings) => join(root, registryRel(dialect, settings));
|
|
34
45
|
const firstFile = async (fs, cwd, names) => {
|
|
35
46
|
for (const name of names) {
|
|
36
47
|
const path = join(cwd, name);
|
|
@@ -39,6 +50,7 @@ const firstFile = async (fs, cwd, names) => {
|
|
|
39
50
|
}
|
|
40
51
|
return void 0;
|
|
41
52
|
};
|
|
53
|
+
const excludeNodeModules = " <PropertyGroup>\n <DefaultItemExcludes>$(DefaultItemExcludes);node_modules/**</DefaultItemExcludes>\n </PropertyGroup>\n";
|
|
42
54
|
const wireCsharp = async (cwd, output, dryRun, deps) => {
|
|
43
55
|
const entries = await deps.fs.readdir(cwd).catch(() => []);
|
|
44
56
|
const target = csharpTarget(entries);
|
|
@@ -46,28 +58,34 @@ const wireCsharp = async (cwd, output, dryRun, deps) => {
|
|
|
46
58
|
const csprojPath = join(cwd, target);
|
|
47
59
|
const generated = join(outputRoot(cwd, output), "csharp");
|
|
48
60
|
const rel = posix(relative(dirname(csprojPath), generated));
|
|
49
|
-
if (!rel.startsWith("..")) return;
|
|
50
61
|
const include = `${rel}/**/*.cs`;
|
|
51
62
|
const existing = await optional(deps.fs, csprojPath);
|
|
52
|
-
if (existing === void 0
|
|
63
|
+
if (existing === void 0) return;
|
|
64
|
+
const needExclude = !existing.includes("node_modules/**");
|
|
65
|
+
const needInclude = rel.startsWith("..") && !existing.includes(include);
|
|
66
|
+
if (!needExclude && !needInclude) return;
|
|
53
67
|
if (dryRun) {
|
|
54
68
|
deps.log(csprojPath);
|
|
55
69
|
return;
|
|
56
70
|
}
|
|
57
|
-
|
|
71
|
+
const patched = [
|
|
72
|
+
needExclude ? excludeNodeModules : "",
|
|
73
|
+
needInclude ? ` <ItemGroup>
|
|
58
74
|
<Compile Include="${include}" />
|
|
59
75
|
</ItemGroup>
|
|
60
|
-
|
|
76
|
+
` : ""
|
|
77
|
+
].join("");
|
|
78
|
+
await deps.fs.writeFile(csprojPath, existing.replace("</Project>", `${patched}</Project>`));
|
|
61
79
|
deps.log(csprojPath);
|
|
62
80
|
};
|
|
63
|
-
const wireRegister = async (cwd, output, dialect, dryRun, deps) => {
|
|
81
|
+
const wireRegister = async (cwd, output, dialect, dryRun, deps, settings = {}) => {
|
|
64
82
|
if (dialect === "csharp") return wireCsharp(cwd, output, dryRun, deps);
|
|
65
83
|
const root = outputRoot(cwd, output);
|
|
66
84
|
if (relative(cwd, root).startsWith("..")) return;
|
|
67
|
-
if (await optional(deps.fs, registryPath(root, dialect)) === void 0) return;
|
|
85
|
+
if (await optional(deps.fs, registryPath(root, dialect, settings)) === void 0) return;
|
|
68
86
|
const entries = await deps.fs.readdir(cwd).catch(() => []);
|
|
69
87
|
const hook = hookPath(cwd, dialect, entries.includes("src"));
|
|
70
|
-
const text = hookContents(dialect, hook, root);
|
|
88
|
+
const text = hookContents(dialect, hook, root, settings);
|
|
71
89
|
if (dryRun) {
|
|
72
90
|
deps.log(hook);
|
|
73
91
|
return;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import { catalog } from "./catalog.js";
|
|
3
|
+
const optional = async (fs, path) => {
|
|
4
|
+
try {
|
|
5
|
+
return await fs.readFile(path);
|
|
6
|
+
} catch {
|
|
7
|
+
return void 0;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
const firstFile = async (fs, cwd, names) => {
|
|
11
|
+
for (const name of names) {
|
|
12
|
+
const path = join(cwd, name);
|
|
13
|
+
const text = await optional(fs, path);
|
|
14
|
+
if (text !== void 0) return { path, text };
|
|
15
|
+
}
|
|
16
|
+
return void 0;
|
|
17
|
+
};
|
|
18
|
+
const rustBindContents = (names) => names.map((name) => `use ${catalog[name].cargo.replaceAll("-", "_")} as _;
|
|
19
|
+
`).join("");
|
|
20
|
+
const attachedProviders = (entry) => entry.includes("datasources_providers") ? void 0 : `mod datasources_providers;
|
|
21
|
+
${entry}`;
|
|
22
|
+
const wireRustProviders = async (cwd, names, dryRun, deps) => {
|
|
23
|
+
const entry = await firstFile(deps.fs, cwd, ["src/lib.rs", "src/main.rs", "lib.rs", "main.rs"]);
|
|
24
|
+
const bind = join(entry ? dirname(entry.path) : cwd, "datasources_providers.rs");
|
|
25
|
+
const text = rustBindContents(names);
|
|
26
|
+
if (dryRun) {
|
|
27
|
+
deps.log(bind);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
await deps.fs.writeFile(bind, text);
|
|
31
|
+
deps.log(bind);
|
|
32
|
+
if (!entry) return;
|
|
33
|
+
const next = attachedProviders(entry.text);
|
|
34
|
+
if (next === void 0) return;
|
|
35
|
+
await deps.fs.writeFile(entry.path, next);
|
|
36
|
+
deps.log(entry.path);
|
|
37
|
+
};
|
|
38
|
+
export {
|
|
39
|
+
attachedProviders,
|
|
40
|
+
rustBindContents,
|
|
41
|
+
wireRustProviders
|
|
42
|
+
};
|
|
@@ -10,10 +10,6 @@ const pluralSnake = (entity) => {
|
|
|
10
10
|
parts[parts.length - 1] = pluralize.plural(parts[parts.length - 1]);
|
|
11
11
|
return parts.join("_");
|
|
12
12
|
};
|
|
13
|
-
const DATASOURCE_DIR = "Types/Datasource/Generated";
|
|
14
|
-
const VIEW_DIR = "Types/View/Generated";
|
|
15
|
-
const DATASOURCE_VALIDATOR_DIR = `${DATASOURCE_DIR}/Validators`;
|
|
16
|
-
const VIEW_VALIDATOR_DIR = `${VIEW_DIR}/Validators`;
|
|
17
13
|
class CsharpImportGenerator {
|
|
18
14
|
organizeByFeature;
|
|
19
15
|
flat;
|
|
@@ -26,7 +22,7 @@ class CsharpImportGenerator {
|
|
|
26
22
|
this.casing = createCasing(settings);
|
|
27
23
|
}
|
|
28
24
|
datasource(entity) {
|
|
29
|
-
return this.underBase(this.rel(
|
|
25
|
+
return this.underBase(this.rel(this.layered("types/datasource/generated"), this.casedFile(entity)));
|
|
30
26
|
}
|
|
31
27
|
datasourceRel(entity) {
|
|
32
28
|
return this.datasource(entity);
|
|
@@ -37,7 +33,7 @@ class CsharpImportGenerator {
|
|
|
37
33
|
datasourceValidator(entity) {
|
|
38
34
|
return this.underBase(
|
|
39
35
|
this.rel(
|
|
40
|
-
|
|
36
|
+
this.layered("types/datasource/generated/validators"),
|
|
41
37
|
this.csFile(`datasource_${entity}_validator`)
|
|
42
38
|
)
|
|
43
39
|
);
|
|
@@ -46,7 +42,7 @@ class CsharpImportGenerator {
|
|
|
46
42
|
return this.datasourceValidator(entity);
|
|
47
43
|
}
|
|
48
44
|
view(entity) {
|
|
49
|
-
return this.underBase(this.rel(
|
|
45
|
+
return this.underBase(this.rel(this.layered("types/view/generated"), this.csFile(entity)));
|
|
50
46
|
}
|
|
51
47
|
viewRel(entity) {
|
|
52
48
|
return this.view(entity);
|
|
@@ -56,7 +52,7 @@ class CsharpImportGenerator {
|
|
|
56
52
|
}
|
|
57
53
|
viewValidator(entity) {
|
|
58
54
|
return this.underBase(
|
|
59
|
-
this.rel(
|
|
55
|
+
this.rel(this.layered("types/view/generated/validators"), this.csFile(`${entity}_validator`))
|
|
60
56
|
);
|
|
61
57
|
}
|
|
62
58
|
viewValidatorRel(entity) {
|
|
@@ -71,12 +67,12 @@ class CsharpImportGenerator {
|
|
|
71
67
|
serviceCustom(name, _module) {
|
|
72
68
|
const file = this.csFile(name);
|
|
73
69
|
return this.underBase(
|
|
74
|
-
this.organizeByFeature ?
|
|
70
|
+
this.organizeByFeature ? `${this.featuresDir(featureEntity(name))}/custom/${file}` : `../custom/${file}`
|
|
75
71
|
);
|
|
76
72
|
}
|
|
77
73
|
serviceCustomRel(entity) {
|
|
78
74
|
const file = this.csFile(entity);
|
|
79
|
-
return this.organizeByFeature ?
|
|
75
|
+
return this.organizeByFeature ? `${this.featuresDir(entity)}/custom/${file}` : `../custom/${file}`;
|
|
80
76
|
}
|
|
81
77
|
serviceTest(entity) {
|
|
82
78
|
return this.underBase(this.csFile(`${entity}_service_tests`));
|
|
@@ -102,7 +98,7 @@ class CsharpImportGenerator {
|
|
|
102
98
|
routeCustom(name, _module) {
|
|
103
99
|
const file = this.csFile(`${name}_route`);
|
|
104
100
|
return this.underBase(
|
|
105
|
-
this.organizeByFeature ?
|
|
101
|
+
this.organizeByFeature ? `${this.featuresDir(featureEntity(name))}/custom/${file}` : `../custom/${file}`
|
|
106
102
|
);
|
|
107
103
|
}
|
|
108
104
|
routeTest(entity) {
|
|
@@ -149,7 +145,15 @@ class CsharpImportGenerator {
|
|
|
149
145
|
}
|
|
150
146
|
casedFile(entity) {
|
|
151
147
|
const file = this.csFile(entity);
|
|
152
|
-
return this.organizeByFeature ?
|
|
148
|
+
return this.organizeByFeature ? `${this.featuresDir(entity)}/${file}` : file;
|
|
149
|
+
}
|
|
150
|
+
layered(path) {
|
|
151
|
+
return path.split("/").map(
|
|
152
|
+
(segment) => segment === "custom" ? segment : this.casing.convertDirectories(segment)
|
|
153
|
+
).join("/");
|
|
154
|
+
}
|
|
155
|
+
featuresDir(entity) {
|
|
156
|
+
return `${this.casing.convertDirectories("features")}/${this.casing.directory(entity)}`;
|
|
153
157
|
}
|
|
154
158
|
rel(prefix, file) {
|
|
155
159
|
if (this.organizeByFeature || this.flat) return file;
|
|
@@ -136,6 +136,17 @@ describe("CsharpImportGenerator layered (organize_by_feature unset)", () => {
|
|
|
136
136
|
snake.datasource("notification_type"),
|
|
137
137
|
"Types/Datasource/Generated/notification_type.cs",
|
|
138
138
|
);
|
|
139
|
+
const kebabDirs = createImportGenerator(".", {
|
|
140
|
+
"languages.csharp.casing.directories": "Kebab",
|
|
141
|
+
});
|
|
142
|
+
assert.equal(
|
|
143
|
+
kebabDirs.datasource("user"),
|
|
144
|
+
"types/datasource/generated/User.cs",
|
|
145
|
+
);
|
|
146
|
+
assert.equal(
|
|
147
|
+
kebabDirs.view("user"),
|
|
148
|
+
"types/view/generated/User.cs",
|
|
149
|
+
);
|
|
139
150
|
});
|
|
140
151
|
|
|
141
152
|
it("cases type quals from settings independently of files", () => {
|
|
@@ -173,11 +184,11 @@ describe("CsharpImportGenerator by-feature", () => {
|
|
|
173
184
|
});
|
|
174
185
|
assert.equal(
|
|
175
186
|
imports.datasource("notification_type"),
|
|
176
|
-
"
|
|
187
|
+
"features/notification-type/NotificationType.cs",
|
|
177
188
|
);
|
|
178
189
|
assert.equal(
|
|
179
190
|
imports.datasourceRel("notification_type"),
|
|
180
|
-
"
|
|
191
|
+
"features/notification-type/NotificationType.cs",
|
|
181
192
|
);
|
|
182
193
|
assert.equal(imports.view("user"), "User.cs");
|
|
183
194
|
assert.equal(imports.viewRel("user"), "User.cs");
|
|
@@ -200,31 +211,31 @@ describe("CsharpImportGenerator by-feature", () => {
|
|
|
200
211
|
});
|
|
201
212
|
assert.equal(
|
|
202
213
|
imports.serviceCustom("user"),
|
|
203
|
-
"
|
|
214
|
+
"features/user/custom/User.cs",
|
|
204
215
|
);
|
|
205
216
|
assert.equal(
|
|
206
217
|
imports.serviceCustom("create_card_payment"),
|
|
207
|
-
"
|
|
218
|
+
"features/card-payment/custom/CreateCardPayment.cs",
|
|
208
219
|
);
|
|
209
220
|
assert.equal(
|
|
210
221
|
imports.serviceCustom("update_card_payment"),
|
|
211
|
-
"
|
|
222
|
+
"features/card-payment/custom/UpdateCardPayment.cs",
|
|
212
223
|
);
|
|
213
224
|
assert.equal(
|
|
214
225
|
imports.serviceCustomRel("notification_type"),
|
|
215
|
-
"
|
|
226
|
+
"features/notification-type/custom/NotificationType.cs",
|
|
216
227
|
);
|
|
217
228
|
assert.equal(
|
|
218
229
|
imports.routeCustom("get_health"),
|
|
219
|
-
"
|
|
230
|
+
"features/get-health/custom/GetHealthRoute.cs",
|
|
220
231
|
);
|
|
221
232
|
assert.equal(
|
|
222
233
|
imports.routeCustom("create_card_payment"),
|
|
223
|
-
"
|
|
234
|
+
"features/card-payment/custom/CreateCardPaymentRoute.cs",
|
|
224
235
|
);
|
|
225
236
|
assert.equal(
|
|
226
237
|
imports.serviceCustom("user", "./ignored/module"),
|
|
227
|
-
"
|
|
238
|
+
"features/user/custom/User.cs",
|
|
228
239
|
);
|
|
229
240
|
});
|
|
230
241
|
|
|
@@ -235,11 +246,11 @@ describe("CsharpImportGenerator by-feature", () => {
|
|
|
235
246
|
});
|
|
236
247
|
assert.equal(
|
|
237
248
|
imports.datasource("notification_type"),
|
|
238
|
-
"
|
|
249
|
+
"features/notification_type/NotificationType.cs",
|
|
239
250
|
);
|
|
240
251
|
assert.equal(
|
|
241
252
|
imports.serviceCustomRel("notification_type"),
|
|
242
|
-
"
|
|
253
|
+
"features/notification_type/custom/NotificationType.cs",
|
|
243
254
|
);
|
|
244
255
|
});
|
|
245
256
|
});
|
|
@@ -15,11 +15,6 @@ const pluralSnake = (entity: string): string => {
|
|
|
15
15
|
return parts.join("_");
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
const DATASOURCE_DIR = "Types/Datasource/Generated";
|
|
19
|
-
const VIEW_DIR = "Types/View/Generated";
|
|
20
|
-
const DATASOURCE_VALIDATOR_DIR = `${DATASOURCE_DIR}/Validators`;
|
|
21
|
-
const VIEW_VALIDATOR_DIR = `${VIEW_DIR}/Validators`;
|
|
22
|
-
|
|
23
18
|
export class CsharpImportGenerator implements IImportGenerator {
|
|
24
19
|
private readonly organizeByFeature: boolean;
|
|
25
20
|
private readonly flat: boolean;
|
|
@@ -35,7 +30,7 @@ export class CsharpImportGenerator implements IImportGenerator {
|
|
|
35
30
|
}
|
|
36
31
|
|
|
37
32
|
datasource(entity: string): string {
|
|
38
|
-
return this.underBase(this.rel(
|
|
33
|
+
return this.underBase(this.rel(this.layered("types/datasource/generated"), this.casedFile(entity)));
|
|
39
34
|
}
|
|
40
35
|
|
|
41
36
|
datasourceRel(entity: string): string {
|
|
@@ -49,7 +44,7 @@ export class CsharpImportGenerator implements IImportGenerator {
|
|
|
49
44
|
datasourceValidator(entity: string): string {
|
|
50
45
|
return this.underBase(
|
|
51
46
|
this.rel(
|
|
52
|
-
|
|
47
|
+
this.layered("types/datasource/generated/validators"),
|
|
53
48
|
this.csFile(`datasource_${entity}_validator`),
|
|
54
49
|
),
|
|
55
50
|
);
|
|
@@ -60,7 +55,7 @@ export class CsharpImportGenerator implements IImportGenerator {
|
|
|
60
55
|
}
|
|
61
56
|
|
|
62
57
|
view(entity: string): string {
|
|
63
|
-
return this.underBase(this.rel(
|
|
58
|
+
return this.underBase(this.rel(this.layered("types/view/generated"), this.csFile(entity)));
|
|
64
59
|
}
|
|
65
60
|
|
|
66
61
|
viewRel(entity: string): string {
|
|
@@ -73,7 +68,7 @@ export class CsharpImportGenerator implements IImportGenerator {
|
|
|
73
68
|
|
|
74
69
|
viewValidator(entity: string): string {
|
|
75
70
|
return this.underBase(
|
|
76
|
-
this.rel(
|
|
71
|
+
this.rel(this.layered("types/view/generated/validators"), this.csFile(`${entity}_validator`)),
|
|
77
72
|
);
|
|
78
73
|
}
|
|
79
74
|
|
|
@@ -93,7 +88,7 @@ export class CsharpImportGenerator implements IImportGenerator {
|
|
|
93
88
|
const file = this.csFile(name);
|
|
94
89
|
return this.underBase(
|
|
95
90
|
this.organizeByFeature
|
|
96
|
-
?
|
|
91
|
+
? `${this.featuresDir(featureEntity(name))}/custom/${file}`
|
|
97
92
|
: `../custom/${file}`,
|
|
98
93
|
);
|
|
99
94
|
}
|
|
@@ -101,7 +96,7 @@ export class CsharpImportGenerator implements IImportGenerator {
|
|
|
101
96
|
serviceCustomRel(entity: string): string {
|
|
102
97
|
const file = this.csFile(entity);
|
|
103
98
|
return this.organizeByFeature
|
|
104
|
-
?
|
|
99
|
+
? `${this.featuresDir(entity)}/custom/${file}`
|
|
105
100
|
: `../custom/${file}`;
|
|
106
101
|
}
|
|
107
102
|
|
|
@@ -137,7 +132,7 @@ export class CsharpImportGenerator implements IImportGenerator {
|
|
|
137
132
|
const file = this.csFile(`${name}_route`);
|
|
138
133
|
return this.underBase(
|
|
139
134
|
this.organizeByFeature
|
|
140
|
-
?
|
|
135
|
+
? `${this.featuresDir(featureEntity(name))}/custom/${file}`
|
|
141
136
|
: `../custom/${file}`,
|
|
142
137
|
);
|
|
143
138
|
}
|
|
@@ -205,10 +200,23 @@ export class CsharpImportGenerator implements IImportGenerator {
|
|
|
205
200
|
private casedFile(entity: string): string {
|
|
206
201
|
const file = this.csFile(entity);
|
|
207
202
|
return this.organizeByFeature
|
|
208
|
-
?
|
|
203
|
+
? `${this.featuresDir(entity)}/${file}`
|
|
209
204
|
: file;
|
|
210
205
|
}
|
|
211
206
|
|
|
207
|
+
private layered(path: string): string {
|
|
208
|
+
return path
|
|
209
|
+
.split("/")
|
|
210
|
+
.map((segment) =>
|
|
211
|
+
segment === "custom" ? segment : this.casing.convertDirectories(segment),
|
|
212
|
+
)
|
|
213
|
+
.join("/");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private featuresDir(entity: string): string {
|
|
217
|
+
return `${this.casing.convertDirectories("features")}/${this.casing.directory(entity)}`;
|
|
218
|
+
}
|
|
219
|
+
|
|
212
220
|
private rel(prefix: string, file: string): string {
|
|
213
221
|
if (this.organizeByFeature || this.flat) return file;
|
|
214
222
|
return `${prefix}/${file}`;
|
package/node_modules/@deterministic-code/datasources-code-generators/dist/nestedSelectTypes.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { referenceTarget } from "./sql/common/reference-target.js";
|
|
1
2
|
import { ChangeCasingMapper, NestedSelectBuilder, PluralizerMapper } from "@deterministic-code/datasources";
|
|
2
3
|
const pascal = new ChangeCasingMapper("snakeCase", "pascalCase");
|
|
3
4
|
const plural = new PluralizerMapper();
|
|
@@ -51,12 +52,7 @@ const build = (type, catalog, ancestors) => {
|
|
|
51
52
|
});
|
|
52
53
|
return { name: entity(type.name), key, properties, relations: [...objects, ...lists] };
|
|
53
54
|
};
|
|
54
|
-
const target = (field) =>
|
|
55
|
-
if (Array.isArray(field.references) && field.references.length === 2)
|
|
56
|
-
return [field.references[0] ?? "", field.references[1] ?? ""];
|
|
57
|
-
const [table, column] = String(field.references ?? "").split(".");
|
|
58
|
-
return [table ?? "", column ?? ""];
|
|
59
|
-
};
|
|
55
|
+
const target = (field) => field.references === undefined ? ["", ""] : referenceTarget(field.references);
|
|
60
56
|
const relationName = (field, table) => {
|
|
61
57
|
const name = entity(field);
|
|
62
58
|
return name.endsWith("Id") && name.length > 2 ? name.slice(0, -2) : entity(table);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { referenceTarget } from "./reference-target.js";
|
|
2
|
+
const needsType = (field) => !field.isArray &&
|
|
3
|
+
!field.isMap &&
|
|
4
|
+
field.references !== undefined &&
|
|
5
|
+
field.type === "string" &&
|
|
6
|
+
field.size === undefined;
|
|
7
|
+
const ready = (field) => field.type !== "string" || field.size !== undefined;
|
|
8
|
+
const lookup = (types, field) => {
|
|
9
|
+
const [table, column] = referenceTarget(field.references);
|
|
10
|
+
return types.find((type) => type.name === table)?.fields.find((item) => item.name === column);
|
|
11
|
+
};
|
|
12
|
+
export const inferReferenceFieldTypes = (types) => {
|
|
13
|
+
const working = types.map((type) => ({ ...type, fields: type.fields.map((field) => ({ ...field })) }));
|
|
14
|
+
for (let pass = 0; pass < working.length; pass++) {
|
|
15
|
+
let changed = false;
|
|
16
|
+
for (const type of working) {
|
|
17
|
+
type.fields = type.fields.map((field) => {
|
|
18
|
+
if (!needsType(field))
|
|
19
|
+
return field;
|
|
20
|
+
const parent = lookup(working, field);
|
|
21
|
+
if (parent === undefined || !ready(parent))
|
|
22
|
+
return field;
|
|
23
|
+
changed = true;
|
|
24
|
+
return {
|
|
25
|
+
...field,
|
|
26
|
+
type: parent.type,
|
|
27
|
+
kind: parent.kind,
|
|
28
|
+
base: parent.base,
|
|
29
|
+
...(parent.size !== undefined ? { size: parent.size } : {}),
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (!changed)
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
return working;
|
|
37
|
+
};
|
package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/sql-schema.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DatasourceFieldOverlay, DatasourceIndex, DatasourceTable, IDeterministic, Type, TypeField } from "@deterministic-code/deterministic-generators-common/parser";
|
|
2
|
+
export { referenceTarget } from "./reference-target.js";
|
|
2
3
|
/** Flattened `datasource.*` flags. Stored procedures are opt-in `"true"`. */
|
|
3
4
|
export declare const datasourceSettings: (settings: Record<string, string>) => {
|
|
4
5
|
useStoredProcedures: boolean;
|
|
@@ -28,7 +29,6 @@ export type SqlFile = {
|
|
|
28
29
|
path: string;
|
|
29
30
|
content: string;
|
|
30
31
|
};
|
|
31
|
-
export declare const referenceTarget: (references: NonNullable<TypeField["references"]>) => [string, string];
|
|
32
32
|
/** Attach physical names and order parent tables before children. */
|
|
33
33
|
export declare const buildLiveTables: (types: SqlTable[], mapping: {
|
|
34
34
|
tableName: (table: SqlTable) => string;
|
package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/sql-schema.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { datasourceTypesOf, dictionaryUniqueColumns, identityColumns, persistedColumnFields, tableByName, } from "@deterministic-code/generators-common/spec-types";
|
|
2
|
+
import { inferReferenceFieldTypes } from "./infer-reference-types.js";
|
|
3
|
+
export { referenceTarget } from "./reference-target.js";
|
|
2
4
|
/** Flattened `datasource.*` flags. Stored procedures are opt-in `"true"`. */
|
|
3
5
|
export const datasourceSettings = (settings) => ({
|
|
4
6
|
useStoredProcedures: String(settings["datasource.use_stored_procedures"]) === "true",
|
|
@@ -44,6 +46,7 @@ export const isGeneratedIdentity = (table) => {
|
|
|
44
46
|
export const usesGeneratedIdColumn = (table, field) => field.isId === true && isGeneratedIdentity(table);
|
|
45
47
|
export const sqlTablesFrom = (spec) => {
|
|
46
48
|
requireIdIsId(spec);
|
|
49
|
+
spec = { ...spec, expandedTypes: inferReferenceFieldTypes(spec.expandedTypes) };
|
|
47
50
|
const overlays = tableByName(spec);
|
|
48
51
|
const byName = new Map(spec.expandedTypes.map((t) => [t.name, t]));
|
|
49
52
|
return datasourceTypesOf(spec).map((type) => {
|
|
@@ -80,12 +83,6 @@ const referenceParents = (references) => {
|
|
|
80
83
|
return [references[0]];
|
|
81
84
|
return [references.split(".")[0]];
|
|
82
85
|
};
|
|
83
|
-
export const referenceTarget = (references) => {
|
|
84
|
-
if (Array.isArray(references))
|
|
85
|
-
return [references[0], references[1]];
|
|
86
|
-
const [table, col] = references.split(".");
|
|
87
|
-
return [table ?? "", col ?? ""];
|
|
88
|
-
};
|
|
89
86
|
const topoSort = (tables) => {
|
|
90
87
|
const names = new Set(tables.map((t) => t.name));
|
|
91
88
|
const deps = new Map(tables.map((t) => [
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { parse
|
|
1
|
+
import { parse } from "yaml";
|
|
2
2
|
import { CreateTableStatement } from "@deterministic-code/datasources";
|
|
3
3
|
import { memoryReader } from "@deterministic-code/generators-common/deterministic-reader";
|
|
4
|
-
import { DeterministicParser } from "@deterministic-code/deterministic-generators-common/parser";
|
|
5
|
-
import { applyDocument, isObject, snapshotsEqual } from "./version-apply.js";
|
|
4
|
+
import { DeterministicParser, VersionSnapshot } from "@deterministic-code/deterministic-generators-common/parser";
|
|
6
5
|
import { createCasing } from "./default-casing.js";
|
|
7
6
|
import { SqlMapping } from "./sql-mapping.js";
|
|
8
7
|
import { buildLiveTables, sqlTablesFrom } from "./sql-schema.js";
|
|
@@ -23,11 +22,26 @@ export const versionDiffPaths = (settings) => (settings["version.diffs"] ?? "")
|
|
|
23
22
|
.split("\n")
|
|
24
23
|
.map((path) => path.trim())
|
|
25
24
|
.filter((path) => versionDiff.test(path));
|
|
26
|
-
const
|
|
25
|
+
const own = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
|
|
26
|
+
const parseDiff = (text, source) => {
|
|
27
|
+
const value = parse(text);
|
|
28
|
+
if (value == null || typeof value !== "object" || Array.isArray(value))
|
|
29
|
+
throw new Error(`${source}: expected a mapping`);
|
|
30
|
+
return value;
|
|
31
|
+
};
|
|
32
|
+
const fold = (path, text) => VersionSnapshot.combine([{ [path]: { added: true, content: parse(text) } }]).yaml(path);
|
|
33
|
+
const matches = (snapshot, path, live, whenMissing) => {
|
|
34
|
+
const has = own(snapshot.documents, path);
|
|
35
|
+
const text = live === undefined || live === "" ? whenMissing : live;
|
|
36
|
+
if (text === undefined || text === "")
|
|
37
|
+
return !has;
|
|
38
|
+
const snapshotYaml = has ? snapshot.yaml(path) : whenMissing === undefined ? undefined : fold(path, whenMissing);
|
|
39
|
+
return snapshotYaml !== undefined && snapshotYaml === fold(path, text);
|
|
40
|
+
};
|
|
27
41
|
const filesOf = (snapshot) => {
|
|
28
42
|
const files = {};
|
|
29
|
-
for (const
|
|
30
|
-
files[path] =
|
|
43
|
+
for (const path of Object.keys(snapshot.documents))
|
|
44
|
+
files[path] = snapshot.yaml(path);
|
|
31
45
|
files["datasource.yaml"] ??= defaultDatasourceYaml;
|
|
32
46
|
return files;
|
|
33
47
|
};
|
|
@@ -37,7 +51,7 @@ const compile = async (snapshot, settings) => {
|
|
|
37
51
|
const mapping = new SqlMapping(createCasing(settings), types);
|
|
38
52
|
return { tables: buildLiveTables(types, mapping), mapping, seeds: spec.datasourceSeeds };
|
|
39
53
|
};
|
|
40
|
-
const emptySnapshot = (settings) => compile(
|
|
54
|
+
const emptySnapshot = (settings) => compile(VersionSnapshot.combine([]), settings);
|
|
41
55
|
const pad = (n) => String(n).padStart(4, "0");
|
|
42
56
|
const renderAll = (dialect, statements) => statements
|
|
43
57
|
.map((statement) => renderSql(dialect, statement))
|
|
@@ -48,22 +62,19 @@ export const versionMigrationFiles = async (dialect, ctx, casing, live) => {
|
|
|
48
62
|
const paths = versionDiffPaths(ctx.settings);
|
|
49
63
|
if (paths.length === 0)
|
|
50
64
|
return { files: [], count: 0 };
|
|
51
|
-
|
|
65
|
+
const diffs = [];
|
|
52
66
|
const snapshots = [];
|
|
53
67
|
for (const path of paths) {
|
|
54
68
|
const text = await ctx.reader.read(path);
|
|
55
69
|
if (text === "")
|
|
56
70
|
continue;
|
|
57
|
-
|
|
58
|
-
snapshots.push(
|
|
71
|
+
diffs.push(parseDiff(text, path));
|
|
72
|
+
snapshots.push(VersionSnapshot.combine(diffs));
|
|
59
73
|
}
|
|
60
74
|
if (snapshots.length === 0)
|
|
61
75
|
return { files: [], count: 0 };
|
|
62
76
|
const last = snapshots[snapshots.length - 1];
|
|
63
|
-
|
|
64
|
-
const liveDatasource = parse(live.datasourceYaml ?? defaultDatasourceYaml);
|
|
65
|
-
const snapshotDatasource = last["datasource.yaml"] ?? parse(defaultDatasourceYaml);
|
|
66
|
-
if (!snapshotsEqual(last["types.yaml"], liveTypes) || !snapshotsEqual(snapshotDatasource, liveDatasource)) {
|
|
77
|
+
if (!matches(last, "types.yaml", live.typesYaml, undefined) || !matches(last, "datasource.yaml", live.datasourceYaml, defaultDatasourceYaml)) {
|
|
67
78
|
throw new Error("types.yaml or datasource.yaml differs from the frozen version diffs; run datasources version first");
|
|
68
79
|
}
|
|
69
80
|
const files = [];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deterministic-code/datasources-code-generators",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/generateSql.js",
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
"./generate-stored-procedures": "./dist/generate-stored-procedures.js",
|
|
10
10
|
"./sql/generate-stored-procedures": "./dist/sql/generate-stored-procedures.js",
|
|
11
11
|
"./common/sql-dialect": "./dist/sql/common/sql-dialect.js",
|
|
12
|
-
"./sql/common/write-inclusion": "./dist/sql/common/write-inclusion.js"
|
|
12
|
+
"./sql/common/write-inclusion": "./dist/sql/common/write-inclusion.js",
|
|
13
|
+
"./sql/common/default-casing": "./dist/sql/common/default-casing.js",
|
|
14
|
+
"./sql/common/infer-reference-types": "./dist/sql/common/infer-reference-types.js"
|
|
13
15
|
},
|
|
14
16
|
"dependencies": {
|
|
15
17
|
"@deterministic-code/datasources": "^0.1.12",
|