Skip to content

Commit c25890d

Browse files
committed
feat: implement initial diff update
1 parent 08a67da commit c25890d

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,4 +1,4 @@
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';
@@ -11,7 +11,7 @@ import {
1111
} from './action-utils';
1212
import { syncEnums, syncRelation, syncTable, type Relation } from './pull';
1313
import { providers } from './pull/provider';
14-
import { getDatasource } from './pull/utils';
14+
import { getDatasource, getDbName } from './pull/utils';
1515
import { config } from '@dotenvx/dotenvx';
1616

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

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

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

123-
const zmodelSchema = generator.generate(newModel);
191+
if (options.out) {
192+
const zmodelSchema = generator.generate(newModel);
124193

125-
console.log(options.out ? `Writing to ${options.out}` : schemaFile);
194+
console.log(`Writing to ${options.out}`);
126195

127-
const outPath = options.out ? path.resolve(options.out) : schemaFile;
128-
console.log(outPath);
196+
const outPath = options.out ? path.resolve(options.out) : schemaFile;
129197

130-
fs.writeFileSync(outPath, zmodelSchema);
198+
fs.writeFileSync(outPath, zmodelSchema);
199+
} else {
200+
docs.forEach(({ uri, parseResult: { value: model } }) => {
201+
const zmodelSchema = generator.generate(model);
202+
console.log(`Writing to ${uri.path}`);
203+
fs.writeFileSync(uri.fsPath, zmodelSchema);
204+
});
205+
}
131206
} catch (error) {
132207
console.log(error);
133208
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)