@zenstackhq/cli 3.1.0 → 3.2.0
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 +88 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +89 -6
- package/dist/index.js.map +1 -1
- package/package.json +17 -9
- package/.turbo/turbo-build.log +0 -22
- package/eslint.config.js +0 -4
- package/scripts/post-build.ts +0 -20
- package/src/actions/action-utils.ts +0 -146
- package/src/actions/check.ts +0 -22
- package/src/actions/db.ts +0 -51
- package/src/actions/format.ts +0 -27
- package/src/actions/generate.ts +0 -226
- package/src/actions/index.ts +0 -10
- package/src/actions/info.ts +0 -71
- package/src/actions/init.ts +0 -61
- package/src/actions/migrate.ts +0 -149
- package/src/actions/seed.ts +0 -38
- package/src/actions/templates.ts +0 -58
- package/src/cli-error.ts +0 -4
- package/src/constants.ts +0 -5
- package/src/index.ts +0 -233
- package/src/plugins/index.ts +0 -2
- package/src/plugins/prisma.ts +0 -21
- package/src/plugins/typescript.ts +0 -40
- package/src/telemetry.ts +0 -139
- package/src/utils/exec-utils.ts +0 -61
- package/src/utils/is-ci.ts +0 -5
- package/src/utils/is-container.ts +0 -23
- package/src/utils/is-docker.ts +0 -31
- package/src/utils/is-wsl.ts +0 -18
- package/src/utils/machine-id-utils.ts +0 -76
- package/src/utils/version-utils.ts +0 -50
- package/test/check.test.ts +0 -101
- package/test/db.test.ts +0 -61
- package/test/format.test.ts +0 -33
- package/test/generate.test.ts +0 -76
- package/test/init.test.ts +0 -14
- package/test/migrate.test.ts +0 -72
- package/test/plugins/custom-plugin.test.ts +0 -50
- package/test/plugins/prisma-plugin.test.ts +0 -81
- package/test/ts-schema-gen.test.ts +0 -445
- package/test/utils.ts +0 -23
- package/tsconfig.json +0 -4
- package/tsup.config.ts +0 -13
- package/vitest.config.ts +0 -4
package/test/init.test.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import tmp from 'tmp';
|
|
4
|
-
import { describe, expect, it } from 'vitest';
|
|
5
|
-
import { runCli } from './utils';
|
|
6
|
-
|
|
7
|
-
// skipping due to timeout during CI
|
|
8
|
-
describe.skip('Cli init command tests', () => {
|
|
9
|
-
it('should create a new project', () => {
|
|
10
|
-
const { name: workDir } = tmp.dirSync({ unsafeCleanup: true });
|
|
11
|
-
runCli('init', workDir);
|
|
12
|
-
expect(fs.existsSync(path.join(workDir, 'zenstack/schema.zmodel'))).toBe(true);
|
|
13
|
-
});
|
|
14
|
-
});
|
package/test/migrate.test.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { describe, expect, it } from 'vitest';
|
|
4
|
-
import { createProject, runCli } from './utils';
|
|
5
|
-
|
|
6
|
-
const model = `
|
|
7
|
-
model User {
|
|
8
|
-
id String @id @default(cuid())
|
|
9
|
-
}
|
|
10
|
-
`;
|
|
11
|
-
|
|
12
|
-
describe('CLI migrate commands test', () => {
|
|
13
|
-
it('should generate a database with migrate dev', () => {
|
|
14
|
-
const workDir = createProject(model);
|
|
15
|
-
runCli('migrate dev --name init', workDir);
|
|
16
|
-
expect(fs.existsSync(path.join(workDir, 'zenstack/dev.db'))).toBe(true);
|
|
17
|
-
expect(fs.existsSync(path.join(workDir, 'zenstack/migrations'))).toBe(true);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('should reset the database with migrate reset', () => {
|
|
21
|
-
const workDir = createProject(model);
|
|
22
|
-
runCli('db push', workDir);
|
|
23
|
-
expect(fs.existsSync(path.join(workDir, 'zenstack/dev.db'))).toBe(true);
|
|
24
|
-
runCli('migrate reset --force', workDir);
|
|
25
|
-
expect(fs.existsSync(path.join(workDir, 'zenstack/dev.db'))).toBe(true);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('should reset the database with migrate deploy', () => {
|
|
29
|
-
const workDir = createProject(model);
|
|
30
|
-
runCli('migrate dev --name init', workDir);
|
|
31
|
-
fs.rmSync(path.join(workDir, 'zenstack/dev.db'));
|
|
32
|
-
runCli('migrate deploy', workDir);
|
|
33
|
-
expect(fs.existsSync(path.join(workDir, 'zenstack/dev.db'))).toBe(true);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('supports migrate status', () => {
|
|
37
|
-
const workDir = createProject(model);
|
|
38
|
-
runCli('migrate dev --name init', workDir);
|
|
39
|
-
runCli('migrate status', workDir);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('supports migrate resolve', () => {
|
|
43
|
-
const workDir = createProject(model);
|
|
44
|
-
runCli('migrate dev --name init', workDir);
|
|
45
|
-
|
|
46
|
-
// find the migration record "timestamp_init"
|
|
47
|
-
const migrationRecords = fs.readdirSync(path.join(workDir, 'zenstack/migrations'));
|
|
48
|
-
const migration = migrationRecords.find((f) => f.endsWith('_init'));
|
|
49
|
-
|
|
50
|
-
// force a migration failure
|
|
51
|
-
fs.writeFileSync(path.join(workDir, 'zenstack/migrations', migration!, 'migration.sql'), 'invalid content');
|
|
52
|
-
|
|
53
|
-
// redeploy the migration, which will fail
|
|
54
|
-
fs.rmSync(path.join(workDir, 'zenstack/dev.db'), { force: true });
|
|
55
|
-
try {
|
|
56
|
-
runCli('migrate deploy', workDir);
|
|
57
|
-
} catch {
|
|
58
|
-
// noop
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// --rolled-back
|
|
62
|
-
runCli(`migrate resolve --rolled-back ${migration}`, workDir);
|
|
63
|
-
|
|
64
|
-
// --applied
|
|
65
|
-
runCli(`migrate resolve --applied ${migration}`, workDir);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('should throw error when neither applied nor rolled-back is provided', () => {
|
|
69
|
-
const workDir = createProject(model);
|
|
70
|
-
expect(() => runCli('migrate resolve', workDir)).toThrow();
|
|
71
|
-
});
|
|
72
|
-
});
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { describe, expect, it } from 'vitest';
|
|
4
|
-
import { createProject, runCli } from '../utils';
|
|
5
|
-
import { execSync } from 'node:child_process';
|
|
6
|
-
|
|
7
|
-
describe('Custom plugins tests', () => {
|
|
8
|
-
it('runs custom plugin generator', () => {
|
|
9
|
-
const workDir = createProject(`
|
|
10
|
-
plugin custom {
|
|
11
|
-
provider = '../my-plugin.js'
|
|
12
|
-
output = '../custom-output'
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
model User {
|
|
16
|
-
id String @id @default(cuid())
|
|
17
|
-
}
|
|
18
|
-
`);
|
|
19
|
-
|
|
20
|
-
fs.writeFileSync(
|
|
21
|
-
path.join(workDir, 'my-plugin.ts'),
|
|
22
|
-
`
|
|
23
|
-
import type { CliPlugin } from '@zenstackhq/sdk';
|
|
24
|
-
import fs from 'node:fs';
|
|
25
|
-
import path from 'node:path';
|
|
26
|
-
|
|
27
|
-
const plugin: CliPlugin = {
|
|
28
|
-
name: 'Custom Generator',
|
|
29
|
-
statusText: 'Generating foo.txt',
|
|
30
|
-
async generate({ model, defaultOutputPath, pluginOptions }) {
|
|
31
|
-
let outDir = defaultOutputPath;
|
|
32
|
-
if (typeof pluginOptions['output'] === 'string') {
|
|
33
|
-
outDir = path.resolve(defaultOutputPath, pluginOptions['output']);
|
|
34
|
-
if (!fs.existsSync(outDir)) {
|
|
35
|
-
fs.mkdirSync(outDir, { recursive: true });
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
fs.writeFileSync(path.join(outDir, 'foo.txt'), 'from my plugin');
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export default plugin;
|
|
43
|
-
`,
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
execSync('npx tsc', { cwd: workDir });
|
|
47
|
-
runCli('generate', workDir);
|
|
48
|
-
expect(fs.existsSync(path.join(workDir, 'custom-output/foo.txt'))).toBe(true);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { describe, expect, it } from 'vitest';
|
|
4
|
-
import { createProject, runCli } from '../utils';
|
|
5
|
-
|
|
6
|
-
describe('Core plugins tests', () => {
|
|
7
|
-
it('can automatically generate a TypeScript schema with default output', () => {
|
|
8
|
-
const workDir = createProject(`
|
|
9
|
-
model User {
|
|
10
|
-
id String @id @default(cuid())
|
|
11
|
-
}
|
|
12
|
-
`);
|
|
13
|
-
runCli('generate', workDir);
|
|
14
|
-
expect(fs.existsSync(path.join(workDir, 'zenstack/schema.ts'))).toBe(true);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('can automatically generate a TypeScript schema with custom output', () => {
|
|
18
|
-
const workDir = createProject(`
|
|
19
|
-
plugin typescript {
|
|
20
|
-
provider = '@core/typescript'
|
|
21
|
-
output = '../generated-schema'
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
model User {
|
|
25
|
-
id String @id @default(cuid())
|
|
26
|
-
}
|
|
27
|
-
`);
|
|
28
|
-
runCli('generate', workDir);
|
|
29
|
-
expect(fs.existsSync(path.join(workDir, 'generated-schema/schema.ts'))).toBe(true);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('can generate a Prisma schema with default output', () => {
|
|
33
|
-
const workDir = createProject(`
|
|
34
|
-
plugin prisma {
|
|
35
|
-
provider = '@core/prisma'
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
model User {
|
|
39
|
-
id String @id @default(cuid())
|
|
40
|
-
}
|
|
41
|
-
`);
|
|
42
|
-
runCli('generate', workDir);
|
|
43
|
-
expect(fs.existsSync(path.join(workDir, 'zenstack/schema.prisma'))).toBe(true);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('can generate a Prisma schema with custom output', () => {
|
|
47
|
-
const workDir = createProject(`
|
|
48
|
-
plugin prisma {
|
|
49
|
-
provider = '@core/prisma'
|
|
50
|
-
output = '../prisma/schema.prisma'
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
model User {
|
|
54
|
-
id String @id @default(cuid())
|
|
55
|
-
}
|
|
56
|
-
`);
|
|
57
|
-
runCli('generate', workDir);
|
|
58
|
-
expect(fs.existsSync(path.join(workDir, 'prisma/schema.prisma'))).toBe(true);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('can generate a Prisma schema with custom output relative to zenstack.output', () => {
|
|
62
|
-
const workDir = createProject(`
|
|
63
|
-
plugin prisma {
|
|
64
|
-
provider = '@core/prisma'
|
|
65
|
-
output = './schema.prisma'
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
model User {
|
|
69
|
-
id String @id @default(cuid())
|
|
70
|
-
}
|
|
71
|
-
`);
|
|
72
|
-
|
|
73
|
-
const pkgJson = JSON.parse(fs.readFileSync(path.join(workDir, 'package.json'), 'utf8'));
|
|
74
|
-
pkgJson.zenstack = {
|
|
75
|
-
output: './relative',
|
|
76
|
-
};
|
|
77
|
-
fs.writeFileSync(path.join(workDir, 'package.json'), JSON.stringify(pkgJson, null, 2));
|
|
78
|
-
runCli('generate', workDir);
|
|
79
|
-
expect(fs.existsSync(path.join(workDir, 'relative/schema.prisma'))).toBe(true);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
@@ -1,445 +0,0 @@
|
|
|
1
|
-
import { ExpressionUtils } from '@zenstackhq/orm/schema';
|
|
2
|
-
import { createTestProject, generateTsSchema, generateTsSchemaInPlace } from '@zenstackhq/testtools';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import { describe, expect, it } from 'vitest';
|
|
6
|
-
|
|
7
|
-
describe('TypeScript schema generation tests', () => {
|
|
8
|
-
it('generates correct data models', async () => {
|
|
9
|
-
const { schema } = await generateTsSchema(`
|
|
10
|
-
model User {
|
|
11
|
-
id String @id @default(uuid())
|
|
12
|
-
name String
|
|
13
|
-
email String @unique
|
|
14
|
-
createdAt DateTime @default(now())
|
|
15
|
-
updatedAt DateTime @updatedAt
|
|
16
|
-
posts Post[]
|
|
17
|
-
|
|
18
|
-
@@map('users')
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
model Post {
|
|
22
|
-
id String @id @default(cuid())
|
|
23
|
-
title String
|
|
24
|
-
published Boolean @default(false)
|
|
25
|
-
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
|
|
26
|
-
authorId String
|
|
27
|
-
}
|
|
28
|
-
`);
|
|
29
|
-
|
|
30
|
-
expect(schema.provider).toMatchObject({
|
|
31
|
-
type: 'sqlite',
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
expect(schema.models).toMatchObject({
|
|
35
|
-
User: {
|
|
36
|
-
fields: {
|
|
37
|
-
id: {
|
|
38
|
-
type: 'String',
|
|
39
|
-
id: true,
|
|
40
|
-
default: ExpressionUtils.call('uuid'),
|
|
41
|
-
attributes: [
|
|
42
|
-
{ name: '@id' },
|
|
43
|
-
{
|
|
44
|
-
name: '@default',
|
|
45
|
-
args: [
|
|
46
|
-
{
|
|
47
|
-
value: {
|
|
48
|
-
kind: 'call',
|
|
49
|
-
function: 'uuid',
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
],
|
|
53
|
-
},
|
|
54
|
-
],
|
|
55
|
-
},
|
|
56
|
-
name: { type: 'String' },
|
|
57
|
-
email: { type: 'String', unique: true },
|
|
58
|
-
createdAt: {
|
|
59
|
-
type: 'DateTime',
|
|
60
|
-
default: ExpressionUtils.call('now'),
|
|
61
|
-
attributes: [
|
|
62
|
-
{
|
|
63
|
-
name: '@default',
|
|
64
|
-
args: [
|
|
65
|
-
{
|
|
66
|
-
value: {
|
|
67
|
-
kind: 'call',
|
|
68
|
-
function: 'now',
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
],
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
},
|
|
75
|
-
updatedAt: {
|
|
76
|
-
type: 'DateTime',
|
|
77
|
-
attributes: [
|
|
78
|
-
{
|
|
79
|
-
name: '@updatedAt',
|
|
80
|
-
},
|
|
81
|
-
],
|
|
82
|
-
updatedAt: true,
|
|
83
|
-
},
|
|
84
|
-
posts: {
|
|
85
|
-
type: 'Post',
|
|
86
|
-
array: true,
|
|
87
|
-
relation: {
|
|
88
|
-
opposite: 'author',
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
attributes: [
|
|
93
|
-
{
|
|
94
|
-
name: '@@map',
|
|
95
|
-
args: [{ name: 'name', value: { kind: 'literal' } }],
|
|
96
|
-
},
|
|
97
|
-
],
|
|
98
|
-
idFields: ['id'],
|
|
99
|
-
uniqueFields: {
|
|
100
|
-
id: { type: 'String' },
|
|
101
|
-
email: { type: 'String' },
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
Post: {
|
|
105
|
-
fields: {
|
|
106
|
-
id: {
|
|
107
|
-
type: 'String',
|
|
108
|
-
id: true,
|
|
109
|
-
default: ExpressionUtils.call('cuid'),
|
|
110
|
-
attributes: [
|
|
111
|
-
{ name: '@id' },
|
|
112
|
-
{
|
|
113
|
-
name: '@default',
|
|
114
|
-
args: [
|
|
115
|
-
{
|
|
116
|
-
value: {
|
|
117
|
-
kind: 'call',
|
|
118
|
-
function: 'cuid',
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
],
|
|
122
|
-
},
|
|
123
|
-
],
|
|
124
|
-
},
|
|
125
|
-
title: { type: 'String' },
|
|
126
|
-
published: {
|
|
127
|
-
type: 'Boolean',
|
|
128
|
-
default: false,
|
|
129
|
-
},
|
|
130
|
-
authorId: { type: 'String' },
|
|
131
|
-
author: {
|
|
132
|
-
type: 'User',
|
|
133
|
-
relation: {
|
|
134
|
-
fields: ['authorId'],
|
|
135
|
-
references: ['id'],
|
|
136
|
-
onDelete: 'Cascade',
|
|
137
|
-
opposite: 'posts',
|
|
138
|
-
},
|
|
139
|
-
attributes: [
|
|
140
|
-
{
|
|
141
|
-
name: '@relation',
|
|
142
|
-
args: [
|
|
143
|
-
{
|
|
144
|
-
name: 'fields',
|
|
145
|
-
value: {
|
|
146
|
-
kind: 'array',
|
|
147
|
-
items: [
|
|
148
|
-
{
|
|
149
|
-
kind: 'field',
|
|
150
|
-
field: 'authorId',
|
|
151
|
-
},
|
|
152
|
-
],
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
name: 'references',
|
|
157
|
-
value: {
|
|
158
|
-
kind: 'array',
|
|
159
|
-
items: [
|
|
160
|
-
{
|
|
161
|
-
kind: 'field',
|
|
162
|
-
field: 'id',
|
|
163
|
-
},
|
|
164
|
-
],
|
|
165
|
-
},
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
name: 'onDelete',
|
|
169
|
-
value: {
|
|
170
|
-
kind: 'literal',
|
|
171
|
-
value: 'Cascade',
|
|
172
|
-
},
|
|
173
|
-
},
|
|
174
|
-
],
|
|
175
|
-
},
|
|
176
|
-
],
|
|
177
|
-
},
|
|
178
|
-
},
|
|
179
|
-
idFields: ['id'],
|
|
180
|
-
uniqueFields: {
|
|
181
|
-
id: { type: 'String' },
|
|
182
|
-
},
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('merges fields and attributes from mixins', async () => {
|
|
188
|
-
const { schema } = await generateTsSchema(`
|
|
189
|
-
type Timestamped {
|
|
190
|
-
createdAt DateTime @default(now())
|
|
191
|
-
updatedAt DateTime @updatedAt
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
type Named {
|
|
195
|
-
name String
|
|
196
|
-
@@unique([name])
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
model User with Timestamped Named {
|
|
200
|
-
id String @id @default(uuid())
|
|
201
|
-
email String @unique
|
|
202
|
-
}
|
|
203
|
-
`);
|
|
204
|
-
expect(schema).toMatchObject({
|
|
205
|
-
models: {
|
|
206
|
-
User: {
|
|
207
|
-
fields: {
|
|
208
|
-
id: { type: 'String' },
|
|
209
|
-
email: { type: 'String' },
|
|
210
|
-
createdAt: {
|
|
211
|
-
type: 'DateTime',
|
|
212
|
-
default: expect.objectContaining({ function: 'now', kind: 'call' }),
|
|
213
|
-
},
|
|
214
|
-
updatedAt: { type: 'DateTime', updatedAt: true },
|
|
215
|
-
name: { type: 'String' },
|
|
216
|
-
},
|
|
217
|
-
uniqueFields: expect.objectContaining({
|
|
218
|
-
name: { type: 'String' },
|
|
219
|
-
}),
|
|
220
|
-
},
|
|
221
|
-
},
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
it('generates type definitions', async () => {
|
|
226
|
-
const { schema } = await generateTsSchema(`
|
|
227
|
-
type Base {
|
|
228
|
-
name String
|
|
229
|
-
@@meta('foo', 'bar')
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
type Address with Base {
|
|
233
|
-
street String
|
|
234
|
-
city String
|
|
235
|
-
}
|
|
236
|
-
`);
|
|
237
|
-
expect(schema).toMatchObject({
|
|
238
|
-
typeDefs: {
|
|
239
|
-
Base: {
|
|
240
|
-
fields: {
|
|
241
|
-
name: { type: 'String' },
|
|
242
|
-
},
|
|
243
|
-
attributes: [
|
|
244
|
-
{
|
|
245
|
-
name: '@@meta',
|
|
246
|
-
args: [
|
|
247
|
-
{ name: 'name', value: { kind: 'literal', value: 'foo' } },
|
|
248
|
-
{ name: 'value', value: { kind: 'literal', value: 'bar' } },
|
|
249
|
-
],
|
|
250
|
-
},
|
|
251
|
-
],
|
|
252
|
-
},
|
|
253
|
-
Address: {
|
|
254
|
-
fields: {
|
|
255
|
-
street: { type: 'String' },
|
|
256
|
-
city: { type: 'String' },
|
|
257
|
-
},
|
|
258
|
-
attributes: [
|
|
259
|
-
{
|
|
260
|
-
name: '@@meta',
|
|
261
|
-
args: [
|
|
262
|
-
{ name: 'name', value: { kind: 'literal', value: 'foo' } },
|
|
263
|
-
{ name: 'value', value: { kind: 'literal', value: 'bar' } },
|
|
264
|
-
],
|
|
265
|
-
},
|
|
266
|
-
],
|
|
267
|
-
},
|
|
268
|
-
},
|
|
269
|
-
});
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
it('merges fields and attributes from base models', async () => {
|
|
273
|
-
const { schema } = await generateTsSchema(`
|
|
274
|
-
model Base {
|
|
275
|
-
id String @id @default(uuid())
|
|
276
|
-
createdAt DateTime @default(now())
|
|
277
|
-
updatedAt DateTime @updatedAt
|
|
278
|
-
type String
|
|
279
|
-
@@delegate(type)
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
model User extends Base {
|
|
283
|
-
email String @unique
|
|
284
|
-
}
|
|
285
|
-
`);
|
|
286
|
-
expect(schema).toMatchObject({
|
|
287
|
-
models: {
|
|
288
|
-
Base: {
|
|
289
|
-
fields: {
|
|
290
|
-
id: {
|
|
291
|
-
type: 'String',
|
|
292
|
-
id: true,
|
|
293
|
-
default: expect.objectContaining({ function: 'uuid', kind: 'call' }),
|
|
294
|
-
},
|
|
295
|
-
createdAt: {
|
|
296
|
-
type: 'DateTime',
|
|
297
|
-
default: expect.objectContaining({ function: 'now', kind: 'call' }),
|
|
298
|
-
},
|
|
299
|
-
updatedAt: { type: 'DateTime', updatedAt: true },
|
|
300
|
-
type: { type: 'String' },
|
|
301
|
-
},
|
|
302
|
-
attributes: [
|
|
303
|
-
{
|
|
304
|
-
name: '@@delegate',
|
|
305
|
-
args: [{ name: 'discriminator', value: { kind: 'field', field: 'type' } }],
|
|
306
|
-
},
|
|
307
|
-
],
|
|
308
|
-
isDelegate: true,
|
|
309
|
-
},
|
|
310
|
-
User: {
|
|
311
|
-
baseModel: 'Base',
|
|
312
|
-
fields: {
|
|
313
|
-
id: { type: 'String' },
|
|
314
|
-
createdAt: {
|
|
315
|
-
type: 'DateTime',
|
|
316
|
-
default: expect.objectContaining({ function: 'now', kind: 'call' }),
|
|
317
|
-
originModel: 'Base',
|
|
318
|
-
},
|
|
319
|
-
updatedAt: { type: 'DateTime', updatedAt: true, originModel: 'Base' },
|
|
320
|
-
type: { type: 'String', originModel: 'Base' },
|
|
321
|
-
email: { type: 'String' },
|
|
322
|
-
},
|
|
323
|
-
uniqueFields: expect.objectContaining({
|
|
324
|
-
email: { type: 'String' },
|
|
325
|
-
}),
|
|
326
|
-
},
|
|
327
|
-
},
|
|
328
|
-
});
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
it('merges all declarations from imported modules', async () => {
|
|
332
|
-
const workDir = createTestProject();
|
|
333
|
-
fs.writeFileSync(
|
|
334
|
-
path.join(workDir, 'a.zmodel'),
|
|
335
|
-
`
|
|
336
|
-
enum Role {
|
|
337
|
-
Admin
|
|
338
|
-
User
|
|
339
|
-
}
|
|
340
|
-
`,
|
|
341
|
-
);
|
|
342
|
-
fs.writeFileSync(
|
|
343
|
-
path.join(workDir, 'b.zmodel'),
|
|
344
|
-
`
|
|
345
|
-
import './a'
|
|
346
|
-
|
|
347
|
-
datasource db {
|
|
348
|
-
provider = 'sqlite'
|
|
349
|
-
url = 'file:./test.db'
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
model User {
|
|
353
|
-
id Int @id
|
|
354
|
-
role Role
|
|
355
|
-
}
|
|
356
|
-
`,
|
|
357
|
-
);
|
|
358
|
-
|
|
359
|
-
const { schema } = await generateTsSchemaInPlace(path.join(workDir, 'b.zmodel'));
|
|
360
|
-
expect(schema.enums).toMatchObject({ Role: expect.any(Object) });
|
|
361
|
-
expect(schema.models).toMatchObject({ User: expect.any(Object) });
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
it('generates correct default literal function arguments', async () => {
|
|
365
|
-
const { schema } = await generateTsSchema(`
|
|
366
|
-
model User {
|
|
367
|
-
id String @id @default(uuid(7))
|
|
368
|
-
}
|
|
369
|
-
`);
|
|
370
|
-
|
|
371
|
-
expect(schema.models).toMatchObject({
|
|
372
|
-
User: {
|
|
373
|
-
name: 'User',
|
|
374
|
-
fields: {
|
|
375
|
-
id: {
|
|
376
|
-
name: 'id',
|
|
377
|
-
type: 'String',
|
|
378
|
-
id: true,
|
|
379
|
-
attributes: [
|
|
380
|
-
{
|
|
381
|
-
name: '@id',
|
|
382
|
-
},
|
|
383
|
-
{
|
|
384
|
-
name: '@default',
|
|
385
|
-
args: [
|
|
386
|
-
{
|
|
387
|
-
name: 'value',
|
|
388
|
-
value: {
|
|
389
|
-
kind: 'call',
|
|
390
|
-
function: 'uuid',
|
|
391
|
-
args: [
|
|
392
|
-
{
|
|
393
|
-
kind: 'literal',
|
|
394
|
-
value: 7,
|
|
395
|
-
},
|
|
396
|
-
],
|
|
397
|
-
},
|
|
398
|
-
},
|
|
399
|
-
],
|
|
400
|
-
},
|
|
401
|
-
],
|
|
402
|
-
default: {
|
|
403
|
-
kind: 'call',
|
|
404
|
-
function: 'uuid',
|
|
405
|
-
args: [
|
|
406
|
-
{
|
|
407
|
-
kind: 'literal',
|
|
408
|
-
value: 7,
|
|
409
|
-
},
|
|
410
|
-
],
|
|
411
|
-
},
|
|
412
|
-
},
|
|
413
|
-
},
|
|
414
|
-
idFields: ['id'],
|
|
415
|
-
uniqueFields: {
|
|
416
|
-
id: {
|
|
417
|
-
type: 'String',
|
|
418
|
-
},
|
|
419
|
-
},
|
|
420
|
-
},
|
|
421
|
-
});
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
it('supports lite schema generation', async () => {
|
|
425
|
-
const { schemaLite } = await generateTsSchema(
|
|
426
|
-
`
|
|
427
|
-
model User {
|
|
428
|
-
id String @id @default(uuid())
|
|
429
|
-
name String
|
|
430
|
-
email String @unique
|
|
431
|
-
|
|
432
|
-
@@map('users')
|
|
433
|
-
}
|
|
434
|
-
`,
|
|
435
|
-
undefined,
|
|
436
|
-
undefined,
|
|
437
|
-
undefined,
|
|
438
|
-
true,
|
|
439
|
-
);
|
|
440
|
-
|
|
441
|
-
expect(schemaLite!.models.User.attributes).toBeUndefined();
|
|
442
|
-
expect(schemaLite!.models.User.fields.id.attributes).toBeUndefined();
|
|
443
|
-
expect(schemaLite!.models.User.fields.email.attributes).toBeUndefined();
|
|
444
|
-
});
|
|
445
|
-
});
|
package/test/utils.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { createTestProject } from '@zenstackhq/testtools';
|
|
2
|
-
import { execSync } from 'node:child_process';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
|
|
6
|
-
const ZMODEL_PRELUDE = `datasource db {
|
|
7
|
-
provider = "sqlite"
|
|
8
|
-
url = "file:./dev.db"
|
|
9
|
-
}
|
|
10
|
-
`;
|
|
11
|
-
|
|
12
|
-
export function createProject(zmodel: string, addPrelude = true) {
|
|
13
|
-
const workDir = createTestProject();
|
|
14
|
-
fs.mkdirSync(path.join(workDir, 'zenstack'), { recursive: true });
|
|
15
|
-
const schemaPath = path.join(workDir, 'zenstack/schema.zmodel');
|
|
16
|
-
fs.writeFileSync(schemaPath, addPrelude ? `${ZMODEL_PRELUDE}\n\n${zmodel}` : zmodel);
|
|
17
|
-
return workDir;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function runCli(command: string, cwd: string) {
|
|
21
|
-
const cli = path.join(__dirname, '../dist/index.js');
|
|
22
|
-
execSync(`node ${cli} ${command}`, { cwd });
|
|
23
|
-
}
|
package/tsconfig.json
DELETED