Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Comments

feat:customId function#2377

Open
sanny-io wants to merge 9 commits intozenstackhq:devfrom
sanny-io:feat/custom-id
Open

feat:customId function#2377
sanny-io wants to merge 9 commits intozenstackhq:devfrom
sanny-io:feat/custom-id

Conversation

@sanny-io
Copy link
Contributor

@sanny-iosanny-io commentedFeb 12, 2026
edited
Loading

Allows developers to specify a custom implementation of an ID generation function.

Sample Usage

modelUser {idString@id@default(customId())// length chosen by implementation}modelPost {idString@id@default(customId(8))// length chosen by schema}
exportconstdb=newZenStackClient(schema,{dialect:newSqliteDialect({database:newSQLite(':memory:'),}),customId:({ model, length, client})=>{return ...},});

Closes#2348
Prisma issues:prisma/prisma#6719

Summary by CodeRabbit

  • New Features

    • Configurable custom ID generation via a client-supplied function, with optional length.
    • Default ID generation now receives per-entity and per-field context so IDs can vary by entity/field.
    • Runtime checks ensure a provided length is a positive number and generated IDs are non-empty strings.
  • Tests

    • Added unit tests for length validation.
    • Added end-to-end tests covering custom ID outputs, nested creations, and missing/invalid implementation cases.

oriole-pub reacted with hooray emojioriole-pub reacted with rocket emoji
@coderabbitai
Copy link
Contributor

coderabbitaibot commentedFeb 12, 2026
edited
Loading

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing thereviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new default-value generatorcustomId(length: Int?): language declaration and validation, ORM client option and types for a user-provided generator, wiring of model+field context into default-value evaluation, and end-to-end tests covering success and failure scenarios.

Changes

Cohort / File(s)Summary
Language Layer
packages/language/res/stdlib.zmodel,packages/language/src/validators/function-invocation-validator.ts,packages/language/test/function-invocation.test.ts
Declared publiccustomId(length: Int?) with@@@expressionContext([DefaultValue]). Added validator forcustomId to ensure optional length is a positive number. Added tests asserting non‑positive lengths are rejected.
ORM Client — Types & Options
packages/orm/src/client/options.ts
ExportedCustomIdFunctionContext<Schema> andCustomIdFunction<Schema> types. ExtendedClientOptions<Schema> with optionalcustomId?: CustomIdFunction<Schema> and inline docs describing usage with@default(customId()).
ORM Client — Default Generation Logic
packages/orm/src/client/crud/operations/base.ts
UpdatedBaseOperationHandler.evalGenerator signature to accept(defaultValue, model, field). ImplementedcustomId generator handling: requiresclient.options.customId, calls it with{ client, model, field, length? }, and enforces a non-empty string return. Updated call sites to pass model and field.
End-to-end Tests
tests/e2e/orm/client-api/custom-id.test.ts
Added E2E tests covering default IDs, custom length, nested/deep create behavior, and failure cases whencustomId is missing or returns invalid values (undefined, empty, non-string).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I nibble code and weave a name,
For models and fields I stake my claim.
Give length or none, I hop and make,
A tiny string for records' sake.
Sniff, stamp, bounce — your IDs awake!

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 inconclusive)
Check nameStatusExplanationResolution
Linked Issues check❓ InconclusiveThe PR addresses issue#2348 by enabling custom ID generation, but implements a generic customId function rather than the requested nanoid custom alphabet feature.Clarify whether the customId function fully satisfies issue#2348's requirements or if nanoid custom alphabet support should be added as a follow-up.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title 'feat:customId function' is clear and directly related to the main change: adding a new customId function for custom ID generation.
Out of Scope Changes check✅ PassedAll changes are directly related to implementing the customId function: stdlib declaration, validation, tests, type definitions, and runtime implementation.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for usingCodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment@coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitaicoderabbitaibot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@tests/e2e/orm/client-api/custom-id.test.ts`:- Around line 140-160: Remove the unnecessary `@ts-expect-error` comments thatprecede the assertion lines invoking client.user.create in the test (these arethe three occurrences after each createTestClient call where you do awaitexpect(client.user.create({ data: {} })).rejects.toThrowError(...)); leave thevalid `@ts-expect-error` comments that suppress the type errors on the customIdfunction arguments intact, and run typecheck to confirm no other TS errors areintroduced.
🧹 Nitpick comments (3)
packages/language/src/validators/function-invocation-validator.ts (1)

240-252:Duplicated logic with_checkNanoid.

_checkCustomId is identical to_checkNanoid (lines 226–238). Consider extracting a shared helper like_checkPositiveFirstArg to avoid the duplication.

♻️ Proposed refactor
+    private _checkPositiveFirstArg(expr: InvocationExpr, accept: ValidationAcceptor) {+        const lengthArg = expr.args[0]?.value;+        if (lengthArg) {+            const length = getLiteral<number>(lengthArg);+            if (length !== undefined && length <= 0) {+                accept('error', 'first argument must be a positive number', {+                    node: expr.args[0]!,+                });+            }+        }+    }+     `@func`('nanoid')     private _checkNanoid(expr: InvocationExpr, accept: ValidationAcceptor) {-        // first argument must be positive if provided-        const lengthArg = expr.args[0]?.value;-        if (lengthArg) {-            const length = getLiteral<number>(lengthArg);-            if (length !== undefined && length <= 0) {-                accept('error', 'first argument must be a positive number', {-                    node: expr.args[0]!,-                });-            }-        }+        this._checkPositiveFirstArg(expr, accept);     }      `@func`('customId')     private _checkCustomId(expr: InvocationExpr, accept: ValidationAcceptor) {-        // first argument must be positive if provided-        const lengthArg = expr.args[0]?.value;-        if (lengthArg) {-            const length = getLiteral<number>(lengthArg);-            if (length !== undefined && length <= 0) {-                accept('error', 'first argument must be a positive number', {-                    node: expr.args[0]!,-                });-            }-        }+        this._checkPositiveFirstArg(expr, accept);     }
packages/language/test/function-invocation.test.ts (1)

418-434:Test coverage is incomplete compared to thenanoid() suite.

Thenanoid() length validation tests (lines 362–416) cover both positive acceptance and rejection of0 and-1. This suite only checks-1. Consider adding a positive-length acceptance test and acustomId(0) rejection test for parity.

tests/e2e/orm/client-api/custom-id.test.ts (1)

24-24:Unnecessaryasync ondescribe callback.

Thedescribe block doesn't use top-levelawait, so theasync modifier is unnecessary and could be removed.

@sanny-io
Copy link
ContributorAuthor

@ymc9 only non-empty strings are allowed at the moment. Should the restrictions be relaxed, or maybe tightened?

Not sure if, for example, a string full of only whitespaces could cause issues.

Copy link
Contributor

@coderabbitaicoderabbitaibot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@packages/orm/src/client/crud/operations/base.ts`:- Around line 1098-1109: The current use of invariant in the customId generationpath (the with('customId', ...) block that calls this.client.$options.customId)loses error messages in production; replace those invariant calls with apreserved-message error constructor (e.g., call createInvalidInputError orcreateInternalError) so users see meaningful messages if customId is missing orreturns a non-string. Specifically, where the code currently doesinvariant(this.client.$options.customId, ...) and invariant(generated && typeofgenerated === 'string', ...), throw a new preserved-message error (usingcreateInvalidInputError/createInternalError) with the same descriptive text andinclude context (model, field, length) as appropriate to aid debugging.- Line 1107: The validation for generated custom IDs in base.ts currently onlychecks `generated && typeof generated === 'string'`, which permitswhitespace-only strings; update the check used around the invariant (the`generated` validation for "customId") to ensure the string is not allwhitespace by using a trimmed-length test (e.g., verify `typeof generated ==='string' && generated.trim().length > 0`) before calling invariant, and ifwhitespace-only IDs are intentionally allowed, add a clear comment documentingthat exception near the `customId` handling.
🧹 Nitpick comments (2)
packages/orm/src/client/options.ts (2)

