Skip to content

Commit d52f862

Browse files
committed
feat: implement initial diff update
1 parent c81fe44 commit d52f862

File tree

2 files changed

+104
-19
lines changed

2 files changed

+104
-19
lines changed

packages/cli/src/actions/db.ts

Lines changed: 84 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import type { Model } from '@zenstackhq/language/ast';
1+
import { Model, Enum, DataModel } from '@zenstackhq/language/ast';
22
import { ZModelCodeGenerator } from '@zenstackhq/sdk';
33
import fs from 'node:fs';
44
import path from 'node:path';
55
import { execPrisma } from '../utils/exec-utils';
66
import { generateTempPrismaSchema, getSchemaFile, handleSubProcessError, requireDataSourceUrl, loadSchemaDocumentWithServices } from './action-utils';
77
import { syncEnums, syncRelation, syncTable, type Relation } from './pull';
88
import { providers } from './pull/provider';
9-
import { getDatasource } from './pull/utils';
9+
import { getDatasource, getDbName } from './pull/utils';
1010
import { config } from '@dotenvx/dotenvx';
1111

1212
type PushOptions = {
@@ -115,18 +115,93 @@ async function runPull(options: PullOptions) {
115115
syncRelation({ model: newModel, relation, services, options });
116116
}
117117

118-
//TODO: diff models and apply changes only
118+
const cwd = new URL(`file://${process.cwd()}`).pathname;
119+
const docs = services.shared.workspace.LangiumDocuments.all
120+
.filter(({ uri }) => uri.path.toLowerCase().startsWith(cwd.toLowerCase()))
121+
.toArray();
122+
const docsSet = new Set(docs.map((d) => d.uri.toString()));
123+
console.log(docsSet);
124+
newModel.declarations
125+
.filter((d) => [DataModel, Enum].includes(d.$type))
126+
.forEach((_declaration) => {
127+
const declaration = _declaration as DataModel | Enum;
128+
const declarations = services.shared.workspace.IndexManager.allElements(declaration.$type, docsSet);
129+
const originalModel = declarations.find((d) => getDbName(d.node as any) === getDbName(declaration))
130+
?.node as DataModel | Enum | undefined;
131+
if (!originalModel) {
132+
model.declarations.push(declaration);
133+
(declaration as any).$container = model;
134+
return;
135+
}
136+
137+
declaration.fields.forEach((f) => {
138+
const originalField = originalModel.fields.find((d) => getDbName(d) === getDbName(f));
139+
140+
if (!originalField) {
141+
console.log(`Added field ${f.name} to ${originalModel.name}`);
142+
(f as any).$container = originalModel;
143+
originalModel.fields.push(f as any);
144+
return;
145+
}
146+
//TODO: update field
147+
});
148+
originalModel.fields
149+
.filter((f) => !declaration.fields.find((d) => getDbName(d) === getDbName(f)))
150+
.forEach((f) => {
151+
const model = f.$container;
152+
const index = model.fields.findIndex((d) => d === f);
153+
model.fields.splice(index, 1);
154+
console.log(`Delete field ${f.name}`);
155+
});
156+
});
157+
158+
services.shared.workspace.IndexManager.allElements('DataModel', docsSet)
159+
.filter(
160+
(declaration) =>
161+
!newModel.declarations.find((d) => getDbName(d) === getDbName(declaration.node as any)),
162+
)
163+
.forEach((decl) => {
164+
const model = decl.node!.$container as Model;
165+
const index = model.declarations.findIndex((d) => d === decl.node);
166+
model.declarations.splice(index, 1);
167+
console.log(`Delete model ${decl.name}`);
168+
});
169+
services.shared.workspace.IndexManager.allElements('Enum', docsSet)
170+
.filter(
171+
(declaration) =>
172+
!newModel.declarations.find((d) => getDbName(d) === getDbName(declaration.node as any)),
173+
)
174+
.forEach((decl) => {
175+
const model = decl.node!.$container as Model;
176+
const index = model.declarations.findIndex((d) => d === decl.node);
177+
model.declarations.splice(index, 1);
178+
console.log(`Delete enum ${decl.name}`);
179+
});
180+
181+
if (options.out && !fs.lstatSync(options.out).isFile()) {
182+
throw new Error(`Output path ${options.out} is not a file`);
183+
}
119184

120-
const generator = new ZModelCodeGenerator();
185+
const generator = new ZModelCodeGenerator({
186+
//TODO: make configurable
187+
quote: 'double',
188+
});
121189

122-
const zmodelSchema = generator.generate(newModel);
190+
if (options.out) {
191+
const zmodelSchema = generator.generate(newModel);
123192

124-
console.log(options.out ? `Writing to ${options.out}` : schemaFile);
193+
console.log(`Writing to ${options.out}`);
125194

126-
const outPath = options.out ? path.resolve(options.out) : schemaFile;
127-
console.log(outPath);
195+
const outPath = options.out ? path.resolve(options.out) : schemaFile;
128196

129-
fs.writeFileSync(outPath, zmodelSchema);
197+
fs.writeFileSync(outPath, zmodelSchema);
198+
} else {
199+
docs.forEach(({ uri, parseResult: { value: model } }) => {
200+
const zmodelSchema = generator.generate(model);
201+
console.log(`Writing to ${uri.path}`);
202+
fs.writeFileSync(uri.fsPath, zmodelSchema);
203+
});
204+
}
130205
} catch (error) {
131206
console.log(error);
132207
throw error;

packages/cli/src/actions/pull/index.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,17 @@ export function syncEnums({
4242
});
4343
});
4444

45-
if (dbEnum.schema_name && dbEnum.schema_name != '' && dbEnum.schema_name !== 'public') {
46-
factory.addAttribute((b) =>
47-
b
48-
.setDecl(getAttributeRef('@@schema', services))
49-
.addArg((a) => a.StringLiteral.setValue(dbEnum.schema_name)),
50-
);
45+
try {
46+
if (dbEnum.schema_name && dbEnum.schema_name !== '' && dbEnum.schema_name !== 'public') {
47+
factory.addAttribute((b) =>
48+
b
49+
.setDecl(getAttributeRef('@@schema', services))
50+
.addArg((a) => a.StringLiteral.setValue(dbEnum.schema_name)),
51+
);
52+
}
53+
} catch (_error: unknown) {
54+
//Waiting to support multi-schema
55+
//TODO: remove catch after multi-schema support is implemented
5156
}
5257

5358
model.declarations.push(factory.get({ $container: model }));
@@ -325,10 +330,15 @@ export function syncTable({
325330
);
326331
});
327332

328-
if (table.schema && table.schema != '' && table.schema !== 'public') {
329-
modelFactory.addAttribute((b) =>
330-
b.setDecl(getAttributeRef('@@schema', services)).addArg((a) => a.StringLiteral.setValue(table.schema)),
331-
);
333+
try {
334+
if (table.schema && table.schema !== '' && table.schema !== 'public') {
335+
modelFactory.addAttribute((b) =>
336+
b.setDecl(getAttributeRef('@@schema', services)).addArg((a) => a.StringLiteral.setValue(table.schema)),
337+
);
338+
}
339+
} catch (_error: unknown) {
340+
//Waiting to support multi-schema
341+
//TODO: remove catch after multi-schema support is implemented
332342
}
333343

334344
model.declarations.push(modelFactory.node);

0 commit comments

Comments
 (0)