Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zenstack-v3",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"description": "ZenStack",
"packageManager": "[email protected]",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"publisher": "zenstack",
"displayName": "ZenStack CLI",
"description": "FullStack database toolkit with built-in access control and automatic API generation.",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"type": "module",
"author": {
"name": "ZenStack Team"
Expand Down
2 changes: 1 addition & 1 deletion packages/common-helpers/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/common-helpers",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"description": "ZenStack Common Helpers",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/create-zenstack/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-zenstack",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"description": "Create a new ZenStack project",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/dialects/sql.js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/kysely-sql-js",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"description": "Kysely dialect for sql.js",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-config/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/eslint-config",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"type": "module",
"private": true,
"license": "MIT"
Expand Down
2 changes: 1 addition & 1 deletion packages/ide/vscode/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "zenstack",
"publisher": "zenstack",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"displayName": "ZenStack Language Tools",
"description": "VSCode extension for ZenStack ZModel language",
"private": true,
Expand Down
2 changes: 1 addition & 1 deletion packages/language/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/language",
"description": "ZenStack ZModel language specification",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"license": "MIT",
"author": "ZenStack Team",
"files": [
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/runtime",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"description": "ZenStack Runtime",
"type": "module",
"scripts": {
Expand Down
7 changes: 3 additions & 4 deletions packages/runtime/src/client/crud-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -631,16 +631,15 @@ export type FindArgs<
skip?: number;
take?: number;
orderBy?: OrArray<OrderBy<Schema, Model, true, false>>;
}
} & Distinct<Schema, Model> &
Cursor<Schema, Model>
: {}) &
(AllowFilter extends true
? {
where?: WhereInput<Schema, Model>;
}
: {}) &
SelectIncludeOmit<Schema, Model, Collection> &
Distinct<Schema, Model> &
Cursor<Schema, Model>;
SelectIncludeOmit<Schema, Model, Collection>;

