github zenstackhq/zenstack v3.10.0
ZenStack Release v3.10.0

5 hours ago

New Features

Primitive Custom Types

Custom types can now be based on a scalar type, so you can reuse a set of validation rules across fields, arrays, and procedure inputs/outputs. Contributed by @sanny-io 🙌. #1455 #2526 doc

type UserName with String {
    this String @length(2, 16)
}

type Age with Int {
    this Int @gte(18)
}

model User {
    id   String   @id @default(nanoid())
    name UserName
    age  Age?     @default(18)
    tags UserName[]
}

Values are converted the same way as their base type (e.g. a BigInt-based custom type returns bigint).

Field-Level Update Policies on Many-to-Many Relations

@allow('update', ...) and @deny('update', ...) can now be put on implicit many-to-many relation fields to control connect / disconnect for that side of the relation. A field-level policy takes precedence over the model-level update policy. If there isn't one, the model-level policy applies as before. Contributed by @ludovicmotte 🙏. #2382 doc

model Activity {
    id    String @id @default(uuid())
    clubs Club[] @allow('update', auth() != null)

    @@allow('read', true)
}

Here Activity stays read-only, but signed-in users can link and unlink it from clubs.

Typed Per-Model Entity Mutation Hooks

Entity mutation hooks can now be registered per model, so the entities they load are strongly typed for that model. Per-model hooks run alongside $all hooks, and each model can set its own runAfterMutationWithinTransaction. Contributed by @genu 🎉. #2365 doc

const db = client.$use({
    id: 'audit',
    onEntityMutation: {
        User: {
            async afterEntityMutation(args) {
                // typed as User rows
                const users = await args.loadAfterMutationEntities();
            },
        },
        Post: {
            runAfterMutationWithinTransaction: true,
            async beforeEntityMutation(args) {
                const posts = await args.loadBeforeMutationEntities();
            },
        },
    },
});

Enum References in Policy and Validation Expressions

You can now use an enum as a list of its values in policy and validation rules, which is handy for checking a String field against an enum, including enums with @map-ed values. Contributed by @sanny-io. #1211 doc

enum PostStatus {
    DRAFT
    ACTIVE
    CANCELLED
}

model Post {
    id     String @id
    status String

    @@validate(status in PostStatus)
}

Graduated from Preview

The following features are now considered stable and are no longer marked as preview:

  • Custom procedures doc
  • Field-level access policies doc
  • JSON filters doc

⚠️ Breaking Changes

  • Catch-all entity mutation hooks moved under onEntityMutation.$all. Plugins that define beforeEntityMutation / afterEntityMutation / runAfterMutationWithinTransaction directly under onEntityMutation no longer type-check, so TypeScript users get a compile error until the hooks are moved under $all. At runtime the old shape is still supported, with a one-time deprecation warning. If both shapes are present, $all wins.
// before
const plugin = {
    id: 'audit',
    onEntityMutation: {
        afterEntityMutation(args) { ... },
    },
};

// after
const plugin = {
    id: 'audit',
    onEntityMutation: {
        $all: {
            afterEntityMutation(args) { ... },
        },
    },
};

Fixes and Improvements

  • [orm] updateMany now sets @updatedAt fields - by @ErikDakoda
  • [orm] Fixed deleteMany on a regular model deleting nothing when it's filtered by related polymorphic rows that it cascades to. limit is now supported in that case too
  • [orm] Fixed polymorphic model joins in relation subqueries shadowing outer tables #2870 - by @ErikDakoda
  • [orm] $expr filters now receive a modelAlias context argument, needed to reference the filtered model inside relation filters #2863 - by @Natansal-weme doc
  • [policy] Fixed before() comparisons on enum fields failing on PostgreSQL #2727 - by @theluckystrike
  • [language] Fixed incorrect field resolution scoping in vscode for @relation attribute #2746 - by @sanny-io
  • [language] Improved semantic highlighting for literals, enums, operators, function/procedure arguments, and regex patterns - by @sanny-io
  • Upgraded dependencies flagged by Dependabot

Thanks to @genu, @sanny-io, @ludovicmotte, @ErikDakoda, @Natansal-weme, and @theluckystrike for contributing to this release!

Full Changelog: v3.9.8...v3.10.0

Don't miss a new zenstack release

NewReleases is sending notifications on new releases.