Skip to content

Commit df8371d

Browse files
committed
fix: catch up with feature updates
- improve code styling - enable schema support for db pull
1 parent 018b616 commit df8371d

File tree

8 files changed

+74
-54
lines changed

8 files changed

+74
-54
lines changed

packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"dependencies": {
3232
"@dotenvx/dotenvx": "^1.51.0",
3333
"@zenstackhq/common-helpers": "workspace:*",
34+
"@zenstackhq/schema": "workspace:*",
3435
"@zenstackhq/language": "workspace:*",
3536
"@zenstackhq/sdk": "workspace:*",
3637
"prisma": "catalog:",

packages/cli/src/actions/action-utils.ts

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { loadDocument } from '@zenstackhq/language';
2-
import { isDataSource } from '@zenstackhq/language/ast';
1+
import { type ZModelServices, loadDocument } from '@zenstackhq/language';
2+
import { type Model, isDataSource } from '@zenstackhq/language/ast';
33
import { PrismaSchemaGenerator } from '@zenstackhq/sdk';
44
import colors from 'colors';
55
import fs from 'node:fs';
@@ -41,22 +41,22 @@ export function getSchemaFile(file?: string) {
4141
}
4242
}
4343

44-
export async function loadSchemaDocument(schemaFile: string) {
45-
const loadResult = await loadDocument(schemaFile);
46-
if (!loadResult.success) {
47-
loadResult.errors.forEach((err) => {
48-
console.error(colors.red(err));
49-
});
50-
throw new CliError('Schema contains errors. See above for details.');
51-
}
52-
loadResult.warnings.forEach((warn) => {
53-
console.warn(colors.yellow(warn));
54-
});
55-
return loadResult.model;
56-
}
44+
export async function loadSchemaDocument(
45+
schemaFile: string,
46+
opts?: { keepImports?: boolean; returnServices?: false },
47+
): Promise<Model>;
48+
export async function loadSchemaDocument(
49+
schemaFile: string,
50+
opts: { returnServices: true; keepImports?: boolean },
51+
): Promise<{ model: Model; services: ZModelServices }>;
52+
export async function loadSchemaDocument(
53+
schemaFile: string,
54+
opts: { returnServices?: boolean; keepImports?: boolean } = {},
55+
) {
56+
const returnServices = opts.returnServices || false;
57+
const keepImports = opts.keepImports || false;
5758

58-
export async function loadSchemaDocumentWithServices(schemaFile: string) {
59-
const loadResult = await loadDocument(schemaFile, [], true);
59+
const loadResult = await loadDocument(schemaFile, [], keepImports);
6060
if (!loadResult.success) {
6161
loadResult.errors.forEach((err) => {
6262
console.error(colors.red(err));
@@ -66,7 +66,10 @@ export async function loadSchemaDocumentWithServices(schemaFile: string) {
6666
loadResult.warnings.forEach((warn) => {
6767
console.warn(colors.yellow(warn));
6868
});
69-
return { services: loadResult.services, model: loadResult.model };
69+
70+
if (returnServices) return { model: loadResult.model, services: loadResult.services };
71+
72+
return loadResult.model;
7073
}
7174

7275
export function handleSubProcessError(err: unknown) {

packages/cli/src/actions/db.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import { Model, Enum, DataModel, DataField } from '@zenstackhq/language/ast';
2-
import { ZModelCodeGenerator } from '@zenstackhq/sdk';
1+
import { config } from '@dotenvx/dotenvx';
2+
import { ZModelCodeGenerator } from '@zenstackhq/language';
3+
import { type DataField, DataModel, Enum, type Model } from '@zenstackhq/language/ast';
34
import fs from 'node:fs';
45
import path from 'node:path';
56
import { execPrisma } from '../utils/exec-utils';
67
import { generateTempPrismaSchema, getSchemaFile, handleSubProcessError, requireDataSourceUrl, loadSchemaDocumentWithServices } from './action-utils';
78
import { syncEnums, syncRelation, syncTable, type Relation } from './pull';
89
import { providers } from './pull/provider';
910
import { getDatasource, getDbName, getRelationFkName } from './pull/utils';
10-
import { config } from '@dotenvx/dotenvx';
1111

1212
type PushOptions = {
1313
schema?: string;
@@ -17,7 +17,6 @@ type PushOptions = {
1717

1818
export type PullOptions = {
1919
schema?: string;
20-
excludeSchemas?: string[];
2120
out?: string;
2221
modelCasing: 'pascal' | 'camel' | 'snake' | 'kebab' | 'none';
2322
fieldCasing: 'pascal' | 'camel' | 'snake' | 'kebab' | 'none';
@@ -74,7 +73,7 @@ async function runPush(options: PushOptions) {
7473
async function runPull(options: PullOptions) {
7574
try {
7675
const schemaFile = getSchemaFile(options.schema);
77-
const { model, services } = await loadSchemaDocumentWithServices(schemaFile);
76+
const { model, services } = await loadSchemaDocument(schemaFile, { returnServices: true });
7877
config();
7978
const SUPPORTED_PROVIDERS = ['sqlite', 'postgresql'];
8079
const datasource = getDatasource(model);
@@ -94,8 +93,8 @@ async function runPull(options: PullOptions) {
9493
}
9594

9695
const { enums: allEnums, tables: allTables } = await provider.introspect(datasource.url);
97-
const enums = allEnums.filter((e) => !options.excludeSchemas?.includes(e.schema_name));
98-
const tables = allTables.filter((t) => !options.excludeSchemas?.includes(t.schema));
96+
const enums = allEnums.filter((e) => datasource.schemas.includes(e.schema_name));
97+
const tables = allTables.filter((t) => datasource.schemas.includes(t.schema));
9998

10099
const newModel: Model = {
101100
$type: 'Model',
@@ -106,11 +105,18 @@ async function runPull(options: PullOptions) {
106105
imports: [],
107106
};
108107

109-
syncEnums({ dbEnums: enums, model: newModel, services, options });
108+
syncEnums({ dbEnums: enums, model: newModel, services, options, defaultSchema: datasource.defaultSchema });
110109

111110
const resolvedRelations: Relation[] = [];
112111
for (const table of tables) {
113-
const relations = syncTable({ table, model: newModel, provider, services, options });
112+
const relations = syncTable({
113+
table,
114+
model: newModel,
115+
provider,
116+
services,
117+
options,
118+
defaultSchema: datasource.defaultSchema,
119+
});
114120
resolvedRelations.push(...relations);
115121
}
116122

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

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ZModelServices } from '@zenstackhq/language';
22
import {
3-
Attribute,
43
isEnum,
4+
type Attribute,
55
type DataField,
66
type DataModel,
77
type Enum,
@@ -23,11 +23,13 @@ export function syncEnums({
2323
model,
2424
options,
2525
services,
26+
defaultSchema,
2627
}: {
2728
dbEnums: IntrospectedEnum[];
2829
model: Model;
2930
services: ZModelServices;
3031
options: PullOptions;
32+
defaultSchema: string;
3133
}) {
3234
for (const dbEnum of dbEnums) {
3335
const { modified, name } = resolveNameCasing(options.modelCasing, dbEnum.enum_type);
@@ -55,18 +57,12 @@ export function syncEnums({
5557
});
5658
});
5759

58-
try {
59-
if (dbEnum.schema_name && dbEnum.schema_name !== '' && dbEnum.schema_name !== 'public') {
60-
factory.addAttribute((b) =>
61-
b
62-
.setDecl(getAttributeRef('@@schema', services))
63-
.addArg((a) => a.StringLiteral.setValue(dbEnum.schema_name)),
64-
);
65-
}
66-
} catch (error: any) {
67-
if (error?.message !== `Declaration not found: @@schema`) throw error;
68-
//Waiting to support multi-schema
69-
//TODO: remove catch after multi-schema support is implemented
60+
if (dbEnum.schema_name && dbEnum.schema_name !== '' && dbEnum.schema_name !== defaultSchema) {
61+
factory.addAttribute((b) =>
62+
b
63+
.setDecl(getAttributeRef('@@schema', services))
64+
.addArg((a) => a.StringLiteral.setValue(dbEnum.schema_name)),
65+
);
7066
}
7167

7268
model.declarations.push(factory.get({ $container: model }));
@@ -143,12 +139,14 @@ export function syncTable({
143139
table,
144140
services,
145141
options,
142+
defaultSchema,
146143
}: {
147144
table: IntrospectedTable;
148145
model: Model;
149146
provider: IntrospectionProvider;
150147
services: ZModelServices;
151148
options: PullOptions;
149+
defaultSchema: string;
152150
}) {
153151
const idAttribute = getAttributeRef('@id', services);
154152
const modelIdAttribute = getAttributeRef('@@id', services);
@@ -372,16 +370,10 @@ export function syncTable({
372370
);
373371
});
374372

375-
try {
376-
if (table.schema && table.schema !== '' && table.schema !== 'public') {
377-
modelFactory.addAttribute((b) =>
378-
b.setDecl(getAttributeRef('@@schema', services)).addArg((a) => a.StringLiteral.setValue(table.schema)),
379-
);
380-
}
381-
} catch (error: any) {
382-
if (error?.message !== `Declaration not found: @@schema`) throw error;
383-
//Waiting to support multi-schema
384-
//TODO: remove catch after multi-schema support is implemented
373+
if (table.schema && table.schema !== '' && table.schema !== defaultSchema) {
374+
modelFactory.addAttribute((b) =>
375+
b.setDecl(getAttributeRef('@@schema', services)).addArg((a) => a.StringLiteral.setValue(table.schema)),
376+
);
385377
}
386378

387379
model.declarations.push(modelFactory.node);
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import type { DataSourceProviderType } from '@zenstackhq/schema';
12
export * from './provider';
23

34
import { postgresql } from './postgresql';
5+
import type { IntrospectionProvider } from './provider';
46
import { sqlite } from './sqlite';
57

6-
export const providers = {
8+
export const providers: Record<DataSourceProviderType, IntrospectionProvider> = {
79
postgresql,
810
sqlite,
911
};

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import {
1111
type Model,
1212
type StringLiteral,
1313
} from '@zenstackhq/language/ast';
14-
import { getStringLiteral } from '@zenstackhq/language/utils';
15-
import type { DataSourceProviderType } from '@zenstackhq/sdk/schema';
14+
import { getLiteralArray, getStringLiteral } from '@zenstackhq/language/utils';
15+
import type { DataSourceProviderType } from '@zenstackhq/schema';
1616
import type { Reference } from 'langium';
1717

1818
export function getAttribute(model: Model, attrName: string) {
@@ -53,12 +53,26 @@ export function getDatasource(model: Model) {
5353
throw new Error('The url field must be a string literal or an env().');
5454
}
5555

56+
const defaultSchemaField = datasource.fields.find((f) => f.name === 'defaultSchema');
57+
const defaultSchema = (defaultSchemaField && getStringLiteral(defaultSchemaField.value)) || 'public';
58+
59+
const schemasField = datasource.fields.find((f) => f.name === 'schemas');
60+
const schemas =
61+
(schemasField &&
62+
getLiteralArray(schemasField.value)
63+
?.map(getStringLiteral)
64+
.filter((s) => s !== undefined)) ||
65+
[];
66+
5667
return {
5768
name: datasource.name,
5869
provider: getStringLiteral(
5970
datasource.fields.find((f) => f.name === 'provider')?.value,
6071
) as DataSourceProviderType,
6172
url,
73+
defaultSchema,
74+
schemas,
75+
allSchemas: [defaultSchema, ...schemas],
6276
};
6377
}
6478

packages/cli/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,6 @@ function createProgram() {
142142
.description('Introspect your database.')
143143
.addOption(schemaOption)
144144
.addOption(noVersionCheckOption)
145-
.addOption(new Option('-e, --exclude-schemas <schemas...>', 'exclude specific schemas from introspection'))
146145
.addOption(new Option('-o, --out <path>', 'add custom output path for the introspected schema'))
147146
.addOption(
148147
new Option('--model-casing <pascal|camel|snake|kebab>', 'set the casing of generated models').default(

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)