feat(tailordb): type-level hooks/validators with issues() API and default support#1487
Draft
toiroakr wants to merge 6 commits into
Draft
feat(tailordb): type-level hooks/validators with issues() API and default support#1487toiroakr wants to merge 6 commits into
toiroakr wants to merge 6 commits into
Conversation
🦋 Changeset detectedLatest commit: f1b7b8c The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
This comment has been minimized.
This comment has been minimized.
Field and type-level hooks and validators are now compiled into a single per-type create/update script. Hooks receive a `now` (Date) shared across every field hooked in the same operation, so multiple fields can be stamped with one identical timestamp.
… preserve Create-input optionality The platform derives GraphQL Create-input optionality from the presence of a field-level create hook, not from type_hook. Emit a passthrough create hook (`_value`) per field so required hooked fields stay optional in input; the real shared-now logic in type_hook runs afterward and overwrites the value.
…oto field Add .default() builder method for TailorDBField with TypeLevelError type guards. Regenerate proto bindings to use optionalOnCreate instead of field-level hook placeholder, resolving type_hook coexistence conflict.
176cf40 to
21b053b
Compare
Code Metrics Report (packages/sdk)
Details | | main (fc572f3) | #1487 (a470092) | +/- |
|--------------------|----------------|-----------------|-------|
+ | Coverage | 70.7% | 70.8% | +0.1% |
| Files | 425 | 426 | +1 |
| Lines | 15503 | 15563 | +60 |
+ | Covered | 10967 | 11030 | +63 |
+ | Code to Test Ratio | 1:0.4 | 1:0.4 | +0.0 |
| Code | 106278 | 106539 | +261 |
+ | Test | 47984 | 48115 | +131 |Code coverage of files in pull request scope (77.0% → 77.8%)
SDK Configure Bundle Size
Runtime Performance
Type Performance (instantiations)
Reported by octocov |
…y field validators
- Add type-level validate function form to .validate() accepting (args, issues) callback
- Field validators now return string (error) | void (pass) instead of [fn, message] tuple
- Type-safe field path autocomplete for issues() via DottedPaths utility type
- Full pipeline: configure -> parser -> bundler -> snapshot -> manifest
- Hook functions use newRecord/oldRecord args matching platform _input/_oldRecord variables
- Field validators receive { newValue, oldValue } only
Comment on lines
+125
to
+129
| const chain = validators.map((v) => `(${v.script?.expr})`).join(" ?? "); | ||
| statements.push( | ||
| `{ const _value = ${access}; const _oldValue = ${oldAccess} ?? null;` + | ||
| ` const __r = ${chain}; if (typeof __r === "string") { __errs[${key(fieldPath)}] = __r; } }`, | ||
| ); |
Comment on lines
+259
to
+266
| Add hooks to execute functions during data creation or update. Hooks receive four arguments: | ||
|
|
||
| - `value`: User input if provided, otherwise existing value on update or null on create | ||
| - `data`: Entire record data (for accessing other field values) | ||
| - `data`: The submitted record data (for accessing other field values) | ||
| - `user`: User performing the operation | ||
| - `now`: Operation timestamp (`Date`). The same instant is shared by every field's hook in the same create/update, so multiple fields can be stamped with an identical timestamp. | ||
|
|
||
| All of a type's hooks run together as one operation and observe the same submitted input: `data` reflects what the client sent, so a hook does not see another field's hook result. Order between fields is not significant. |
Comment on lines
+5
to
+7
| Add a `now` argument to TailorDB hooks. `now` is the operation timestamp and is shared across every field hooked in the same create/update, so multiple fields can be stamped with an identical `Date`. Hooks and validators are now applied per type rather than per field, which is what makes the shared timestamp possible. | ||
|
|
||
| As part of this, all of a type's hooks now run together and observe the same submitted input: a hook's `data` reflects what the client sent and does not include other fields' hook results. |
Comment on lines
62
to
+66
| value: (data as Record<string, unknown>)[key], | ||
| data: data, | ||
| newRecord: data, | ||
| oldRecord: null, | ||
| user: unauthenticatedTailorUser, | ||
| now: new Date(), |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
type_hook/type_validate) instead of per-field scripts.now(Date) argument computed once per operation and shared across every field, so multiple fields can be stamped with an identical timestamp.datano longer reflects other fields' hook results. The previous per-field behavior was order-dependent and non-deterministic.newRecord/oldRecordarguments matching the platform_input/_oldRecordvariables..default()builder method forTailorDBFieldwithTypeLevelErrortype guards (prevents double-call, nested, serial). Defaults are applied after hooks on create only via?? defaultValuein the generated type-hook script. Datetime/date/time fields accept"now"to use the shared operation timestamp.tailor-proto) to includeoptionalOnCreatefield. UseoptionalOnCreate: trueinstead of the field-level hook placeholder (_value), resolving the platform validation error wheretype_hookand field-level hooks could not coexist.string(error message) orvoid(pass) instead of the previous[fn, "message"]tuple form. Validators receive{ newValue, oldValue }only (nouser, nodata)..validate((args, issues) => { ... }): accepts a function with{ newRecord, oldRecord, user }and anissues(field, message)callback for cross-field validation. Field path argument is type-checked viaDottedPaths<TData>utility type, providing autocomplete for top-level and nested field paths.type_hook/type_validateso hook/validator changes are detected as updates, and treats an empty field-levelvalidateas unset.