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
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-beta.18",
"version": "3.0.0-beta.19",
"description": "ZenStack",
"packageManager": "pnpm@10.20.0",
"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-beta.18",
"version": "3.0.0-beta.19",
"type": "module",
"author": {
"name": "ZenStack Team"
Expand Down
2 changes: 1 addition & 1 deletion packages/clients/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-beta.18",
"version": "3.0.0-beta.19",
"description": "TanStack Query Client for consuming ZenStack v3's CRUD service",
"main": "index.js",
"type": "module",
Expand Down
8 changes: 5 additions & 3 deletions packages/clients/tanstack-query/src/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import {
type ExtraMutationOptions,
type ExtraQueryOptions,
} from './utils/common';
import type { TrimDelegateModelOperations } from './utils/types';
import type { TrimDelegateModelOperations, WithOptimistic } from './utils/types';

export type { FetchFn } from './utils/common';

Expand Down Expand Up @@ -93,12 +93,14 @@ function useHooksContext() {

export type ModelQueryOptions<T> = Omit<UseQueryOptions<T, DefaultError>, 'queryKey'> & ExtraQueryOptions;

export type ModelQueryResult<T> = UseQueryResult<T, DefaultError> & { queryKey: QueryKey };
export type ModelQueryResult<T> = UseQueryResult<WithOptimistic<T>, DefaultError> & { queryKey: QueryKey };

export type ModelSuspenseQueryOptions<T> = Omit<UseSuspenseQueryOptions<T, DefaultError>, 'queryKey'> &
ExtraQueryOptions;

export type ModelSuspenseQueryResult<T> = UseSuspenseQueryResult<T, DefaultError> & { queryKey: QueryKey };
export type ModelSuspenseQueryResult<T> = UseSuspenseQueryResult<WithOptimistic<T>, DefaultError> & {
queryKey: QueryKey;
};

export type ModelInfiniteQueryOptions<T> = Omit<
UseInfiniteQueryOptions<T, DefaultError, InfiniteData<T>>,
Expand Down
6 changes: 4 additions & 2 deletions packages/clients/tanstack-query/src/svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import {
type ExtraMutationOptions,
type ExtraQueryOptions,
} from './utils/common';
import type { TrimDelegateModelOperations } from './utils/types';
import type { TrimDelegateModelOperations, WithOptimistic } from './utils/types';

export type { FetchFn } from './utils/common';

Expand Down Expand Up @@ -91,7 +91,9 @@ function getQuerySettings() {

export type ModelQueryOptions<T> = Omit<CreateQueryOptions<T, DefaultError>, 'queryKey'> & ExtraQueryOptions;

export type ModelQueryResult<T> = Readable<UnwrapStore<CreateQueryResult<T, DefaultError>> & { queryKey: QueryKey }>;
export type ModelQueryResult<T> = Readable<
UnwrapStore<CreateQueryResult<WithOptimistic<T>, DefaultError>> & { queryKey: QueryKey }
>;

export type ModelInfiniteQueryOptions<T> = Omit<
CreateInfiniteQueryOptions<T, DefaultError, InfiniteData<T>>,
Expand Down
11 changes: 11 additions & 0 deletions packages/clients/tanstack-query/src/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,14 @@ export type TrimDelegateModelOperations<
Model extends GetModels<Schema>,
T extends Record<string, unknown>,
> = IsDelegateModel<Schema, Model> extends true ? Omit<T, HooksOperationsIneligibleForDelegateModels> : T;

type WithOptimisticFlag<T> = T extends object
? T & {
/**
* Indicates if the item is in an optimistic update state
*/
$optimistic?: boolean;
}
: T;

export type WithOptimistic<T> = T extends Array<infer U> ? Array<WithOptimisticFlag<U>> : WithOptimisticFlag<T>;
4 changes: 2 additions & 2 deletions packages/clients/tanstack-query/src/vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import {
type ExtraMutationOptions,
type ExtraQueryOptions,
} from './utils/common';
import type { TrimDelegateModelOperations } from './utils/types';
import type { TrimDelegateModelOperations, WithOptimistic } from './utils/types';

export type { FetchFn } from './utils/common';
export const VueQueryContextKey = 'zenstack-vue-query-context';
Expand Down Expand Up @@ -86,7 +86,7 @@ export type ModelQueryOptions<T> = MaybeRefOrGetter<
Omit<UnwrapRef<UseQueryOptions<T, DefaultError>>, 'queryKey'> & ExtraQueryOptions
>;

export type ModelQueryResult<T> = UseQueryReturnType<T, DefaultError> & { queryKey: QueryKey };
export type ModelQueryResult<T> = UseQueryReturnType<WithOptimistic<T>, DefaultError> & { queryKey: QueryKey };

export type ModelInfiniteQueryOptions<T> = MaybeRefOrGetter<
Omit<UnwrapRef<UseInfiniteQueryOptions<T, DefaultError, InfiniteData<T>>>, 'queryKey' | 'initialPageParam'>
Expand Down
4 changes: 4 additions & 0 deletions packages/clients/tanstack-query/test/react-typing-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ check(client.user.useFindUnique({ select: { email: true } }).data.name);
check(client.user.useFindUnique({ where: { id: '1' }, include: { posts: true } }).data?.posts[0]?.title);

check(client.user.useFindFirst().data?.email);
check(client.user.useFindFirst().data?.$optimistic);

check(client.user.useFindMany().data?.[0]?.email);
check(client.user.useFindMany().data?.[0]?.$optimistic);

check(client.user.useInfiniteFindMany().data?.pages[0]?.[0]?.email);
check(
Expand All @@ -28,6 +30,8 @@ check(
},
).data?.pages[1]?.[0]?.email,
);
// @ts-expect-error
check(client.user.useInfiniteFindMany().data?.pages[0]?.[0]?.$optimistic);

check(client.user.useSuspenseFindMany().data[0]?.email);
check(client.user.useSuspenseInfiniteFindMany().data.pages[0]?.[0]?.email);
Expand Down
5 changes: 5 additions & 0 deletions packages/clients/tanstack-query/test/svelte-typing-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ check(get(client.user.useFindUnique({ select: { email: true } })).data.name);
check(get(client.user.useFindUnique({ where: { id: '1' }, include: { posts: true } })).data?.posts[0]?.title);

check(get(client.user.useFindFirst()).data?.email);
check(get(client.user.useFindFirst()).data?.$optimistic);

check(get(client.user.useFindMany()).data?.[0]?.email);
check(get(client.user.useFindMany()).data?.[0]?.$optimistic);

check(get(client.user.useInfiniteFindMany()).data?.pages[0]?.[0]?.email);
check(
get(
Expand All @@ -30,6 +33,8 @@ check(
),
).data?.pages[1]?.[0]?.email,
);
// @ts-expect-error
check(get(client.user.useInfiniteFindMany()).data?.pages[0]?.[0]?.$optimistic);

check(get(client.user.useCount()).data?.toFixed(2));
check(get(client.user.useCount({ select: { email: true } })).data?.email.toFixed(2));
Expand Down
4 changes: 4 additions & 0 deletions packages/clients/tanstack-query/test/vue-typing-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ check(client.user.useFindUnique({ select: { email: true } }).data.name);
check(client.user.useFindUnique({ where: { id: '1' }, include: { posts: true } }).data.value?.posts[0]?.title);

check(client.user.useFindFirst().data.value?.email);
check(client.user.useFindFirst().data.value?.$optimistic);

check(client.user.useFindMany().data.value?.[0]?.email);
check(client.user.useFindMany().data.value?.[0]?.$optimistic);

check(client.user.useInfiniteFindMany().data.value?.pages[0]?.[0]?.email);
check(
Expand All @@ -28,6 +30,8 @@ check(
},
).data.value?.pages[1]?.[0]?.email,
);
// @ts-expect-error
check(client.user.useInfiniteFindMany().data.value?.pages[0]?.[0]?.$optimistic);

check(client.user.useCount().data.value?.toFixed(2));
check(client.user.useCount({ select: { email: true } }).data.value?.email.toFixed(2));
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-beta.18",
"version": "3.0.0-beta.19",
"description": "ZenStack Common Helpers",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/config/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-beta.18",
"version": "3.0.0-beta.19",
"type": "module",
"private": true,
"license": "MIT"
Expand Down
2 changes: 1 addition & 1 deletion packages/config/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-beta.18",
"version": "3.0.0-beta.19",
"private": true,
"license": "MIT"
}
2 changes: 1 addition & 1 deletion packages/config/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-beta.18",
"version": "3.0.0-beta.19",
"private": true,
"license": "MIT",
"exports": {
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-beta.18",
"version": "3.0.0-beta.19",
"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-beta.18",
"version": "3.0.0-beta.19",
"description": "Kysely dialect for sql.js",
"type": "module",
"scripts": {
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-beta.18",
"version": "3.0.0-beta.19",
"license": "MIT",
"author": "ZenStack Team",
"files": [
Expand Down
2 changes: 1 addition & 1 deletion packages/orm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/orm",
"version": "3.0.0-beta.18",
"version": "3.0.0-beta.19",
"description": "ZenStack ORM",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/policy/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/plugin-policy",
"version": "3.0.0-beta.18",
"version": "3.0.0-beta.19",
"description": "ZenStack Policy Plugin",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/schema/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/schema",
"version": "3.0.0-beta.18",
"version": "3.0.0-beta.19",
"description": "ZenStack Runtime Schema",
"type": "module",
"scripts": {
Expand Down
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
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-beta.18",
"version": "3.0.0-beta.19",
"description": "ZenStack SDK",
"type": "module",
"scripts": {
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
2 changes: 1 addition & 1 deletion packages/server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/server",
"version": "3.0.0-beta.18",
"version": "3.0.0-beta.19",
"description": "ZenStack automatic CRUD API handlers and server adapters",
"type": "module",
"scripts": {
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-beta.18",
"version": "3.0.0-beta.19",
"description": "ZenStack Test Tools",
"type": "module",
"scripts": {
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-beta.18",
"version": "3.0.0-beta.19",
"description": "",
"type": "module",
"main": "index.js",
Expand Down
2 changes: 1 addition & 1 deletion samples/next.js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "next.js",
"version": "3.0.0-beta.18",
"version": "3.0.0-beta.19",
"private": true,
"scripts": {
"generate": "zen generate --lite",
Expand Down
2 changes: 1 addition & 1 deletion samples/orm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sample-blog",
"version": "3.0.0-beta.18",
"version": "3.0.0-beta.19",
"description": "",
"main": "index.js",
"private": true,
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,
});
});
});
Loading
Loading