Skip to content

Commit 00768de

Browse files
ymc9claude
andauthored
fix(orm): use uncapitalized model names in OmitConfig and ComputedFieldsOptions (#2496)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 397d2ab commit 00768de

File tree

8 files changed

+27
-24
lines changed

8 files changed

+27
-24
lines changed

packages/orm/src/client/client-impl.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ export class ClientImpl {
164164
for (const [modelName, modelDef] of Object.entries(this.$schema.models)) {
165165
if (modelDef.computedFields) {
166166
for (const fieldName of Object.keys(modelDef.computedFields)) {
167-
const modelConfig = computedFieldsConfig?.[modelName];
167+
// check both uncapitalized (current) and original (backward compat) model name
168+
const modelConfig = computedFieldsConfig?.[lowerCaseFirst(modelName)] ?? computedFieldsConfig?.[modelName];
168169
const fieldConfig = modelConfig?.[fieldName];
169170
// Check if the computed field has a configuration
170171
if (fieldConfig === null || fieldConfig === undefined) {

packages/orm/src/client/crud-types.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,10 @@ type OptionsLevelOmit<
121121
Model extends GetModels<Schema>,
122122
Field extends GetModelFields<Schema, Model>,
123123
Options extends QueryOptions<Schema>,
124-
> = Model extends keyof Options['omit']
125-
? Field extends keyof Options['omit'][Model]
126-
? Options['omit'][Model][Field] extends boolean
127-
? Options['omit'][Model][Field]
124+
> = Uncapitalize<Model> extends keyof Options['omit']
125+
? Field extends keyof Options['omit'][Uncapitalize<Model>]
126+
? Options['omit'][Uncapitalize<Model>][Field] extends boolean
127+
? Options['omit'][Uncapitalize<Model>][Field]
128128
: undefined
129129
: undefined
130130
: undefined;

packages/orm/src/client/crud/dialects/base-dialect.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { enumerate, invariant, isPlainObject } from '@zenstackhq/common-helpers';
1+
import { enumerate, invariant, isPlainObject, lowerCaseFirst } from '@zenstackhq/common-helpers';
22
import type { AliasableExpression, Expression, ExpressionBuilder, ExpressionWrapper, SqlBool, ValueNode } from 'kysely';
33
import { expressionBuilder, sql, type SelectQueryBuilder } from 'kysely';
44
import { match, P } from 'ts-pattern';
@@ -1160,12 +1160,12 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
11601160
return (omit as any)[field];
11611161
}
11621162

1163-
if (
1164-
this.options.omit?.[model] &&
1165-
typeof this.options.omit[model] === 'object' &&
1166-
typeof (this.options.omit[model] as any)[field] === 'boolean'
1167-
) {
1168-
return (this.options.omit[model] as any)[field];
1163+
// client-level: check both uncapitalized (current) and original (backward compat) model name
1164+
const uncapModel = lowerCaseFirst(model);
1165+
const omitConfig = (this.options.omit as Record<string, any> | undefined)?.[uncapModel] ??
1166+
(this.options.omit as Record<string, any> | undefined)?.[model];
1167+
if (omitConfig && typeof omitConfig === 'object' && typeof omitConfig[field] === 'boolean') {
1168+
return omitConfig[field];
11691169
}
11701170

11711171
// schema-level
@@ -1355,7 +1355,9 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
13551355
let computer: Function | undefined;
13561356
if ('computedFields' in this.options) {
13571357
const computedFields = this.options.computedFields as Record<string, any>;
1358-
computer = computedFields?.[fieldDef.originModel ?? model]?.[field];
1358+
// check both uncapitalized (current) and original (backward compat) model name
1359+
const computedModel = fieldDef.originModel ?? model;
1360+
computer = computedFields?.[lowerCaseFirst(computedModel)]?.[field] ?? computedFields?.[computedModel]?.[field];
13591361
}
13601362
if (!computer) {
13611363
throw createConfigError(`Computed field "${field}" implementation not provided for model "${model}"`);

packages/orm/src/client/options.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,13 +252,13 @@ export type ClientOptions<Schema extends SchemaDef> = QueryOptions<Schema> & {
252252
* Config for omitting fields in ORM query results.
253253
*/
254254
export type OmitConfig<Schema extends SchemaDef> = {
255-
[Model in GetModels<Schema>]?: {
255+
[Model in GetModels<Schema> as Uncapitalize<Model>]?: {
256256
[Field in GetModelFields<Schema, Model> as Field extends ScalarFields<Schema, Model> ? Field : never]?: boolean;
257257
};
258258
};
259259

260260
export type ComputedFieldsOptions<Schema extends SchemaDef> = {
261-
[Model in GetModels<Schema> as 'computedFields' extends keyof GetModel<Schema, Model> ? Model : never]: {
261+
[Model in GetModels<Schema> as 'computedFields' extends keyof GetModel<Schema, Model> ? Uncapitalize<Model> : never]: {
262262
[Field in keyof Schema['models'][Model]['computedFields']]: Schema['models'][Model]['computedFields'][Field] extends infer Func
263263
? Func extends (...args: any[]) => infer R
264264
? (

samples/orm/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ async function main() {
88
const db = new ZenStackClient(schema, {
99
dialect: new SqliteDialect({ database: new SQLite('./zenstack/dev.db') }),
1010
computedFields: {
11-
User: {
11+
user: {
1212
postCount: (eb, { modelAlias }) =>
1313
eb
1414
.selectFrom('Post')

tests/e2e/orm/client-api/computed-fields.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ model User {
191191
`,
192192
{
193193
computedFields: {
194-
User: {
194+
user: {
195195
upperName: (eb: any) => eb.fn('upper', ['name']),
196196
},
197197
},
@@ -204,7 +204,7 @@ async function main() {
204204
const client = new ZenStackClient(schema, {
205205
dialect: {} as any,
206206
computedFields: {
207-
User: {
207+
user: {
208208
upperName: (eb) => eb.fn('upper', ['name']),
209209
},
210210
}
@@ -263,7 +263,7 @@ model User {
263263
`,
264264
{
265265
computedFields: {
266-
User: {
266+
user: {
267267
upperName: (eb: any) => eb.lit(null),
268268
},
269269
},
@@ -276,7 +276,7 @@ async function main() {
276276
const client = new ZenStackClient(schema, {
277277
dialect: {} as any,
278278
computedFields: {
279-
User: {
279+
user: {
280280
upperName: (eb) => eb.lit(null),
281281
},
282282
}

tests/e2e/orm/client-api/omit.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ describe('Field omission tests', () => {
3737
});
3838

3939
it('respects client omit options', async () => {
40-
const options = { omit: { User: { name: true } }, dialect: {} as any } as const;
40+
const options = { omit: { user: { name: true } }, dialect: {} as any } as const;
4141
const db = await createTestClient<typeof schema, typeof options>(schema, options);
4242

4343
const user = await db.user.create({
@@ -66,7 +66,7 @@ describe('Field omission tests', () => {
6666

6767
it('allows override at query options level', async () => {
6868
// override schema-level omit
69-
const options = { omit: { User: { password: false } }, dialect: {} as any } as const;
69+
const options = { omit: { user: { password: false } }, dialect: {} as any } as const;
7070
const db = await createTestClient<typeof schema, typeof options>(schema, options);
7171
const user1 = await db.user.create({
7272
data: {
@@ -114,7 +114,7 @@ describe('Field omission tests', () => {
114114

115115
it('allows override at query level', async () => {
116116
// override options-level omit
117-
const options = { omit: { User: { name: true } }, dialect: {} as any } as const;
117+
const options = { omit: { user: { name: true } }, dialect: {} as any } as const;
118118
const db = await createTestClient<typeof schema, typeof options>(schema, options);
119119
const user5 = await db.user.create({
120120
data: { id: 2, name: 'User2', password: 'abc' },

tests/e2e/orm/schemas/typing/typecheck.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { schema } from './schema';
77
const client = new ZenStackClient(schema, {
88
dialect: new SqliteDialect({ database: new SQLite('./zenstack/test.db') }),
99
computedFields: {
10-
User: {
10+
user: {
1111
postCount: (eb) =>
1212
eb
1313
.selectFrom('Post')

0 commit comments

Comments
 (0)