Skip to content

Commit 88828e3

Browse files
authored
fix: missing string quote during function arg gen (#234)
1 parent 4f1b9fc commit 88828e3

File tree

16 files changed

+109
-37
lines changed

16 files changed

+109
-37
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "zenstack-monorepo",
3-
"version": "1.0.0-alpha.53",
3+
"version": "1.0.0-alpha.55",
44
"description": "",
55
"scripts": {
66
"build": "pnpm -r build",

packages/language/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@zenstackhq/language",
3-
"version": "1.0.0-alpha.53",
3+
"version": "1.0.0-alpha.55",
44
"displayName": "ZenStack modeling language compiler",
55
"description": "ZenStack modeling language compiler",
66
"homepage": "https://zenstack.dev",

packages/next/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@zenstackhq/next",
3-
"version": "1.0.0-alpha.53",
3+
"version": "1.0.0-alpha.55",
44
"displayName": "ZenStack Next.js integration",
55
"description": "ZenStack Next.js integration",
66
"homepage": "https://zenstack.dev",

packages/plugins/react/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/react",
33
"displayName": "ZenStack plugin and runtime for ReactJS",
4-
"version": "1.0.0-alpha.53",
4+
"version": "1.0.0-alpha.55",
55
"description": "ZenStack plugin and runtime for ReactJS",
66
"main": "index.js",
77
"repository": {

packages/plugins/trpc/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/trpc",
33
"displayName": "ZenStack plugin for tRPC",
4-
"version": "1.0.0-alpha.53",
4+
"version": "1.0.0-alpha.55",
55
"description": "ZenStack plugin for tRPC",
66
"main": "index.js",
77
"repository": {

packages/runtime/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/runtime",
33
"displayName": "ZenStack Runtime Library",
4-
"version": "1.0.0-alpha.53",
4+
"version": "1.0.0-alpha.55",
55
"description": "Runtime of ZenStack for both client-side and server-side environments.",
66
"repository": {
77
"type": "git",
@@ -29,7 +29,6 @@
2929
"decimal.js": "^10.4.2",
3030
"deepcopy": "^2.1.0",
3131
"superjson": "^1.11.0",
32-
"swr": "^1.3.0",
3332
"tslib": "^2.4.1",
3433
"zod": "^3.19.1",
3534
"zod-validation-error": "^0.2.1"

packages/schema/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"publisher": "zenstack",
44
"displayName": "ZenStack Language Tools",
55
"description": "A toolkit for building secure CRUD apps with Next.js + Typescript",
6-
"version": "1.0.0-alpha.53",
6+
"version": "1.0.0-alpha.55",
77
"author": {
88
"name": "ZenStack Team"
99
},

packages/schema/src/language-server/validator/utils.ts

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
DataModelAttribute,
88
DataModelField,
99
DataModelFieldAttribute,
10+
Expression,
1011
ExpressionType,
1112
isArrayExpr,
1213
isAttribute,
@@ -54,10 +55,21 @@ export function getStringLiteral(node: AstNode | undefined): string | undefined
5455
}
5556
}
5657

58+
const isoDateTimeRegex = /^\d{4}(-\d\d(-\d\d(T\d\d:\d\d(:\d\d)?(\.\d+)?(([+-]\d\d:\d\d)|Z)?)?)?)?$/i;
59+
5760
/**
5861
* Determines if the given sourceType is assignable to a destination of destType
5962
*/
60-
export function typeAssignable(destType: ExpressionType, sourceType: ExpressionType): boolean {
63+
export function typeAssignable(destType: ExpressionType, sourceType: ExpressionType, sourceExpr?: Expression): boolean {
64+
// implicit conversion from ISO datetime string to datetime
65+
if (destType === 'DateTime' && sourceType === 'String' && sourceExpr && isLiteralExpr(sourceExpr)) {
66+
const literal = getStringLiteral(sourceExpr);
67+
if (literal && isoDateTimeRegex.test(literal)) {
68+
// implicitly convert to DateTime
69+
sourceType = 'DateTime';
70+
}
71+
}
72+
6173
switch (destType) {
6274
case 'Any':
6375
return true;
@@ -108,6 +120,19 @@ export function assignableToAttributeParam(
108120
let dstIsArray = param.type.array;
109121
const dstRef = param.type.reference;
110122

123+
// destination is field reference or transitive field reference, check if
124+
// argument is reference or array or reference
125+
if (dstType === 'FieldReference' || dstType === 'TransitiveFieldReference') {
126+
if (dstIsArray) {
127+
return (
128+
isArrayExpr(arg.value) &&
129+
!arg.value.items.find((item) => !isReferenceExpr(item) || !isDataModelField(item.target.ref))
130+
);
131+
} else {
132+
return isReferenceExpr(arg.value) && isDataModelField(arg.value.target.ref);
133+
}
134+
}
135+
111136
if (isEnum(argResolvedType.decl)) {
112137
// enum type
113138

@@ -127,16 +152,7 @@ export function assignableToAttributeParam(
127152
return false;
128153
}
129154

130-
if (dstType === 'FieldReference' || dstType === 'TransitiveFieldReference') {
131-
if (dstIsArray) {
132-
return (
133-
isArrayExpr(arg.value) &&
134-
!arg.value.items.find((item) => !isReferenceExpr(item) || !isDataModelField(item.target.ref))
135-
);
136-
} else {
137-
return isReferenceExpr(arg.value) && isDataModelField(arg.value.target.ref);
138-
}
139-
} else if (dstType === 'ContextType') {
155+
if (dstType === 'ContextType') {
140156
// attribute parameter type is ContextType, need to infer type from
141157
// the attribute's container
142158
if (isDataModelField(attr.$container)) {
@@ -151,7 +167,8 @@ export function assignableToAttributeParam(
151167
}
152168

153169
return (
154-
typeAssignable(dstType, argResolvedType.decl) && (dstType === 'Any' || dstIsArray === argResolvedType.array)
170+
typeAssignable(dstType, argResolvedType.decl, arg.value) &&
171+
(dstType === 'Any' || dstIsArray === argResolvedType.array)
155172
);
156173
} else {
157174
// reference type

packages/schema/src/plugins/prisma/prisma-builder.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,13 @@ export class FunctionCallArg {
277277
constructor(public name: string | undefined, public value: any) {}
278278

279279
toString(): string {
280-
return this.name ? `${this.name}: ${this.value}` : this.value;
280+
const val =
281+
this.value === null || this.value === undefined
282+
? 'null'
283+
: typeof this.value === 'string'
284+
? `"${this.value}"`
285+
: this.value.toString();
286+
return this.name ? `${this.name}: ${val}` : val;
281287
}
282288
}
283289

packages/schema/tests/generator/prisma-builder.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
FieldReference,
88
FieldReferenceArg,
99
FunctionCall,
10+
FunctionCallArg,
1011
ModelFieldType,
1112
PrismaModel,
1213
} from '../../src/plugins/prisma/prisma-builder';
@@ -94,6 +95,17 @@ describe('Prisma Builder Tests', () => {
9495
post.addField('id', 'String', [new FieldAttribute('@id')]);
9596
post.addField('slug', 'String');
9697
post.addField('space', 'String');
98+
post.addField('tsid', 'String', [
99+
new FieldAttribute('@default', [
100+
new AttributeArg(
101+
undefined,
102+
new AttributeArgValue(
103+
'FunctionCall',
104+
new FunctionCall('dbgenerated', [new FunctionCallArg(undefined, 'timestamp_id()')])
105+
)
106+
),
107+
]),
108+
]);
97109
post.addAttribute('@@unique', [
98110
new AttributeArg(
99111
'fields',

packages/schema/tests/schema/validation/attribute-validation.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,34 @@ describe('Attribute tests', () => {
8181
}
8282
`)
8383
).toContain(`Attribute "@default" doesn't have a parameter named "foo"`);
84+
85+
expect(
86+
await loadModelWithError(`
87+
${prelude}
88+
model M {
89+
id String @id()
90+
dt DateTime @default('2020abc')
91+
}
92+
`)
93+
).toContain('Value is not assignable to parameter');
94+
95+
// auto-convert of string to date time
96+
await loadModel(`
97+
${prelude}
98+
model M {
99+
id String @id()
100+
dt DateTime @default('2000-01-01T00:00:00Z')
101+
}
102+
`);
103+
104+
// auto-convert of string to bytes
105+
await loadModel(`
106+
${prelude}
107+
model M {
108+
id String @id()
109+
dt Bytes @default('abc123')
110+
}
111+
`);
84112
});
85113

86114
it('field attribute coverage', async () => {

packages/schema/tests/schema/validation/datamodel-validation.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,5 +370,27 @@ describe('Data Model Validation Tests', () => {
370370
}
371371
`)
372372
).toContain(`Could not resolve reference to ReferenceTarget named 'aId'.`);
373+
374+
// enum as foreign key
375+
await loadModel(`
376+
${prelude}
377+
378+
enum Role {
379+
ADMIN
380+
USER
381+
}
382+
383+
model A {
384+
id String @id
385+
role Role @unique
386+
bs B[]
387+
}
388+
389+
model B {
390+
id String @id
391+
a A @relation(fields: [aRole], references: [role])
392+
aRole Role
393+
}
394+
`);
373395
});
374396
});

packages/sdk/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@zenstackhq/sdk",
3-
"version": "1.0.0-alpha.53",
3+
"version": "1.0.0-alpha.55",
44
"description": "ZenStack plugin development SDK",
55
"main": "index.js",
66
"scripts": {

packages/testtools/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@zenstackhq/testtools",
3-
"version": "1.0.0-alpha.53",
3+
"version": "1.0.0-alpha.55",
44
"description": "ZenStack Test Tools",
55
"main": "index.js",
66
"publishConfig": {

pnpm-lock.yaml

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

tests/integration/test-run/package-lock.json

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

0 commit comments

Comments
 (0)