43-65:model could useGetModels<Schema> for stronger typing.

ZModelFunctionContext on line 24 typesmodel asGetModels<Schema>, butCustomIdFunctionContext uses a plainstring. UsingGetModels<Schema> would give consumers autocomplete and type checking on the model name.

Also, minor grammar nit: lines 50 and 55 say "for which the ID should be generatedfor" — the trailing "for" is redundant.

Proposed fix
 export type CustomIdFunctionContext<Schema extends SchemaDef> = {     /**      * ZenStack client instance.      */     client: ClientContract<Schema>;      /**-     * The model for which the ID should be generated for.+     * The model for which the ID should be generated.      */-    model: string;+    model: GetModels<Schema>;      /**-     * The field for which the ID should be generated for.+     * The field for which the ID should be generated.      */     field: string;      /**      * The length of the ID as requested by the schema.      */     length?: number; };

65-65:CustomIdFunction is synchronous — async ID generation is unsupported.

Returningstring (notstring | Promise<string>) prevents users from generating IDs via async sources (e.g., a remote ID service, DB sequence lookup). SincefillGeneratedAndDefaultValues andevalGenerator inbase.ts are both synchronous, this would need broader changes to support, but it's worth flagging as a potential limitation consumers may hit.

If you don't plan to support async generation now, consider documenting this limitation in the JSDoc. If you do want to support it,evalGenerator andfillGeneratedAndDefaultValues would need to become async.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@coderabbitaicoderabbitai[bot]coderabbitai[bot] left review comments

At least 1 approving review is required to merge this pull request.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

nanoid support custom alphabet

1 participant

@sanny-io

[8]ページ先頭

©2009-2026 Movatter.jp