export type FindManyArgs<Schema extends SchemaDef, Model extends GetModels<Schema>> = FindArgs<Schema, Model, true>;
export type FindFirstArgs<Schema extends SchemaDef, Model extends GetModels<Schema>> = FindArgs<Schema, Model, false>;
Expand Down
53 changes: 29 additions & 24 deletions packages/runtime/src/client/crud/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -589,15 +589,7 @@ export class InputValidator<Schema extends SchemaDef> {
for (const field of Object.keys(modelDef.fields)) {
const fieldDef = requireField(this.schema, model, field);
if (fieldDef.relation) {
fields[field] = z
.union([
z.literal(true),
z.strictObject({
select: z.lazy(() => this.makeSelectSchema(fieldDef.type)).optional(),
include: z.lazy(() => this.makeIncludeSchema(fieldDef.type)).optional(),
}),
])
.optional();
fields[field] = this.makeRelationSelectIncludeSchema(fieldDef).optional();
} else {
fields[field] = z.boolean().optional();
}
Expand Down Expand Up @@ -634,6 +626,33 @@ export class InputValidator<Schema extends SchemaDef> {
return z.strictObject(fields);
}

private makeRelationSelectIncludeSchema(fieldDef: FieldDef) {
return z.union([
z.boolean(),
z.strictObject({
...(fieldDef.array || fieldDef.optional
? {
// to-many relations and optional to-one relations are filterable
where: z.lazy(() => this.makeWhereSchema(fieldDef.type, false)).optional(),
}
: {}),
select: z.lazy(() => this.makeSelectSchema(fieldDef.type)).optional(),
include: z.lazy(() => this.makeIncludeSchema(fieldDef.type)).optional(),
omit: z.lazy(() => this.makeOmitSchema(fieldDef.type)).optional(),
...(fieldDef.array
? {
// to-many relations can be ordered, skipped, taken, and cursor-located
orderBy: z.lazy(() => this.makeOrderBySchema(fieldDef.type, true, false)).optional(),
skip: this.makeSkipSchema().optional(),
take: this.makeTakeSchema().optional(),
cursor: this.makeCursorSchema(fieldDef.type).optional(),
distinct: this.makeDistinctSchema(fieldDef.type).optional(),
}
: {}),
}),
]);
}

private makeOmitSchema(model: string) {
const modelDef = requireModel(this.schema, model);
const fields: Record<string, ZodType> = {};
Expand All @@ -652,21 +671,7 @@ export class InputValidator<Schema extends SchemaDef> {
for (const field of Object.keys(modelDef.fields)) {
const fieldDef = requireField(this.schema, model, field);
if (fieldDef.relation) {
fields[field] = z
.union([
z.literal(true),
z.strictObject({
select: z.lazy(() => this.makeSelectSchema(fieldDef.type)).optional(),
include: z.lazy(() => this.makeIncludeSchema(fieldDef.type)).optional(),
omit: z.lazy(() => this.makeOmitSchema(fieldDef.type)).optional(),
where: z.lazy(() => this.makeWhereSchema(fieldDef.type, false)).optional(),
orderBy: z.lazy(() => this.makeOrderBySchema(fieldDef.type, true, false)).optional(),
skip: this.makeSkipSchema().optional(),
take: this.makeTakeSchema().optional(),
distinct: this.makeDistinctSchema(fieldDef.type).optional(),
}),
])
.optional();
fields[field] = this.makeRelationSelectIncludeSchema(fieldDef).optional();
}
}

Expand Down
93 changes: 92 additions & 1 deletion packages/runtime/test/client-api/find.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,97 @@ describe.each(createClientSpecs(PG_DB_NAME))('Client find tests for $provider',
expect(r?.posts[0]?.createdAt).toBeInstanceOf(Date);
expect(r?.posts[0]?.published).toBeTypeOf('boolean');

await expect(
client.user.findUnique({
where: { id: user.id },
select: {
posts: { where: { published: true }, select: { title: true }, orderBy: { createdAt: 'desc' } },
},
}),
).resolves.toMatchObject({
posts: [expect.objectContaining({ title: 'Post1' })],
});
await expect(
client.user.findUnique({
where: { id: user.id },
include: {
posts: { where: { published: true }, select: { title: true }, orderBy: { createdAt: 'desc' } },
},
}),
).resolves.toMatchObject({
posts: [expect.objectContaining({ title: 'Post1' })],
});

await expect(
client.user.findUnique({
where: { id: user.id },
select: {
posts: { orderBy: { title: 'asc' }, skip: 1, take: 1, distinct: ['title'] },
},
}),
).resolves.toMatchObject({
posts: [expect.objectContaining({ title: 'Post2' })],
});
await expect(
client.user.findUnique({
where: { id: user.id },
include: {
posts: { orderBy: { title: 'asc' }, skip: 1, take: 1, distinct: ['title'] },
},
}),
).resolves.toMatchObject({
posts: [expect.objectContaining({ title: 'Post2' })],
});

await expect(
client.post.findFirst({
select: { author: { select: { email: true } } },
}),
).resolves.toMatchObject({
author: { email: expect.any(String) },
});
await expect(
client.post.findFirst({
include: { author: { select: { email: true } } },
}),
).resolves.toMatchObject({
author: { email: expect.any(String) },
});

await expect(
client.user.findUnique({
where: { id: user.id },
select: {
profile: { where: { bio: 'My bio' } },
},
}),
).resolves.toMatchObject({ profile: expect.any(Object) });
await expect(
client.user.findUnique({
where: { id: user.id },
include: {
profile: { where: { bio: 'My bio' } },
},
}),
).resolves.toMatchObject({ profile: expect.any(Object) });

await expect(
client.user.findUnique({
where: { id: user.id },
select: {
profile: { where: { bio: 'Other bio' } },
},
}),
).resolves.toMatchObject({ profile: null });
await expect(
client.user.findUnique({
where: { id: user.id },
include: {
profile: { where: { bio: 'Other bio' } },
},
}),
).resolves.toMatchObject({ profile: null });

await expect(
client.user.findUnique({
where: { id: user.id },
Expand Down Expand Up @@ -778,7 +869,7 @@ describe.each(createClientSpecs(PG_DB_NAME))('Client find tests for $provider',
// @ts-expect-error
include: { author: { where: { email: user.email } } },
}),
).rejects.toThrow(`Field "author" doesn't support filtering`);
).rejects.toThrow(`Invalid find args`);

// sorting
let u = await client.user.findUniqueOrThrow({
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/sdk",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"description": "ZenStack SDK",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/tanstack-query/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/tanstack-query",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"description": "",
"main": "index.js",
"type": "module",
Expand Down
2 changes: 1 addition & 1 deletion packages/testtools/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/testtools",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"description": "ZenStack Test Tools",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript-config/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/typescript-config",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"private": true,
"license": "MIT"
}
2 changes: 1 addition & 1 deletion packages/vitest-config/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/vitest-config",
"type": "module",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"private": true,
"license": "MIT",
"exports": {
Expand Down
2 changes: 1 addition & 1 deletion packages/zod/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/zod",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"description": "",
"type": "module",
"main": "index.js",
Expand Down
2 changes: 1 addition & 1 deletion samples/blog/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sample-blog",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"description": "",
"main": "index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "e2e",
"version": "3.0.0-alpha.25",
"version": "3.0.0-alpha.26",
"private": true,
"type": "module",
"scripts": {
Expand Down