@zenstackhq/cli 3.4.0-beta.1 → 3.4.0-beta.3
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/index.cjs +219 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +219 -79
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
package/dist/index.js
CHANGED
|
@@ -26,6 +26,7 @@ import { isDataSource } from "@zenstackhq/language/ast";
|
|
|
26
26
|
import { PrismaSchemaGenerator } from "@zenstackhq/sdk";
|
|
27
27
|
import colors from "colors";
|
|
28
28
|
import fs from "fs";
|
|
29
|
+
import { createRequire } from "module";
|
|
29
30
|
import path from "path";
|
|
30
31
|
|
|
31
32
|
// src/cli-error.ts
|
|
@@ -141,10 +142,10 @@ function findUp(names, cwd = process.cwd(), multiple = false, result = []) {
|
|
|
141
142
|
}
|
|
142
143
|
const target = names.find((name) => fs.existsSync(path.join(cwd, name)));
|
|
143
144
|
if (multiple === false && target) {
|
|
144
|
-
return path.
|
|
145
|
+
return path.resolve(cwd, target);
|
|
145
146
|
}
|
|
146
147
|
if (target) {
|
|
147
|
-
result.push(path.
|
|
148
|
+
result.push(path.resolve(cwd, target));
|
|
148
149
|
}
|
|
149
150
|
const up = path.resolve(cwd, "..");
|
|
150
151
|
if (up === cwd) {
|
|
@@ -173,6 +174,44 @@ function getOutputPath(options, schemaFile) {
|
|
|
173
174
|
}
|
|
174
175
|
}
|
|
175
176
|
__name(getOutputPath, "getOutputPath");
|
|
177
|
+
async function getZenStackPackages(searchPath) {
|
|
178
|
+
const pkgJsonFile = findUp([
|
|
179
|
+
"package.json"
|
|
180
|
+
], searchPath, false);
|
|
181
|
+
if (!pkgJsonFile) {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
let pkgJson;
|
|
185
|
+
try {
|
|
186
|
+
pkgJson = JSON.parse(fs.readFileSync(pkgJsonFile, "utf8"));
|
|
187
|
+
} catch {
|
|
188
|
+
return [];
|
|
189
|
+
}
|
|
190
|
+
const packages = Array.from(new Set([
|
|
191
|
+
...Object.keys(pkgJson.dependencies ?? {}),
|
|
192
|
+
...Object.keys(pkgJson.devDependencies ?? {})
|
|
193
|
+
].filter((p) => p.startsWith("@zenstackhq/")))).sort();
|
|
194
|
+
const require2 = createRequire(pkgJsonFile);
|
|
195
|
+
const result = packages.map((pkg) => {
|
|
196
|
+
try {
|
|
197
|
+
const depPkgJson = require2(`${pkg}/package.json`);
|
|
198
|
+
if (depPkgJson.private) {
|
|
199
|
+
return void 0;
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
pkg,
|
|
203
|
+
version: depPkgJson.version
|
|
204
|
+
};
|
|
205
|
+
} catch {
|
|
206
|
+
return {
|
|
207
|
+
pkg,
|
|
208
|
+
version: void 0
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
return result.filter((p) => !!p);
|
|
213
|
+
}
|
|
214
|
+
__name(getZenStackPackages, "getZenStackPackages");
|
|
176
215
|
|
|
177
216
|
// src/actions/check.ts
|
|
178
217
|
async function run(options) {
|
|
@@ -252,6 +291,14 @@ import { lowerCaseFirst } from "@zenstackhq/common-helpers";
|
|
|
252
291
|
// src/actions/pull/utils.ts
|
|
253
292
|
import { isInvocationExpr } from "@zenstackhq/language/ast";
|
|
254
293
|
import { getLiteralArray, getStringLiteral } from "@zenstackhq/language/utils";
|
|
294
|
+
function isDatabaseManagedAttribute(name) {
|
|
295
|
+
return [
|
|
296
|
+
"@relation",
|
|
297
|
+
"@id",
|
|
298
|
+
"@unique"
|
|
299
|
+
].includes(name) || name.startsWith("@db.");
|
|
300
|
+
}
|
|
301
|
+
__name(isDatabaseManagedAttribute, "isDatabaseManagedAttribute");
|
|
255
302
|
function getDatasource(model) {
|
|
256
303
|
const datasource = model.declarations.find((d) => d.$type === "DataSource");
|
|
257
304
|
if (!datasource) {
|
|
@@ -714,12 +761,84 @@ function syncRelation({ model, relation, services, options, selfRelation, simila
|
|
|
714
761
|
});
|
|
715
762
|
sourceModel.fields.splice(firstSourceFieldId, 0, sourceFieldFactory.node);
|
|
716
763
|
const oppositeFieldPrefix = /[0-9]/g.test(targetModel.name.charAt(0)) ? "_" : "";
|
|
717
|
-
|
|
764
|
+
let { name: oppositeFieldName } = resolveNameCasing(options.fieldCasing, similarRelations > 0 ? `${oppositeFieldPrefix}${lowerCaseFirst(sourceModel.name)}_${firstColumn}` : `${lowerCaseFirst(resolveNameCasing(options.fieldCasing, sourceModel.name).name)}${relation.references.type === "many" ? "s" : ""}`);
|
|
765
|
+
if (targetModel.fields.find((f) => f.name === oppositeFieldName)) {
|
|
766
|
+
({ name: oppositeFieldName } = resolveNameCasing(options.fieldCasing, `${lowerCaseFirst(sourceModel.name)}_${firstColumn}To${relation.references.table}_${relation.references.columns[0]}`));
|
|
767
|
+
}
|
|
718
768
|
const targetFieldFactory = new DataFieldFactory().setContainer(targetModel).setName(oppositeFieldName).setType((tb) => tb.setOptional(relation.references.type === "one").setArray(relation.references.type === "many").setReference(sourceModel));
|
|
719
769
|
if (includeRelationName) targetFieldFactory.addAttribute((ab) => ab.setDecl(relationAttribute).addArg((ab2) => ab2.StringLiteral.setValue(relationName)));
|
|
720
770
|
targetModel.fields.push(targetFieldFactory.node);
|
|
721
771
|
}
|
|
722
772
|
__name(syncRelation, "syncRelation");
|
|
773
|
+
function consolidateEnums({ newModel, oldModel }) {
|
|
774
|
+
const newEnums = newModel.declarations.filter((d) => isEnum(d));
|
|
775
|
+
const newDataModels = newModel.declarations.filter((d) => d.$type === "DataModel");
|
|
776
|
+
const oldDataModels = oldModel.declarations.filter((d) => d.$type === "DataModel");
|
|
777
|
+
const enumMapping = /* @__PURE__ */ new Map();
|
|
778
|
+
for (const newEnum of newEnums) {
|
|
779
|
+
for (const newDM of newDataModels) {
|
|
780
|
+
for (const field of newDM.fields) {
|
|
781
|
+
if (field.$type !== "DataField" || field.type.reference?.ref !== newEnum) continue;
|
|
782
|
+
const oldDM = oldDataModels.find((d) => getDbName(d) === getDbName(newDM));
|
|
783
|
+
if (!oldDM) continue;
|
|
784
|
+
const oldField = oldDM.fields.find((f) => getDbName(f) === getDbName(field));
|
|
785
|
+
if (!oldField || oldField.$type !== "DataField" || !oldField.type.reference?.ref) continue;
|
|
786
|
+
const oldEnum = oldField.type.reference.ref;
|
|
787
|
+
if (!isEnum(oldEnum)) continue;
|
|
788
|
+
enumMapping.set(newEnum, oldEnum);
|
|
789
|
+
break;
|
|
790
|
+
}
|
|
791
|
+
if (enumMapping.has(newEnum)) break;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
const reverseMapping = /* @__PURE__ */ new Map();
|
|
795
|
+
for (const [newEnum, oldEnum] of enumMapping) {
|
|
796
|
+
if (!reverseMapping.has(oldEnum)) {
|
|
797
|
+
reverseMapping.set(oldEnum, []);
|
|
798
|
+
}
|
|
799
|
+
reverseMapping.get(oldEnum).push(newEnum);
|
|
800
|
+
}
|
|
801
|
+
for (const [oldEnum, newEnumsGroup] of reverseMapping) {
|
|
802
|
+
const keepEnum = newEnumsGroup[0];
|
|
803
|
+
if (newEnumsGroup.length === 1 && keepEnum.name === oldEnum.name) continue;
|
|
804
|
+
const oldValues = new Set(oldEnum.fields.map((f) => getDbName(f)));
|
|
805
|
+
const allMatch = newEnumsGroup.every((ne) => {
|
|
806
|
+
const newValues = new Set(ne.fields.map((f) => getDbName(f)));
|
|
807
|
+
return oldValues.size === newValues.size && [
|
|
808
|
+
...oldValues
|
|
809
|
+
].every((v) => newValues.has(v));
|
|
810
|
+
});
|
|
811
|
+
if (!allMatch) continue;
|
|
812
|
+
keepEnum.name = oldEnum.name;
|
|
813
|
+
keepEnum.attributes = oldEnum.attributes.map((attr) => {
|
|
814
|
+
const copy = {
|
|
815
|
+
...attr,
|
|
816
|
+
$container: keepEnum
|
|
817
|
+
};
|
|
818
|
+
return copy;
|
|
819
|
+
});
|
|
820
|
+
for (let i = 1; i < newEnumsGroup.length; i++) {
|
|
821
|
+
const idx = newModel.declarations.indexOf(newEnumsGroup[i]);
|
|
822
|
+
if (idx >= 0) {
|
|
823
|
+
newModel.declarations.splice(idx, 1);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
for (const newDM of newDataModels) {
|
|
827
|
+
for (const field of newDM.fields) {
|
|
828
|
+
if (field.$type !== "DataField") continue;
|
|
829
|
+
const ref = field.type.reference?.ref;
|
|
830
|
+
if (ref && newEnumsGroup.includes(ref)) {
|
|
831
|
+
field.type.reference = {
|
|
832
|
+
ref: keepEnum,
|
|
833
|
+
$refText: keepEnum.name
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
console.log(colors3.gray(`Consolidated enum${newEnumsGroup.length > 1 ? "s" : ""} ${newEnumsGroup.map((e) => e.name).join(", ")} \u2192 ${oldEnum.name}`));
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
__name(consolidateEnums, "consolidateEnums");
|
|
723
842
|
|
|
724
843
|
// src/actions/pull/provider/mysql.ts
|
|
725
844
|
import { DataFieldAttributeFactory as DataFieldAttributeFactory2 } from "@zenstackhq/language/factory";
|
|
@@ -977,6 +1096,10 @@ var mysql = {
|
|
|
977
1096
|
return (ab) => ab.InvocationExpr.setFunction(getFunctionRef("uuid", services));
|
|
978
1097
|
}
|
|
979
1098
|
return (ab) => ab.StringLiteral.setValue(val);
|
|
1099
|
+
case "Json":
|
|
1100
|
+
return (ab) => ab.StringLiteral.setValue(val);
|
|
1101
|
+
case "Bytes":
|
|
1102
|
+
return (ab) => ab.StringLiteral.setValue(val);
|
|
980
1103
|
}
|
|
981
1104
|
if (val.includes("(") && val.includes(")")) {
|
|
982
1105
|
return (ab) => ab.InvocationExpr.setFunction(getFunctionRef("dbgenerated", services)).addArg((a) => a.setValue((v) => v.StringLiteral.setValue(val)));
|
|
@@ -1575,6 +1698,26 @@ var postgresql = {
|
|
|
1575
1698
|
return (ab) => ab.StringLiteral.setValue(val.slice(1, -1).replace(/''/g, "'"));
|
|
1576
1699
|
}
|
|
1577
1700
|
return (ab) => ab.StringLiteral.setValue(val);
|
|
1701
|
+
case "Json":
|
|
1702
|
+
if (val.includes("::")) {
|
|
1703
|
+
return typeCastingConvert({
|
|
1704
|
+
defaultValue,
|
|
1705
|
+
enums,
|
|
1706
|
+
val,
|
|
1707
|
+
services
|
|
1708
|
+
});
|
|
1709
|
+
}
|
|
1710
|
+
return (ab) => ab.StringLiteral.setValue(val);
|
|
1711
|
+
case "Bytes":
|
|
1712
|
+
if (val.includes("::")) {
|
|
1713
|
+
return typeCastingConvert({
|
|
1714
|
+
defaultValue,
|
|
1715
|
+
enums,
|
|
1716
|
+
val,
|
|
1717
|
+
services
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1720
|
+
return (ab) => ab.StringLiteral.setValue(val);
|
|
1578
1721
|
}
|
|
1579
1722
|
if (val.includes("(") && val.includes(")")) {
|
|
1580
1723
|
return (ab) => ab.InvocationExpr.setFunction(getFunctionRef("dbgenerated", services)).addArg((a) => a.setValue((v) => v.StringLiteral.setValue(val)));
|
|
@@ -2210,6 +2353,10 @@ var sqlite = {
|
|
|
2210
2353
|
return (ab) => ab.StringLiteral.setValue(strippedName);
|
|
2211
2354
|
}
|
|
2212
2355
|
return (ab) => ab.StringLiteral.setValue(val);
|
|
2356
|
+
case "Json":
|
|
2357
|
+
return (ab) => ab.StringLiteral.setValue(val);
|
|
2358
|
+
case "Bytes":
|
|
2359
|
+
return (ab) => ab.StringLiteral.setValue(val);
|
|
2213
2360
|
}
|
|
2214
2361
|
console.warn(`Unsupported default value type: "${defaultValue}" for field type "${fieldType}". Skipping default value.`);
|
|
2215
2362
|
return null;
|
|
@@ -2385,6 +2532,10 @@ async function runPull(options) {
|
|
|
2385
2532
|
similarRelations
|
|
2386
2533
|
});
|
|
2387
2534
|
}
|
|
2535
|
+
consolidateEnums({
|
|
2536
|
+
newModel,
|
|
2537
|
+
oldModel: model
|
|
2538
|
+
});
|
|
2388
2539
|
console.log(colors4.blue("Schema synced"));
|
|
2389
2540
|
const baseDir = path2.dirname(path2.resolve(schemaFile));
|
|
2390
2541
|
const baseDirUrlPath = new URL(`file://${baseDir}`).pathname;
|
|
@@ -2560,23 +2711,13 @@ async function runPull(options) {
|
|
|
2560
2711
|
}
|
|
2561
2712
|
return;
|
|
2562
2713
|
}
|
|
2563
|
-
originalField.attributes.filter((attr) => !f.attributes.find((d) => d.decl.$refText === attr.decl.$refText) &&
|
|
2564
|
-
"@map",
|
|
2565
|
-
"@@map",
|
|
2566
|
-
"@default",
|
|
2567
|
-
"@updatedAt"
|
|
2568
|
-
].includes(attr.decl.$refText)).forEach((attr) => {
|
|
2714
|
+
originalField.attributes.filter((attr) => !f.attributes.find((d) => d.decl.$refText === attr.decl.$refText) && isDatabaseManagedAttribute(attr.decl.$refText)).forEach((attr) => {
|
|
2569
2715
|
const field = attr.$container;
|
|
2570
2716
|
const index = field.attributes.findIndex((d) => d === attr);
|
|
2571
2717
|
field.attributes.splice(index, 1);
|
|
2572
2718
|
getModelChanges(originalDataModel.name).deletedAttributes.push(colors4.yellow(`- ${attr.decl.$refText} from field: ${originalDataModel.name}.${field.name}`));
|
|
2573
2719
|
});
|
|
2574
|
-
f.attributes.filter((attr) => !originalField.attributes.find((d) => d.decl.$refText === attr.decl.$refText) &&
|
|
2575
|
-
"@map",
|
|
2576
|
-
"@@map",
|
|
2577
|
-
"@default",
|
|
2578
|
-
"@updatedAt"
|
|
2579
|
-
].includes(attr.decl.$refText)).forEach((attr) => {
|
|
2720
|
+
f.attributes.filter((attr) => !originalField.attributes.find((d) => d.decl.$refText === attr.decl.$refText) && isDatabaseManagedAttribute(attr.decl.$refText)).forEach((attr) => {
|
|
2580
2721
|
const cloned = {
|
|
2581
2722
|
...attr,
|
|
2582
2723
|
$container: originalField
|
|
@@ -2674,8 +2815,8 @@ async function runPull(options) {
|
|
|
2674
2815
|
});
|
|
2675
2816
|
}
|
|
2676
2817
|
const generator = new ZModelCodeGenerator({
|
|
2677
|
-
quote: options.quote,
|
|
2678
|
-
indent: options.indent
|
|
2818
|
+
quote: options.quote ?? "single",
|
|
2819
|
+
indent: options.indent ?? 4
|
|
2679
2820
|
});
|
|
2680
2821
|
if (options.output) {
|
|
2681
2822
|
if (treatAsFile) {
|
|
@@ -2812,7 +2953,13 @@ var plugin2 = {
|
|
|
2812
2953
|
var typescript_default = plugin2;
|
|
2813
2954
|
|
|
2814
2955
|
// src/actions/generate.ts
|
|
2956
|
+
import semver from "semver";
|
|
2815
2957
|
async function run4(options) {
|
|
2958
|
+
try {
|
|
2959
|
+
await checkForMismatchedPackages(process.cwd());
|
|
2960
|
+
} catch (err) {
|
|
2961
|
+
console.warn(colors6.yellow(`Failed to check for mismatched ZenStack packages: ${err}`));
|
|
2962
|
+
}
|
|
2816
2963
|
const model = await pureGenerate(options, false);
|
|
2817
2964
|
if (options.watch) {
|
|
2818
2965
|
const logsEnabled = !options.silent;
|
|
@@ -3064,13 +3211,46 @@ async function loadPluginModule(provider, basePath) {
|
|
|
3064
3211
|
}
|
|
3065
3212
|
}
|
|
3066
3213
|
__name(loadPluginModule, "loadPluginModule");
|
|
3214
|
+
async function checkForMismatchedPackages(projectPath) {
|
|
3215
|
+
const packages = await getZenStackPackages(projectPath);
|
|
3216
|
+
if (!packages.length) {
|
|
3217
|
+
return false;
|
|
3218
|
+
}
|
|
3219
|
+
const versions = /* @__PURE__ */ new Set();
|
|
3220
|
+
for (const { version: version2 } of packages) {
|
|
3221
|
+
if (version2) {
|
|
3222
|
+
versions.add(version2);
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
if (versions.size > 1) {
|
|
3226
|
+
const message = "WARNING: Multiple versions of ZenStack packages detected.\n This will probably cause issues and break your types.";
|
|
3227
|
+
const slashes = "/".repeat(73);
|
|
3228
|
+
const latestVersion = semver.sort(Array.from(versions)).reverse()[0];
|
|
3229
|
+
console.warn(colors6.yellow(`${slashes}
|
|
3230
|
+
|
|
3231
|
+
${message}
|
|
3232
|
+
`));
|
|
3233
|
+
for (const { pkg, version: version2 } of packages) {
|
|
3234
|
+
if (!version2) continue;
|
|
3235
|
+
if (version2 === latestVersion) {
|
|
3236
|
+
console.log(` ${pkg.padEnd(32)} ${colors6.green(version2)}`);
|
|
3237
|
+
} else {
|
|
3238
|
+
console.log(` ${pkg.padEnd(32)} ${colors6.yellow(version2)}`);
|
|
3239
|
+
}
|
|
3240
|
+
}
|
|
3241
|
+
console.warn(`
|
|
3242
|
+
${colors6.yellow(slashes)}`);
|
|
3243
|
+
return true;
|
|
3244
|
+
}
|
|
3245
|
+
return false;
|
|
3246
|
+
}
|
|
3247
|
+
__name(checkForMismatchedPackages, "checkForMismatchedPackages");
|
|
3067
3248
|
|
|
3068
3249
|
// src/actions/info.ts
|
|
3069
3250
|
import colors7 from "colors";
|
|
3070
|
-
import path6 from "path";
|
|
3071
3251
|
async function run5(projectPath) {
|
|
3072
3252
|
const packages = await getZenStackPackages(projectPath);
|
|
3073
|
-
if (!packages) {
|
|
3253
|
+
if (!packages.length) {
|
|
3074
3254
|
console.error("Unable to locate package.json. Are you in a valid project directory?");
|
|
3075
3255
|
return;
|
|
3076
3256
|
}
|
|
@@ -3087,51 +3267,11 @@ async function run5(projectPath) {
|
|
|
3087
3267
|
}
|
|
3088
3268
|
}
|
|
3089
3269
|
__name(run5, "run");
|
|
3090
|
-
async function getZenStackPackages(projectPath) {
|
|
3091
|
-
let pkgJson;
|
|
3092
|
-
const resolvedPath = path6.resolve(projectPath);
|
|
3093
|
-
try {
|
|
3094
|
-
pkgJson = (await import(path6.join(resolvedPath, "package.json"), {
|
|
3095
|
-
with: {
|
|
3096
|
-
type: "json"
|
|
3097
|
-
}
|
|
3098
|
-
})).default;
|
|
3099
|
-
} catch {
|
|
3100
|
-
return [];
|
|
3101
|
-
}
|
|
3102
|
-
const packages = Array.from(new Set([
|
|
3103
|
-
...Object.keys(pkgJson.dependencies ?? {}),
|
|
3104
|
-
...Object.keys(pkgJson.devDependencies ?? {})
|
|
3105
|
-
].filter((p) => p.startsWith("@zenstackhq/") || p === "zenstack"))).sort();
|
|
3106
|
-
const result = await Promise.all(packages.map(async (pkg) => {
|
|
3107
|
-
try {
|
|
3108
|
-
const depPkgJson = (await import(`${pkg}/package.json`, {
|
|
3109
|
-
with: {
|
|
3110
|
-
type: "json"
|
|
3111
|
-
}
|
|
3112
|
-
})).default;
|
|
3113
|
-
if (depPkgJson.private) {
|
|
3114
|
-
return void 0;
|
|
3115
|
-
}
|
|
3116
|
-
return {
|
|
3117
|
-
pkg,
|
|
3118
|
-
version: depPkgJson.version
|
|
3119
|
-
};
|
|
3120
|
-
} catch {
|
|
3121
|
-
return {
|
|
3122
|
-
pkg,
|
|
3123
|
-
version: void 0
|
|
3124
|
-
};
|
|
3125
|
-
}
|
|
3126
|
-
}));
|
|
3127
|
-
return result.filter((p) => !!p);
|
|
3128
|
-
}
|
|
3129
|
-
__name(getZenStackPackages, "getZenStackPackages");
|
|
3130
3270
|
|
|
3131
3271
|
// src/actions/init.ts
|
|
3132
3272
|
import colors8 from "colors";
|
|
3133
3273
|
import fs7 from "fs";
|
|
3134
|
-
import
|
|
3274
|
+
import path6 from "path";
|
|
3135
3275
|
import ora3 from "ora";
|
|
3136
3276
|
import { detect, resolveCommand } from "package-manager-detector";
|
|
3137
3277
|
|
|
@@ -3206,11 +3346,11 @@ async function run6(projectPath) {
|
|
|
3206
3346
|
}
|
|
3207
3347
|
}
|
|
3208
3348
|
const generationFolder = "zenstack";
|
|
3209
|
-
if (!fs7.existsSync(
|
|
3210
|
-
fs7.mkdirSync(
|
|
3349
|
+
if (!fs7.existsSync(path6.join(projectPath, generationFolder))) {
|
|
3350
|
+
fs7.mkdirSync(path6.join(projectPath, generationFolder));
|
|
3211
3351
|
}
|
|
3212
|
-
if (!fs7.existsSync(
|
|
3213
|
-
fs7.writeFileSync(
|
|
3352
|
+
if (!fs7.existsSync(path6.join(projectPath, generationFolder, "schema.zmodel"))) {
|
|
3353
|
+
fs7.writeFileSync(path6.join(projectPath, generationFolder, "schema.zmodel"), STARTER_ZMODEL);
|
|
3214
3354
|
} else {
|
|
3215
3355
|
console.log(colors8.yellow("Schema file already exists. Skipping generation of sample."));
|
|
3216
3356
|
}
|
|
@@ -3222,7 +3362,7 @@ __name(run6, "run");
|
|
|
3222
3362
|
|
|
3223
3363
|
// src/actions/migrate.ts
|
|
3224
3364
|
import fs8 from "fs";
|
|
3225
|
-
import
|
|
3365
|
+
import path7 from "path";
|
|
3226
3366
|
|
|
3227
3367
|
// src/actions/seed.ts
|
|
3228
3368
|
import colors9 from "colors";
|
|
@@ -3255,7 +3395,7 @@ __name(run7, "run");
|
|
|
3255
3395
|
async function run8(command, options) {
|
|
3256
3396
|
const schemaFile = getSchemaFile(options.schema);
|
|
3257
3397
|
await requireDataSourceUrl(schemaFile);
|
|
3258
|
-
const prismaSchemaDir = options.migrations ?
|
|
3398
|
+
const prismaSchemaDir = options.migrations ? path7.dirname(options.migrations) : void 0;
|
|
3259
3399
|
const prismaSchemaFile = await generateTempPrismaSchema(schemaFile, prismaSchemaDir);
|
|
3260
3400
|
try {
|
|
3261
3401
|
switch (command) {
|
|
@@ -3380,21 +3520,21 @@ import cors from "cors";
|
|
|
3380
3520
|
import express from "express";
|
|
3381
3521
|
import { createJiti as createJiti2 } from "jiti";
|
|
3382
3522
|
import { createPool as createMysqlPool } from "mysql2";
|
|
3383
|
-
import
|
|
3523
|
+
import path9 from "path";
|
|
3384
3524
|
import { Pool as PgPool } from "pg";
|
|
3385
3525
|
|
|
3386
3526
|
// src/utils/version-utils.ts
|
|
3387
3527
|
import colors10 from "colors";
|
|
3388
3528
|
import fs9 from "fs";
|
|
3389
|
-
import
|
|
3529
|
+
import path8 from "path";
|
|
3390
3530
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3391
|
-
import
|
|
3531
|
+
import semver2 from "semver";
|
|
3392
3532
|
var CHECK_VERSION_TIMEOUT = 2e3;
|
|
3393
3533
|
var VERSION_CHECK_TAG = "next";
|
|
3394
3534
|
function getVersion() {
|
|
3395
3535
|
try {
|
|
3396
|
-
const _dirname = typeof __dirname !== "undefined" ? __dirname :
|
|
3397
|
-
return JSON.parse(fs9.readFileSync(
|
|
3536
|
+
const _dirname = typeof __dirname !== "undefined" ? __dirname : path8.dirname(fileURLToPath2(import.meta.url));
|
|
3537
|
+
return JSON.parse(fs9.readFileSync(path8.join(_dirname, "../package.json"), "utf8")).version;
|
|
3398
3538
|
} catch {
|
|
3399
3539
|
return void 0;
|
|
3400
3540
|
}
|
|
@@ -3408,7 +3548,7 @@ async function checkNewVersion() {
|
|
|
3408
3548
|
} catch {
|
|
3409
3549
|
return;
|
|
3410
3550
|
}
|
|
3411
|
-
if (latestVersion && currVersion &&
|
|
3551
|
+
if (latestVersion && currVersion && semver2.gt(latestVersion, currVersion)) {
|
|
3412
3552
|
console.log(`A newer version ${colors10.cyan(latestVersion)} is available.`);
|
|
3413
3553
|
}
|
|
3414
3554
|
}
|
|
@@ -3423,7 +3563,7 @@ async function getLatestVersion() {
|
|
|
3423
3563
|
if (fetchResult.ok) {
|
|
3424
3564
|
const data = await fetchResult.json();
|
|
3425
3565
|
const latestVersion = data?.version;
|
|
3426
|
-
if (typeof latestVersion === "string" &&
|
|
3566
|
+
if (typeof latestVersion === "string" && semver2.valid(latestVersion)) {
|
|
3427
3567
|
return latestVersion;
|
|
3428
3568
|
}
|
|
3429
3569
|
}
|
|
@@ -3441,8 +3581,8 @@ async function run9(options) {
|
|
|
3441
3581
|
const schemaFile = getSchemaFile(options.schema);
|
|
3442
3582
|
console.log(colors11.gray(`Loading ZModel schema from: ${schemaFile}`));
|
|
3443
3583
|
let outputPath = getOutputPath(options, schemaFile);
|
|
3444
|
-
if (!
|
|
3445
|
-
outputPath =
|
|
3584
|
+
if (!path9.isAbsolute(outputPath)) {
|
|
3585
|
+
outputPath = path9.resolve(process.cwd(), outputPath);
|
|
3446
3586
|
}
|
|
3447
3587
|
const model = await loadSchemaDocument(schemaFile);
|
|
3448
3588
|
const dataSource = model.declarations.find(isDataSource2);
|
|
@@ -3457,7 +3597,7 @@ async function run9(options) {
|
|
|
3457
3597
|
const provider = getStringLiteral2(dataSource?.fields.find((f) => f.name === "provider")?.value);
|
|
3458
3598
|
const dialect = createDialect(provider, databaseUrl, outputPath);
|
|
3459
3599
|
const jiti = createJiti2(import.meta.url);
|
|
3460
|
-
const schemaModule = await jiti.import(
|
|
3600
|
+
const schemaModule = await jiti.import(path9.join(outputPath, "schema"));
|
|
3461
3601
|
const schema = schemaModule.schema;
|
|
3462
3602
|
const omit = {};
|
|
3463
3603
|
for (const [modelName, modelDef] of Object.entries(schema.models)) {
|
|
@@ -3521,8 +3661,8 @@ function createDialect(provider, databaseUrl, outputPath) {
|
|
|
3521
3661
|
let resolvedUrl = databaseUrl.trim();
|
|
3522
3662
|
if (resolvedUrl.startsWith("file:")) {
|
|
3523
3663
|
const filePath = resolvedUrl.substring("file:".length);
|
|
3524
|
-
if (!
|
|
3525
|
-
resolvedUrl =
|
|
3664
|
+
if (!path9.isAbsolute(filePath)) {
|
|
3665
|
+
resolvedUrl = path9.join(outputPath, filePath);
|
|
3526
3666
|
}
|
|
3527
3667
|
}
|
|
3528
3668
|
console.log(colors11.gray(`Connecting to SQLite database at: ${resolvedUrl}`));
|
|
@@ -3883,7 +4023,7 @@ Documentation: https://zenstack.dev/docs`).showHelpAfterError().showSuggestionAf
|
|
|
3883
4023
|
migrateCommand.command("resolve").addOption(schemaOption).addOption(noVersionCheckOption).addOption(migrationsOption).addOption(new Option("--applied <migration>", "record a specific migration as applied")).addOption(new Option("--rolled-back <migration>", "record a specific migration as rolled back")).description("Resolve issues with database migrations in deployment databases").action((options) => migrateAction("resolve", options));
|
|
3884
4024
|
const dbCommand = program.command("db").description("Manage your database schema during development");
|
|
3885
4025
|
dbCommand.command("push").description("Push the state from your schema to your database").addOption(schemaOption).addOption(noVersionCheckOption).addOption(new Option("--accept-data-loss", "ignore data loss warnings")).addOption(new Option("--force-reset", "force a reset of the database before push")).action((options) => dbAction("push", options));
|
|
3886
|
-
dbCommand.command("pull").description("Introspect your database.").addOption(schemaOption).addOption(noVersionCheckOption).addOption(new Option("-o, --output <path>", "set custom output path for the introspected schema. If a file path is provided, all schemas are merged into that single file. If a directory path is provided, files are written to the directory and imports are kept.")).addOption(new Option("--model-casing <pascal|camel|snake|none>", "set the casing of generated models").default("pascal")).addOption(new Option("--field-casing <pascal|camel|snake|none>", "set the casing of generated fields").default("camel")).addOption(new Option("--always-map", "always add @map and @@map attributes to models and fields").default(false)).addOption(new Option("--quote <double|single>", "set the quote style of generated schema files").default("single")).addOption(new Option("--indent <number>", "set the indentation of the generated schema files").default(4)
|
|
4026
|
+
dbCommand.command("pull").description("Introspect your database.").addOption(schemaOption).addOption(noVersionCheckOption).addOption(new Option("-o, --output <path>", "set custom output path for the introspected schema. If a file path is provided, all schemas are merged into that single file. If a directory path is provided, files are written to the directory and imports are kept.")).addOption(new Option("--model-casing <pascal|camel|snake|none>", "set the casing of generated models").default("pascal")).addOption(new Option("--field-casing <pascal|camel|snake|none>", "set the casing of generated fields").default("camel")).addOption(new Option("--always-map", "always add @map and @@map attributes to models and fields").default(false)).addOption(new Option("--quote <double|single>", "set the quote style of generated schema files").default("single")).addOption(new Option("--indent <number>", "set the indentation of the generated schema files").default(4)).action((options) => dbAction("pull", options));
|
|
3887
4027
|
dbCommand.command("seed").description("Seed the database").allowExcessArguments(true).addHelpText("after", `
|
|
3888
4028
|
Seed script is configured under the "zenstack.seed" field in package.json.
|
|
3889
4029
|
E.g.:
|