Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
86 changes: 86 additions & 0 deletions guides/the-manual/schemas/derivations.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,89 @@ order: 7
---

# Derivations

Derivations are computed fields inside a ResourceSchema.
They allow you to define values that are derived from other fields or related resources, and they are automatically kept up to date when dependencies change.

## Creating a Derived Field

```ts [schemas/user.ts]
import { withDefaults } from '@warp-drive/core/reactive';

export const UserSchema = withDefaults({
type: 'user',
fields: [
{ name: 'firstName', kind: 'field' },
{ name: 'lastName', kind: 'field' },
{
name: 'fullName',
kind: 'derived',
type: 'concat',
options: { fields: ['firstName', 'lastName'], separator: ' ' }
}
]
});
```

Here, `fullName` automatically updates whenever `firstName` or `lastName` changes.
With Derivations, you can keep logic about derived values in the schema itself, ensuring consistency and reactivity across your application.

### Dependency Updates in Action

```ts
const user = store.cache.peek('user', '1');
console.log(user.fullName);
user.firstName = 'Grace';
console.log(user.fullName); //Reactive (auto-updated)
```

## Built-in Derivations

WarpDrive ships with a few built-in derivations such as:

- [`concat`](https://canary.warp-drive.io/api/@warp-drive/utilities/derivations/namespaces/concat/#concat) for joining multiple fields
- More derivations can be found in the [API docs](https://canary.warp-drive.io/api/@warp-drive/utilities/derivations/)

## Custom Derivations

You can create your own derivations by providing a compute function and register using [registerDerivations](https://canary.warp-drive.io/api/@warp-drive/core/reactive/functions/registerDerivations#function-registerderivations).

```ts [schemas/derivations/can-edit.ts]
export const CanEditDerivation = {
name: 'canEdit',
kind: 'derived',
type: 'boolean',
compute(user, cache) {
const permissions = cache.get(user, 'permissions');
return Array.isArray(permissions) && permissions.includes('edit');
}
};
```

## Registering a Custom Derivation

```ts [store/index.ts]
import { CanEditDerivation } from '../schemas/derivations/can-edit';

store.schema.registerDerivations([CanEditDerivation]);
```

Once registered, the `canEdit` derived field can be added to any ResourceSchema.

## Using a Custom Derivation in a ResourceSchema

```ts [schemas/user.ts]
import { withDefaults } from '@warp-drive/core/reactive';

export const UserSchema = withDefaults({
type: 'user',
fields: [
{ name: 'id', kind: '@id' },
{ name: 'firstName', kind: 'field' },
{ name: 'permissions', kind: 'field' },
{ name: 'canEdit', kind: 'derived', type: 'boolean' }
Copy link
Contributor

Choose a reason for hiding this comment

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

type here would be the name used to register the derivation so likely canEdit, perhaps choosing a different derivation name from field name will make this more clear

]
});
```

Now `user.canEdit` will reactively update whenever the `permissions` field changes.
65 changes: 65 additions & 0 deletions guides/the-manual/schemas/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,68 @@ order: 6
---

# Traits

Traits are reusable groups of fields that you can include in multiple ResourceSchemas.
They help keep schemas consistent and reduce duplication.

A Trait is defined as a plain object with fields, and then registered so it can be reused anywhere.

## Creating a Trait

```ts [schemas/traits/timestamps.ts]
export const Timestamps = {
fields: [
{ name: 'createdAt', kind: 'field', type: 'date-time' },
{ name: 'updatedAt', kind: 'field', type: 'date-time' }
]
};
```

## Registering a Trait

Once defined, register the trait with the SchemaService using [registerTrait](https://canary.warp-drive.io/api/@warp-drive/core/types/schema/schema-service/interfaces/SchemaService#registertrait)

```ts [store/index.ts]
import { store } from './store';
import { Timestamps } from './schemas/traits/timestamps';

store.schema.registerTrait('timestamps', Timestamps);
```

## Using a Trait in a ResourceSchema

```ts [schemas/user.ts]
import { withDefaults } from '@warp-drive/core/reactive';

export const UserSchema = withDefaults({
type: 'user',
fields: [
{ name: 'id', kind: '@id' },
{ name: 'name', kind: 'field' },
]
traits: ['timestamps']
});
```

The `timestamps` Trait is now mixed into the `user` ResourceSchema.

## Reuse Example

Traits can be shared across multiple schemas:

```ts [schemas/post.ts]
import { withDefaults } from '@warp-drive/core/reactive';

export const PostSchema = withDefaults({
type: 'post',
fields: [
{ name: 'id', kind: '@id' },
{ name: 'title', kind: 'field' }
],
traits: ['timestamps']
});
```

Both `UserSchema` and `PostSchema` now automatically include `createdAt` and `updatedAt`.

By registering and reusing Traits, you can apply consistent sets of fields such as audit information, metadata, or tracking properties across different ResourceSchemas without duplicating code.
Loading