Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/schema/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export type RelationInfo = {
name?: string;
fields?: string[];
references?: string[];
hasDefault?: boolean;
opposite?: string;
onDelete?: CascadeAction;
onUpdate?: CascadeAction;
Expand Down Expand Up @@ -253,7 +254,9 @@ export type FieldHasDefault<
? true
: GetModelField<Schema, Model, Field>['updatedAt'] extends true
? true
: false;
: GetModelField<Schema, Model, Field>['relation'] extends { hasDefault: true }
? true
: false;

export type FieldIsRelationArray<
Schema extends SchemaDef,
Expand Down
15 changes: 15 additions & 0 deletions packages/sdk/src/ts-schema-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -707,12 +707,16 @@ export class TsSchemaGenerator {
}

const relation = getAttribute(field, '@relation');
const fkFields: string[] = [];
if (relation) {
for (const arg of relation.args) {
const param = arg.$resolvedParam.name;
if (param === 'fields' || param === 'references') {
const fieldNames = this.getReferenceNames(arg.value);
if (fieldNames) {
if (param === 'fields') {
fkFields.push(...fieldNames);
}
relationFields.push(
ts.factory.createPropertyAssignment(
param,
Expand All @@ -733,6 +737,17 @@ export class TsSchemaGenerator {
}
}

// check if all fk fields have default values
if (fkFields.length > 0) {
const allHaveDefault = fkFields.every((fieldName) => {
const fieldDef = field.$container.fields.find((f) => f.name === fieldName);
return fieldDef && hasAttribute(fieldDef, '@default');
});
if (allHaveDefault) {
relationFields.push(ts.factory.createPropertyAssignment('hasDefault', ts.factory.createTrue()));
}
}

return ts.factory.createObjectLiteralExpression(relationFields);
}

Expand Down
21 changes: 21 additions & 0 deletions tests/e2e/orm/client-api/default-auth.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createTestClient } from '@zenstackhq/testtools';
import { describe, expect, it } from 'vitest';
import { schema } from '../schemas/default-auth/schema';

describe('Auth as default value tests', () => {
it('should create without requiring the default auth field', async () => {
const db = await createTestClient(schema);
const user1 = await db.user.create({ data: {} });
await expect(db.$setAuth(user1).profile.create({ data: { bio: 'My bio' } })).resolves.toMatchObject({
userId: user1.id,
});

const address = await db.address.create({ data: { city: 'Seattle ' } });
const user2 = await db.user.create({ data: {} });
await expect(
db.$setAuth(user2).profile.create({ data: { bio: 'My bio', address: { connect: { id: address.id } } } }),
).resolves.toMatchObject({
userId: user2.id,
});
});
});
70 changes: 70 additions & 0 deletions tests/e2e/orm/schemas/default-auth/input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//////////////////////////////////////////////////////////////////////////////////////////////
// DO NOT MODIFY THIS FILE //
// This file is automatically generated by ZenStack CLI and should not be manually updated. //
//////////////////////////////////////////////////////////////////////////////////////////////

/* eslint-disable */

import { type SchemaType as $Schema } from "./schema";
import type { FindManyArgs as $FindManyArgs, FindUniqueArgs as $FindUniqueArgs, FindFirstArgs as $FindFirstArgs, CreateArgs as $CreateArgs, CreateManyArgs as $CreateManyArgs, CreateManyAndReturnArgs as $CreateManyAndReturnArgs, UpdateArgs as $UpdateArgs, UpdateManyArgs as $UpdateManyArgs, UpdateManyAndReturnArgs as $UpdateManyAndReturnArgs, UpsertArgs as $UpsertArgs, DeleteArgs as $DeleteArgs, DeleteManyArgs as $DeleteManyArgs, CountArgs as $CountArgs, AggregateArgs as $AggregateArgs, GroupByArgs as $GroupByArgs, WhereInput as $WhereInput, SelectInput as $SelectInput, IncludeInput as $IncludeInput, OmitInput as $OmitInput } from "@zenstackhq/orm";
import type { SimplifiedModelResult as $SimplifiedModelResult, SelectIncludeOmit as $SelectIncludeOmit } from "@zenstackhq/orm";
export type UserFindManyArgs = $FindManyArgs<$Schema, "User">;
export type UserFindUniqueArgs = $FindUniqueArgs<$Schema, "User">;
export type UserFindFirstArgs = $FindFirstArgs<$Schema, "User">;
export type UserCreateArgs = $CreateArgs<$Schema, "User">;
export type UserCreateManyArgs = $CreateManyArgs<$Schema, "User">;
export type UserCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "User">;
export type UserUpdateArgs = $UpdateArgs<$Schema, "User">;
export type UserUpdateManyArgs = $UpdateManyArgs<$Schema, "User">;
export type UserUpdateManyAndReturnArgs = $UpdateManyAndReturnArgs<$Schema, "User">;
export type UserUpsertArgs = $UpsertArgs<$Schema, "User">;
export type UserDeleteArgs = $DeleteArgs<$Schema, "User">;
export type UserDeleteManyArgs = $DeleteManyArgs<$Schema, "User">;
export type UserCountArgs = $CountArgs<$Schema, "User">;
export type UserAggregateArgs = $AggregateArgs<$Schema, "User">;
export type UserGroupByArgs = $GroupByArgs<$Schema, "User">;
export type UserWhereInput = $WhereInput<$Schema, "User">;
export type UserSelect = $SelectInput<$Schema, "User">;
export type UserInclude = $IncludeInput<$Schema, "User">;
export type UserOmit = $OmitInput<$Schema, "User">;
export type UserGetPayload<Args extends $SelectIncludeOmit<$Schema, "User", true>> = $SimplifiedModelResult<$Schema, "User", Args>;
export type ProfileFindManyArgs = $FindManyArgs<$Schema, "Profile">;
export type ProfileFindUniqueArgs = $FindUniqueArgs<$Schema, "Profile">;
export type ProfileFindFirstArgs = $FindFirstArgs<$Schema, "Profile">;
export type ProfileCreateArgs = $CreateArgs<$Schema, "Profile">;
export type ProfileCreateManyArgs = $CreateManyArgs<$Schema, "Profile">;
export type ProfileCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "Profile">;
export type ProfileUpdateArgs = $UpdateArgs<$Schema, "Profile">;
export type ProfileUpdateManyArgs = $UpdateManyArgs<$Schema, "Profile">;
export type ProfileUpdateManyAndReturnArgs = $UpdateManyAndReturnArgs<$Schema, "Profile">;
export type ProfileUpsertArgs = $UpsertArgs<$Schema, "Profile">;
export type ProfileDeleteArgs = $DeleteArgs<$Schema, "Profile">;
export type ProfileDeleteManyArgs = $DeleteManyArgs<$Schema, "Profile">;
export type ProfileCountArgs = $CountArgs<$Schema, "Profile">;
export type ProfileAggregateArgs = $AggregateArgs<$Schema, "Profile">;
export type ProfileGroupByArgs = $GroupByArgs<$Schema, "Profile">;
export type ProfileWhereInput = $WhereInput<$Schema, "Profile">;
export type ProfileSelect = $SelectInput<$Schema, "Profile">;
export type ProfileInclude = $IncludeInput<$Schema, "Profile">;
export type ProfileOmit = $OmitInput<$Schema, "Profile">;
export type ProfileGetPayload<Args extends $SelectIncludeOmit<$Schema, "Profile", true>> = $SimplifiedModelResult<$Schema, "Profile", Args>;
export type AddressFindManyArgs = $FindManyArgs<$Schema, "Address">;
export type AddressFindUniqueArgs = $FindUniqueArgs<$Schema, "Address">;
export type AddressFindFirstArgs = $FindFirstArgs<$Schema, "Address">;
export type AddressCreateArgs = $CreateArgs<$Schema, "Address">;
export type AddressCreateManyArgs = $CreateManyArgs<$Schema, "Address">;
export type AddressCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "Address">;
export type AddressUpdateArgs = $UpdateArgs<$Schema, "Address">;
export type AddressUpdateManyArgs = $UpdateManyArgs<$Schema, "Address">;
export type AddressUpdateManyAndReturnArgs = $UpdateManyAndReturnArgs<$Schema, "Address">;
export type AddressUpsertArgs = $UpsertArgs<$Schema, "Address">;
export type AddressDeleteArgs = $DeleteArgs<$Schema, "Address">;
export type AddressDeleteManyArgs = $DeleteManyArgs<$Schema, "Address">;
export type AddressCountArgs = $CountArgs<$Schema, "Address">;
export type AddressAggregateArgs = $AggregateArgs<$Schema, "Address">;
export type AddressGroupByArgs = $GroupByArgs<$Schema, "Address">;
export type AddressWhereInput = $WhereInput<$Schema, "Address">;
export type AddressSelect = $SelectInput<$Schema, "Address">;
export type AddressInclude = $IncludeInput<$Schema, "Address">;
export type AddressOmit = $OmitInput<$Schema, "Address">;
export type AddressGetPayload<Args extends $SelectIncludeOmit<$Schema, "Address", true>> = $SimplifiedModelResult<$Schema, "Address", Args>;
12 changes: 12 additions & 0 deletions tests/e2e/orm/schemas/default-auth/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//////////////////////////////////////////////////////////////////////////////////////////////
// DO NOT MODIFY THIS FILE //
// This file is automatically generated by ZenStack CLI and should not be manually updated. //
//////////////////////////////////////////////////////////////////////////////////////////////

/* eslint-disable */

import { type SchemaType as $Schema } from "./schema";
import { type ModelResult as $ModelResult } from "@zenstackhq/orm";
export type User = $ModelResult<$Schema, "User">;
export type Profile = $ModelResult<$Schema, "Profile">;
export type Address = $ModelResult<$Schema, "Address">;
122 changes: 122 additions & 0 deletions tests/e2e/orm/schemas/default-auth/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//////////////////////////////////////////////////////////////////////////////////////////////
// DO NOT MODIFY THIS FILE //
// This file is automatically generated by ZenStack CLI and should not be manually updated. //
//////////////////////////////////////////////////////////////////////////////////////////////

/* eslint-disable */

import { type SchemaDef, ExpressionUtils } from "@zenstackhq/orm/schema";
export const schema = {
provider: {
type: "sqlite"
},
models: {
User: {
name: "User",
fields: {
id: {
name: "id",
type: "Int",
id: true,
attributes: [{ name: "@id" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.call("autoincrement") }] }],
default: ExpressionUtils.call("autoincrement")
},
profile: {
name: "profile",
type: "Profile",
optional: true,
relation: { opposite: "user" }
}
},
idFields: ["id"],
uniqueFields: {
id: { type: "Int" }
}
},
Profile: {
name: "Profile",
fields: {
id: {
name: "id",
type: "Int",
id: true,
attributes: [{ name: "@id" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.call("autoincrement") }] }],
default: ExpressionUtils.call("autoincrement")
},
bio: {
name: "bio",
type: "String",
optional: true
},
userId: {
name: "userId",
type: "Int",
unique: true,
attributes: [{ name: "@unique" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"]) }] }],
default: ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"]),
foreignKeyFor: [
"user"
]
},
user: {
name: "user",
type: "User",
attributes: [{ name: "@relation", args: [{ name: "fields", value: ExpressionUtils.array([ExpressionUtils.field("userId")]) }, { name: "references", value: ExpressionUtils.array([ExpressionUtils.field("id")]) }] }],
relation: { opposite: "profile", fields: ["userId"], references: ["id"], hasDefault: true }
},
address: {
name: "address",
type: "Address",
optional: true,
attributes: [{ name: "@relation", args: [{ name: "fields", value: ExpressionUtils.array([ExpressionUtils.field("addressId")]) }, { name: "references", value: ExpressionUtils.array([ExpressionUtils.field("id")]) }] }],
relation: { opposite: "profile", fields: ["addressId"], references: ["id"] }
},
addressId: {
name: "addressId",
type: "Int",
unique: true,
optional: true,
attributes: [{ name: "@unique" }],
foreignKeyFor: [
"address"
]
}
},
idFields: ["id"],
uniqueFields: {
id: { type: "Int" },
userId: { type: "Int" },
addressId: { type: "Int" }
}
},
Address: {
name: "Address",
fields: {
id: {
name: "id",
type: "Int",
id: true,
attributes: [{ name: "@id" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.call("autoincrement") }] }],
default: ExpressionUtils.call("autoincrement")
},
city: {
name: "city",
type: "String"
},
profile: {
name: "profile",
type: "Profile",
optional: true,
relation: { opposite: "address" }
}
},
idFields: ["id"],
uniqueFields: {
id: { type: "Int" }
}
}
},
authType: "User",
plugins: {}
} as const satisfies SchemaDef;
export type SchemaType = typeof schema;
24 changes: 24 additions & 0 deletions tests/e2e/orm/schemas/default-auth/schema.zmodel
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
datasource db {
provider = "sqlite"
url = "file:./dev.db"
}

model User {
id Int @id @default(autoincrement())
profile Profile?
}

model Profile {
id Int @id @default(autoincrement())
bio String?
userId Int @unique @default(auth().id)
user User @relation(fields: [userId], references: [id])
address Address? @relation(fields: [addressId], references: [id])
addressId Int? @unique
}

model Address {
id Int @id @default(autoincrement())
city String
profile Profile?
}