Skip to content

Commit 68ee9d2

Browse files
committed
fix: add sqlite e2e test and fix some bugs
1 parent df8371d commit 68ee9d2

File tree

12 files changed

+419
-281
lines changed

12 files changed

+419
-281
lines changed

packages/cli/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
"dependencies": {
3232
"@dotenvx/dotenvx": "^1.51.0",
3333
"@zenstackhq/common-helpers": "workspace:*",
34-
"@zenstackhq/schema": "workspace:*",
3534
"@zenstackhq/language": "workspace:*",
35+
"@zenstackhq/schema": "workspace:*",
3636
"@zenstackhq/sdk": "workspace:*",
3737
"prisma": "catalog:",
3838
"colors": "1.4.0",
@@ -43,7 +43,8 @@
4343
"ora": "^5.4.1",
4444
"package-manager-detector": "^1.3.0",
4545
"semver": "^7.7.2",
46-
"ts-pattern": "catalog:"
46+
"ts-pattern": "catalog:",
47+
"vscode-uri": "^3.1.0"
4748
},
4849
"devDependencies": {
4950
"@types/better-sqlite3": "catalog:",

packages/cli/src/actions/db.ts

Lines changed: 93 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@ async function runPull(options: PullOptions) {
7474
try {
7575
const schemaFile = getSchemaFile(options.schema);
7676
const { model, services } = await loadSchemaDocument(schemaFile, { returnServices: true });
77-
config();
77+
config({
78+
ignore: ['MISSING_ENV_FILE'],
79+
});
7880
const SUPPORTED_PROVIDERS = ['sqlite', 'postgresql'];
7981
const datasource = getDatasource(model);
80-
8182
if (!datasource) {
8283
throw new Error('No datasource found in the schema.');
8384
}
@@ -91,10 +92,14 @@ async function runPull(options: PullOptions) {
9192
if (!provider) {
9293
throw new Error(`No introspection provider found for: ${datasource.provider}`);
9394
}
94-
95+
console.log('Starging introspect the database...');
9596
const { enums: allEnums, tables: allTables } = await provider.introspect(datasource.url);
96-
const enums = allEnums.filter((e) => datasource.schemas.includes(e.schema_name));
97-
const tables = allTables.filter((t) => datasource.schemas.includes(t.schema));
97+
const enums = provider.isSupportedFeature('Schema')
98+
? allEnums.filter((e) => datasource.schemas.includes(e.schema_name))
99+
: allEnums;
100+
const tables = provider.isSupportedFeature('Schema')
101+
? allTables.filter((t) => datasource.schemas.includes(t.schema))
102+
: allTables;
98103

99104
const newModel: Model = {
100105
$type: 'Model',
@@ -104,8 +109,15 @@ async function runPull(options: PullOptions) {
104109
declarations: [...model.declarations.filter((d) => ['DataSource'].includes(d.$type))],
105110
imports: [],
106111
};
107-
108-
syncEnums({ dbEnums: enums, model: newModel, services, options, defaultSchema: datasource.defaultSchema });
112+
syncEnums({
113+
dbEnums: enums,
114+
model: newModel,
115+
services,
116+
options,
117+
defaultSchema: datasource.defaultSchema,
118+
oldModel: model,
119+
provider,
120+
});
109121

110122
const resolvedRelations: Relation[] = [];
111123
for (const table of tables) {
@@ -116,21 +128,23 @@ async function runPull(options: PullOptions) {
116128
services,
117129
options,
118130
defaultSchema: datasource.defaultSchema,
131+
oldModel: model,
119132
});
120133
resolvedRelations.push(...relations);
121134
}
122-
135+
// sync relation fields
123136
for (const relation of resolvedRelations) {
124137
const simmilarRelations = resolvedRelations.filter((rr) => {
125138
return (
126-
(rr.schema === relation.schema &&
139+
rr !== relation &&
140+
((rr.schema === relation.schema &&
127141
rr.table === relation.table &&
128142
rr.references.schema === relation.references.schema &&
129143
rr.references.table === relation.references.table) ||
130-
(rr.schema === relation.references.schema &&
131-
rr.column === relation.references.column &&
132-
rr.references.schema === relation.schema &&
133-
rr.references.table === relation.table)
144+
(rr.schema === relation.references.schema &&
145+
rr.column === relation.references.column &&
146+
rr.references.schema === relation.schema &&
147+
rr.references.table === relation.table))
134148
);
135149
}).length;
136150
const selfRelation =
@@ -151,6 +165,7 @@ async function runPull(options: PullOptions) {
151165
.toArray();
152166
const docsSet = new Set(docs.map((d) => d.uri.toString()));
153167

168+
//Delete models
154169
services.shared.workspace.IndexManager.allElements('DataModel', docsSet)
155170
.filter(
156171
(declaration) =>
@@ -162,32 +177,35 @@ async function runPull(options: PullOptions) {
162177
model.declarations.splice(index, 1);
163178
console.log(`Delete model ${decl.name}`);
164179
});
165-
services.shared.workspace.IndexManager.allElements('Enum', docsSet)
166-
.filter(
167-
(declaration) =>
168-
!newModel.declarations.find((d) => getDbName(d) === getDbName(declaration.node as any)),
169-
)
170-
.forEach((decl) => {
171-
const model = decl.node!.$container as Model;
172-
const index = model.declarations.findIndex((d) => d === decl.node);
173-
model.declarations.splice(index, 1);
174-
console.log(`Delete enum ${decl.name}`);
175-
});
176180

181+
// Delete Enums
182+
if (provider.isSupportedFeature('NativeEnum'))
183+
services.shared.workspace.IndexManager.allElements('Enum', docsSet)
184+
.filter(
185+
(declaration) =>
186+
!newModel.declarations.find((d) => getDbName(d) === getDbName(declaration.node as any)),
187+
)
188+
.forEach((decl) => {
189+
const model = decl.node!.$container as Model;
190+
const index = model.declarations.findIndex((d) => d === decl.node);
191+
model.declarations.splice(index, 1);
192+
console.log(`Delete enum ${decl.name}`);
193+
});
194+
//
177195
newModel.declarations
178196
.filter((d) => [DataModel, Enum].includes(d.$type))
179197
.forEach((_declaration) => {
180-
const declaration = _declaration as DataModel | Enum;
198+
const newDataModel = _declaration as DataModel | Enum;
181199
const declarations = services.shared.workspace.IndexManager.allElements(
182-
declaration.$type,
200+
newDataModel.$type,
183201
docsSet,
184202
).toArray();
185-
const originalModel = declarations.find((d) => getDbName(d.node as any) === getDbName(declaration))
203+
const originalDataModel = declarations.find((d) => getDbName(d.node as any) === getDbName(newDataModel))
186204
?.node as DataModel | Enum | undefined;
187-
if (!originalModel) {
188-
model.declarations.push(declaration);
189-
(declaration as any).$container = model;
190-
declaration.fields.forEach((f) => {
205+
if (!originalDataModel) {
206+
model.declarations.push(newDataModel);
207+
(newDataModel as any).$container = model;
208+
newDataModel.fields.forEach((f) => {
191209
if (f.$type === 'DataField' && f.type.reference?.ref) {
192210
const ref = declarations.find(
193211
(d) => getDbName(d.node as any) === getDbName(f.type.reference!.ref as any),
@@ -198,19 +216,33 @@ async function runPull(options: PullOptions) {
198216
return;
199217
}
200218

201-
declaration.fields.forEach((f) => {
202-
const originalField = originalModel.fields.find(
203-
(d) =>
219+
newDataModel.fields.forEach((f) => {
220+
const originalFields = originalDataModel.fields.filter((d) => {
221+
return (
204222
getDbName(d) === getDbName(f) ||
205223
(getRelationFkName(d as any) === getRelationFkName(f as any) &&
206224
!!getRelationFkName(d as any) &&
207-
!!getRelationFkName(f as any)),
208-
);
225+
!!getRelationFkName(f as any)) ||
226+
(f.$type === 'DataField' &&
227+
d.$type === 'DataField' &&
228+
f.type.reference?.ref &&
229+
d.type.reference?.ref &&
230+
getDbName(f.type.reference.ref) === getDbName(d.type.reference.ref))
231+
);
232+
});
209233

234+
if (originalFields.length > 1) {
235+
console.warn(
236+
`Found more original fields, need to tweak the search algorith. ${originalDataModel.name}->[${originalFields.map((of) => of.name).join(', ')}](${f.name})`,
237+
);
238+
return;
239+
}
240+
const originalField = originalFields.at(0);
241+
Object.freeze(originalField);
210242
if (!originalField) {
211-
//console.log(`Added field ${f.name} to ${originalModel.name}`);
212-
(f as any).$container = originalModel;
213-
originalModel.fields.push(f as any);
243+
console.log(`Added field ${f.name} to ${originalDataModel.name}`);
244+
(f as any).$container = originalDataModel;
245+
originalDataModel.fields.push(f as any);
214246
if (f.$type === 'DataField' && f.type.reference?.ref) {
215247
const ref = declarations.find(
216248
(d) => getDbName(d.node as any) === getDbName(f.type.reference!.ref as any),
@@ -222,66 +254,42 @@ async function runPull(options: PullOptions) {
222254
}
223255
return;
224256
}
225-
226-
if (originalField.$type === 'DataField') {
227-
const field = f as DataField;
228-
originalField.type = field.type;
229-
if (field.type.reference) {
230-
const ref = declarations.find(
231-
(d) => getDbName(d.node as any) === getDbName(field.type.reference!.ref as any),
232-
)?.node as DataModel | undefined;
233-
if (ref) {
234-
(field.type.reference.$refText as any) = ref.name;
235-
(field.type.reference.ref as any) = ref;
236-
}
237-
}
238-
239-
(originalField.type.$container as any) = originalField;
240-
}
241-
242-
f.attributes.forEach((attr) => {
243-
const originalAttribute = originalField.attributes.find(
244-
(d) => d.decl.$refText === attr.decl.$refText,
245-
);
246-
247-
if (!originalAttribute) {
248-
//console.log(`Added Attribute ${attr.decl.$refText} to ${f.name}`);
249-
(f as any).$container = originalField;
250-
originalField.attributes.push(attr as any);
251-
return;
252-
}
253-
254-
originalAttribute.args = attr.args;
255-
attr.args.forEach((a) => {
256-
(a.$container as any) = originalAttribute;
257-
});
258-
});
259-
257+
if (f.name === 'profiles') console.log(f.attributes.length);
260258
originalField.attributes
261-
.filter((attr) => !f.attributes.find((d) => d.decl.$refText === attr.decl.$refText))
259+
.filter(
260+
(attr) =>
261+
!f.attributes.find((d) => d.decl.$refText === attr.decl.$refText) &&
262+
!['@map', '@@map', '@default', '@updatedAt'].includes(attr.decl.$refText),
263+
)
262264
.forEach((attr) => {
263265
const field = attr.$container;
264266
const index = field.attributes.findIndex((d) => d === attr);
265267
field.attributes.splice(index, 1);
266-
//console.log(`Delete attribute from field:${field.name} ${attr.decl.$refText}`);
268+
console.log(`Delete attribute from field:${field.name} ${attr.decl.$refText}`);
267269
});
268270
});
269-
originalModel.fields
271+
originalDataModel.fields
270272
.filter(
271273
(f) =>
272-
!declaration.fields.find(
273-
(d) =>
274+
!newDataModel.fields.find((d) => {
275+
return (
274276
getDbName(d) === getDbName(f) ||
275277
(getRelationFkName(d as any) === getRelationFkName(f as any) &&
276278
!!getRelationFkName(d as any) &&
277-
!!getRelationFkName(f as any)),
278-
),
279+
!!getRelationFkName(f as any)) ||
280+
(f.$type === 'DataField' &&
281+
d.$type === 'DataField' &&
282+
f.type.reference?.ref &&
283+
d.type.reference?.ref &&
284+
getDbName(f.type.reference.ref) === getDbName(d.type.reference.ref))
285+
);
286+
}),
279287
)
280288
.forEach((f) => {
281-
const model = f.$container;
282-
const index = model.fields.findIndex((d) => d === f);
283-
model.fields.splice(index, 1);
284-
//console.log(`Delete field ${f.name}`);
289+
const _model = f.$container;
290+
const index = _model.fields.findIndex((d) => d === f);
291+
_model.fields.splice(index, 1);
292+
console.log(`Delete field ${f.name}`);
285293
});
286294
});
287295

0 commit comments

Comments
 (0)