diff --git a/docs/.gitignore b/docs/.gitignore index b2d6de306..023b6aa78 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -18,3 +18,12 @@ npm-debug.log* yarn-debug.log* yarn-error.log* + +# yarn +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions diff --git a/docs/.yarn/install-state.gz b/docs/.yarn/install-state.gz new file mode 100644 index 000000000..0f63abfd9 Binary files /dev/null and b/docs/.yarn/install-state.gz differ diff --git a/docs/.yarnrc.yml b/docs/.yarnrc.yml new file mode 100644 index 000000000..f384bc824 --- /dev/null +++ b/docs/.yarnrc.yml @@ -0,0 +1 @@ +yarnPath: ../.yarn/releases/yarn-3.5.0.cjs diff --git a/docs/docs/guides/acl-definition.md b/docs/docs/guides/acl-definition.md index b5aa82aa1..badf2e02e 100644 --- a/docs/docs/guides/acl-definition.md +++ b/docs/docs/guides/acl-definition.md @@ -13,14 +13,14 @@ export class Category { } export class Article { - category = def.manyHasOne(Category) + category = c.manyHasOne(Category) // .... } export class Comment { - article = def.manyHasOne(Article) - content = def.stringColumn() - hiddenAt = def.dateTimeColumn() + article = c.manyHasOne(Article) + content = c.stringColumn() + hiddenAt = c.dateTimeColumn() } ``` @@ -30,12 +30,12 @@ export class Comment { First, we create a public role using [createRole](/reference/engine/schema/acl.md#create-role) function. -There is only single mandatory argument - a role identifier. In second argument, we can define various role options, as described [here](/reference/engine/schema/acl.md#create-role). +There is only single mandatory argument - a role identifier. In second argument, we can define various role options, as described [here](/reference/engine/schema/acl.md#create-role). ```typescript -import { AclDefinition as acl } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' -export const publicRole = acl.createRole('public') +export const publicRole = c.createRole('public') ``` Second, we assign an access rule to a `Comment` entity using [allow](/reference/engine/schema/acl.md#allow) function. @@ -45,7 +45,7 @@ In `when` we define a predicate. In `read` there is an array of accessible field ```typescript // highlight-start -@acl.allow(publicRole, { +@c.Allow(publicRole, { read: ['content'], when: { hiddenAt: { isNull: true } }, }) @@ -62,7 +62,7 @@ That's all. Now, if you access the API with `public` role, you can see not hidde Now, we define a second mentioned role - a `moderator`. Again, we define a role: ```typescript -export const moderatorRole = acl.createRole('moderator') +export const moderatorRole = c.createRole('moderator') ``` Now it gets a bit more tricky, as we want to allow to only moderate comments in given category. @@ -70,7 +70,7 @@ Now it gets a bit more tricky, as we want to allow to only moderate comments in Let's define an [entity variable](#entity-variable), where a category ID (or a list of categories) will be stored for given user. ```typescript -export const categoryIdVariable = acl.createEntityVariable('categoryId', 'Category', moderatorRole) +export const categoryIdVariable = c.createEntityVariable('categoryId', 'Category', moderatorRole) ``` You can manage this variable [on memberships using Tenant API](/reference/engine/tenant/memberships.md) using its name - `categoryId`. @@ -79,7 +79,7 @@ Now we attach another ACL definition to our `Comment` entity: ```typescript // highlight-start -@acl.allow(moderatorRole, { +@c.Allow(moderatorRole, { update: ['hiddenAt', 'content'], when: { article: { category: { id: categoryIdVariable } } }, }) @@ -90,7 +90,7 @@ export class Comment { } ``` -As you can see, you can traverse through relations. Our definition says, that `moderator` can update fields `hiddenAt` and `content` of any `Comment` of an `Article` in a `Category` defined in `categoryId` variable. +As you can see, you can traverse through relations. Our definition says, that `moderator` can update fields `hiddenAt` and `content` of any `Comment` of an `Article` in a `Category` defined in `categoryId` variable. :::note migrations Don't forget to [create a migration](/reference/engine/migrations/basics.md) to apply changes: @@ -101,34 +101,34 @@ npm run contember migrations:diff my-blog setup-acl #### Full example: ```typescript -import { SchemaDefinition as def, Acldefinition as acl } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' -export const publicRole = acl.createRole('public') +export const publicRole = c.createRole('public') -export const moderatorRole = acl.createRole('moderator') -export const categoryIdVariable = acl.createEntityVariable('categoryId', 'Category', moderatorRole) +export const moderatorRole = c.createRole('moderator') +export const categoryIdVariable = c.createEntityVariable('categoryId', 'Category', moderatorRole) export class Category { // .... } export class Article { - category = def.manyHasOne(Category) + category = c.manyHasOne(Category) // .... } -@acl.allow(moderatorRole, { +@c.Allow(moderatorRole, { when: { article: { category: { id: categoryIdVariable } } }, update: ['hiddenAt', 'content'], }) -@acl.allow(publicRole, { +@c.Allow(publicRole, { when: { hiddenAt: { isNull: true } }, read: ['content'], }) export class Comment { - article = def.manyHasOne(Article) - content = def.stringColumn() - hiddenAt = def.dateTimeColumn() + article = c.manyHasOne(Article) + content = c.stringColumn() + hiddenAt = c.dateTimeColumn() } ``` diff --git a/docs/docs/guides/seo.md b/docs/docs/guides/seo.md index ca2d1de05..7efd90995 100644 --- a/docs/docs/guides/seo.md +++ b/docs/docs/guides/seo.md @@ -18,13 +18,13 @@ First, we have to define the schema. Here we have chosen four fields we want to For this, we define an entity in our schema with fields. We are making only the `title` field required (using the `.notNull()` call). We save it in a new file. ```tsx title="api/model/Seo.ts" -import { SchemaDefinition as def } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' export class Seo { - title = def.stringColumn().notNull() - description = def.stringColumn() - ogTitle = def.stringColumn() - ogDescription = def.stringColumn() + title = c.stringColumn().notNull() + description = c.stringColumn() + ogTitle = c.stringColumn() + ogDescription = c.stringColumn() } ``` @@ -41,7 +41,7 @@ To add SEO fields to all of these pages you can create a single `Seo` entity and To connect it to the `Article` entity we add the relation to the entity: ```tsx title="api/model/Article.ts" -import { SchemaDefinition as def } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' // highlight-next-line import { Seo } from './Seo' @@ -49,7 +49,7 @@ export class Article { // some specific fields… // highlight-next-line - seo = def.oneHasOne(Seo, 'article').notNull().removeOrphan() + seo = c.oneHasOne(Seo, 'article').notNull().removeOrphan() } ``` @@ -60,18 +60,18 @@ Note, that if you have already created some articles you can't mark this field a To specify the other side of the relation we add a field to the `Seo` entity we created earlier. ```tsx title="api/model/Seo.ts" -import { SchemaDefinition as def } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' // highlight-next-line import { Article } from './Article' export class Seo { - title = def.stringColumn().notNull() - description = def.stringColumn() - ogTitle = def.stringColumn() - ogDescription = def.stringColumn() + title = c.stringColumn().notNull() + description = c.stringColumn() + ogTitle = c.stringColumn() + ogDescription = c.stringColumn() // highlight-next-line - article = def.oneHasOneInverse(Article, 'seo') + article = c.oneHasOneInverse(Article, 'seo') } ``` @@ -82,11 +82,7 @@ To create migration for this we run `npm run contember migration:diff . add-seo` Now, we have these fields in our database and API, but we need to add them to our administration. To easily reuse them in different parts of our administration we can create a component that will encapsulate all the fields. We create a new file for it: ```tsx title="admin/components/Seo.tsx" -import { - Component, - TextAreaField, - TextField, -} from '@contember/admin' +import { Component, TextAreaField, TextField } from '@contember/admin' export const Seo = Component( () => ( @@ -127,11 +123,7 @@ Most of the time your article or page has a title that you use as a title in SEO First, let's modify our `Seo` component to take the name of the field we should copy the title from. ```tsx title="admin/components/Seo.tsx" -import { - Component, - TextAreaField, - TextField, -} from '@contember/admin' +import { Component, TextAreaField, TextField } from '@contember/admin' /* highlight-start */ interface SeoProps { @@ -156,11 +148,7 @@ export const Seo = Component( And then, when the prop is passed, we use the `DerivedFieldLink` component. Thus when the source field (title of the article) is edited, the change is mirrored in the derived fields (`seo.title` and `seo.ogTitle`). ```tsx title="admin/components/Seo.tsx" -import { - Component, - TextAreaField, - TextField, -} from '@contember/admin' +import { Component, TextAreaField, TextField } from '@contember/admin' interface SeoProps { titleField?: string diff --git a/docs/docs/intro/actions.mdx b/docs/docs/intro/actions.mdx index ea485a1e1..702f8ac47 100644 --- a/docs/docs/intro/actions.mdx +++ b/docs/docs/intro/actions.mdx @@ -16,17 +16,17 @@ While there's an extensive range of potential applications for Actions, we're go From our [previous steps](/intro/quickstart), we already have the schema. Imagine you want to send a Slack notification every time a new article is created. Here's how you'd modify the schema: ```javascript -import { SchemaDefinition as def, ActionsDefinition as actions } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' -@actions.trigger({ +@c.Trigger({ name: 'sent_to_slack', create: true, selection: `title`, webhook: 'https://example.com/send_to_slack', // we'll get to this later }) export class Article { - title = def.stringColumn() - content = def.stringColumn() + title = c.stringColumn() + content = c.stringColumn() } ``` diff --git a/docs/docs/intro/how-it-works.md b/docs/docs/intro/how-it-works.md index 0a1fb5ae7..e634698f0 100644 --- a/docs/docs/intro/how-it-works.md +++ b/docs/docs/intro/how-it-works.md @@ -38,18 +38,18 @@ Define your project's schema, which is then passed to the Contember Engine. Cont ```typescript // Post.ts -import { SchemaDefinition as def } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' -export const publicRole = acl.createRole('public') +export const publicRole = c.createRole('public') -@acl.allow(publicRole, { +@c.Allow(publicRole, { when: { publishedAt: { gte: 'now' } }, read: ['content'], }) export class Post { - title = def.stringColumn().notNull() - publishedAt = def.dateTimeColumn() - content = def.stringColumn().notNull() + title = c.stringColumn().notNull() + publishedAt = c.dateTimeColumn() + content = c.stringColumn().notNull() } ``` ### 2. GraphQL API Generation diff --git a/docs/docs/intro/quickstart.mdx b/docs/docs/intro/quickstart.mdx index e9b8a9c22..9e81060f7 100644 --- a/docs/docs/intro/quickstart.mdx +++ b/docs/docs/intro/quickstart.mdx @@ -47,7 +47,7 @@ your_project_name/ When we installed Contember it already created the structure above. Let's go to `api/model/index.ts` file. It looks like this: ```ts -import { SchemaDefinition as def } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' // export your model definition here @@ -67,11 +67,11 @@ For instance, if you were building a blog platform, some of the entities could b In this example, we'll define entity `Article` with two properties: `title` and `content`, which are both of type string. In real life we would obviously want it a bit different, but this is a very basic example designed to quickly show you how to work with Contember. ```ts title="api/model/index.ts" -import { SchemaDefinition as def } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' export class Article { - title = def.stringColumn() - content = def.stringColumn() + title = c.stringColumn() + content = c.stringColumn() } ``` diff --git a/docs/docs/intro/studio-quickstart.mdx b/docs/docs/intro/studio-quickstart.mdx index abcb1ad15..890949d14 100644 --- a/docs/docs/intro/studio-quickstart.mdx +++ b/docs/docs/intro/studio-quickstart.mdx @@ -82,22 +82,22 @@ In `api/model/index.ts` file you can find your application data model that AI bu Really simple example looks like this but you'll obviously have a more complicated one. ```ts title="api/model/index.ts" -import { SchemaDefinition as def } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' -@acl.allow(publicRole, { +@c.Allow(publicRole, { read: ['content'], when: { hiddenAt: { isNull: true } }, }) export class Article { - title = def.stringColumn() - content = def.stringColumn() - hiddenAt = def.dateTimeColumn() + title = c.stringColumn() + content = c.stringColumn() + hiddenAt = c.dateTimeColumn() } ``` Few notes: -1. Thanks to `import { SchemaDefinition as def }` you get TypeScript autocompletion. Just press ctrl+space in your editor and you'll what you can use for each entity. It will also underline any errors. +1. Thanks to `import { c }` you get TypeScript autocompletion. Just press ctrl+space in your editor and you'll what you can use for each entity. It will also underline any errors. 2. Schema consists of Entities. Each entity has columns with many supported types. 3. Above Entities you can find access control decorators which define what role can access what. diff --git a/docs/docs/reference/engine/actions/definition.md b/docs/docs/reference/engine/actions/definition.md index 80ac83d97..c6bb24319 100644 --- a/docs/docs/reference/engine/actions/definition.md +++ b/docs/docs/reference/engine/actions/definition.md @@ -19,9 +19,9 @@ To define a Watch Action, you employ decorator syntax. The `@watch` decorator is #### Example: Basic structure of a Watch Action definition: ```javascript -import { SchemaDefinition as def, ActionsDefinition as actions } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' -@actions.watch({ +@c.Watch({ name: 'action_name', watch: `fields_to_watch`, webhook: 'webhook_url', @@ -46,9 +46,9 @@ To define a Trigger Action, you attach the `@trigger` decorator to the entity cl #### Example: Basic structure of a Trigger Action definition: ```typescript -import { SchemaDefinition as def, ActionsDefinition as actions } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' -@actions.trigger({ +@c.Trigger({ name: 'action_name', create: true, delete: true, @@ -71,9 +71,9 @@ export class YourEntity { #### Example: Defining a Trigger Action ```javascript -import { SchemaDefinition as def, ActionsDefinition as actions } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' -@actions.trigger({ +@c.Trigger({ name: 'book_created', create: true, selection: ` @@ -85,8 +85,8 @@ import { SchemaDefinition as def, ActionsDefinition as actions } from '@contembe webhook: 'https://example.com/book/created', }) export class Book { - title = def.stringColumn(); - author = def.manyHasOne(Author); + title = c.stringColumn(); + author = c.manyHasOne(Author); } ``` @@ -99,9 +99,9 @@ By default, the payload that is sent to the webhook encapsulates the changes tha Example: Defining a selection within a watch ```typescript -import { SchemaDefinition as def, ActionsDefinition as actions } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' -@actions.watch({ +@c.Watch({ name: 'order_watch', watch: ` status @@ -132,9 +132,9 @@ The `webhook` property determines the URL where the webhook notification will be Instead of defining a simple string for the `webhook` property, you have the option to pass an object that allows for a more detailed configuration of the webhook. This feature gives you the ability to set additional headers, specify timeouts, manage retry attempts, and adjust the batching of webhook requests. Below is an example demonstrating how to leverage these advanced options: ```javascript -import { SchemaDefinition as def, ActionsDefinition as actions } from "@contember/schema-definition" +import { c } from "@contember/schema-definition" -@actions.watch({ +@c.Watch({ name: 'book_watch', watch: ` title @@ -177,9 +177,9 @@ Variables can be employed within the webhook URLs and header values of your Acti #### Example: Using variables in URL and headers: ```javascript -import {SchemaDefinition as def, ActionsDefinition as actions} from "@contember/schema-definition" +import { c } from "@contember/schema-definition" -@actions.watch({ +@c.Watch({ name: 'book_watch', watch: ` title @@ -211,15 +211,15 @@ The managementof these variables are explained in greater detail in the upcoming Contember enables the use of an alternative syntax that separates webhook targets for shared webhook configurations. This method promotes the reuse of identical webhook configurations across multiple Actions, granting flexibility for enabling or disabling watches, while preserving the target definition. Here's an example illustrating this syntax: ```javascript -import {SchemaDefinition as def, ActionsDefinition as actions} from "@contember/schema-definition" +import { c } from "@contember/schema-definition" -export const myOrderUpdateTarget = actions.createTarget({ +export const myOrderUpdateTarget = c.createActionsTarget({ name: 'my_order_update_target', type: 'webhook', url: 'http://localhost', }); -@actions.watch({ +@c.Watch({ target: myOrderUpdateTarget, name: '...', watch: '...', @@ -244,9 +244,9 @@ To assign priority for a `watch` or `trigger` action, include the `priority` pro Below is an example of assigning priority to a `watch` action: ```typescript -import { SchemaDefinition as def, ActionsDefinition as action } from "@contember/schema-definition" +import { c } from "@contember/schema-definition" -@action.watch({ +@c.Watch({ name: 'book_watch', watch: ` title diff --git a/docs/docs/reference/engine/actions/overview.md b/docs/docs/reference/engine/actions/overview.md index b2581c295..eb45acef7 100644 --- a/docs/docs/reference/engine/actions/overview.md +++ b/docs/docs/reference/engine/actions/overview.md @@ -9,9 +9,9 @@ Actions in Contember provide developers with a powerful way to keep track of ent To configure an Action, you need to employ the decorator syntax provided by Contember. Below is an example of an Action definition to demonstrate its structure: ```javascript -import { SchemaDefinition as def, ActionsDefinition as actions } from "@contember/schema-definition" +import { c } from "@contember/schema-definition" -@actions.watch({ +@c.Watch({ name: 'book_watch', watch: ` title @@ -22,9 +22,9 @@ import { SchemaDefinition as def, ActionsDefinition as actions } from "@contembe webhook: 'https://example.com/book/updated', }) export class Book { - title = def.stringColumn(); - tags = def.manyHasMany(Tag); - category = def.manyHasOne(Category); + title = c.stringColumn(); + tags = c.manyHasMany(Tag); + category = c.manyHasOne(Category); } ``` diff --git a/docs/docs/reference/engine/content/advanced/assume-identity.md b/docs/docs/reference/engine/content/advanced/assume-identity.md index a085747d1..2bd7a0576 100644 --- a/docs/docs/reference/engine/content/advanced/assume-identity.md +++ b/docs/docs/reference/engine/content/advanced/assume-identity.md @@ -28,9 +28,9 @@ To use this feature, you must first enable it for the role you are using by sett #### Example how to define a role with ability to assume an identity: ```typescript -export const adminRole = acl.createRole('admin', { +export const adminRole = c.createRole('admin', { system: { assumeIdentity: true, }, }) -``` +``` diff --git a/docs/docs/reference/engine/content/advanced/assume-membership.md b/docs/docs/reference/engine/content/advanced/assume-membership.md index 7cc43901e..15ce85a1c 100644 --- a/docs/docs/reference/engine/content/advanced/assume-membership.md +++ b/docs/docs/reference/engine/content/advanced/assume-membership.md @@ -58,7 +58,7 @@ To allow an identity to use the assume membership feature, the appropriate permi #### Example how to define a role with ability to assume a membership: ```typescript -export const authorRole = acl.createRole('author', { +export const authorRole = c.createRole('author', { content: { assumeMembership: {reader: true} } diff --git a/docs/docs/reference/engine/content/advanced/request-debugging.md b/docs/docs/reference/engine/content/advanced/request-debugging.md index 34ba0f359..736bbc158 100644 --- a/docs/docs/reference/engine/content/advanced/request-debugging.md +++ b/docs/docs/reference/engine/content/advanced/request-debugging.md @@ -11,7 +11,7 @@ In development mode, it is always enabled. On production, the `x-contember-debug Note that debugging information is only included in the response if the role used for the request has debugging enabled in its ACL definition. By default, the admin role has debugging enabled, but for other roles it must be explicitly enabled in the ACL definition. For example: ```typescript -export const editor = acl.createRole('editor', { +export const editor = c.createRole('editor', { debug: true, }) ``` diff --git a/docs/docs/reference/engine/content/queries.md b/docs/docs/reference/engine/content/queries.md index ca3395304..988daa878 100644 --- a/docs/docs/reference/engine/content/queries.md +++ b/docs/docs/reference/engine/content/queries.md @@ -8,11 +8,11 @@ Contember provides a GraphQL API for fetching and modifying data. There are thre For following entity: ```typescript -import { SchemaDefinition as def } from "@contember/schema-definition"; +import { c } from "@contember/schema-definition"; export class Post { - title = def.stringColumn().notNull(); - publishedAt = def.dateTimeColumn(); + title = c.stringColumn().notNull(); + publishedAt = c.dateTimeColumn(); } ``` @@ -71,7 +71,7 @@ query { } ``` -The "by" parameter allows you to filter by any unique column (or columns in case of a compound unique key). By default, the unique field is "id", but you can specify other unique fields using the `.unique()` method on the column or using the `@def.Unique(...)` class annotation. +The "by" parameter allows you to filter by any unique column (or columns in case of a compound unique key). By default, the unique field is "id", but you can specify other unique fields using the `.unique()` method on the column or using the `@c.Unique(...)` class annotation. You can then specify the fields you want to retrieve in the GraphQL query. In the example above, we are retrieving the "title" and "publishedAt" fields of the Post with the specified id. @@ -304,7 +304,7 @@ In addition to `asc` and `desc`, there are also `ascNullsFirst` and `descNullsLa When working with GraphQL, it is often necessary to traverse relationships between objects to retrieve the data needed. -#### Example +#### Example ```graphql query { listPost { @@ -320,7 +320,7 @@ query { } ``` -Additionally, you can traverse multiple levels of relationships by nesting fields within each other. +Additionally, you can traverse multiple levels of relationships by nesting fields within each other. #### Example how to retrieve the author of each post within a category: @@ -372,20 +372,20 @@ query { ## Narrowed has many -You can use the narrowed has many to filter a "has many" relation by a field of a compound unique key, where the second part of the unique key references the entity that you are querying. This allows you to access a specific record within the "has many" relation. +You can use the narrowed has many to filter a "has many" relation by a field of a compound unique key, where the second part of the unique key references the entity that you are querying. This allows you to access a specific record within the "has many" relation. For example, consider the following schema: ```typescript export class Category { - translations = d.oneHasMany(CategoryTranslation, 'category')) - internalNote = def.stringColumn() + translations = c.oneHasMany(CategoryTranslation, 'category') + internalNote = c.stringColumn() } -@d.Unique('category', 'locale') +@c.Unique('category', 'locale') export class CategoryTranslation { - category = d.manyHasOne(Category, 'translations').cascadeOnDelete().notNull() - locale = d.stringColumn().notNull() - name = d.stringColumn() + category = c.manyHasOne(Category, 'translations').cascadeOnDelete().notNull() + locale = c.stringColumn().notNull() + name = c.stringColumn() } ``` diff --git a/docs/docs/reference/engine/content/transfer.md b/docs/docs/reference/engine/content/transfer.md index 60d5b7a74..7ead12458 100644 --- a/docs/docs/reference/engine/content/transfer.md +++ b/docs/docs/reference/engine/content/transfer.md @@ -16,7 +16,7 @@ To use the `data:export` command, open a terminal window and navigate to the roo ``` npm run contember data:export [source-project] ``` -The source project argument is optional. If you leave it blank, the command will export data from the local project. If you want to export data from a remote project, you can specify the project using a DSN format like `contember://project:token@apiurl`. +The source project argument is optional. If you leave it blank, the command will export data from the local project. If you want to export data from a remote project, you can specify the project using a DSN format like `contember://project:token@apiurl`. For example: ``` @@ -47,7 +47,7 @@ To use the `data:import` command, open a terminal window and navigate to the roo ``` npm run contember data:import [target-project] ``` -The input file argument should be the path to the file containing the data you want to import. The target project argument is optional. If you leave it blank, the command will import the data into the local project. If you want to import the data into a remote project, you can specify the project using a DSN format like `contember://project:token@apiurl`. +The input file argument should be the path to the file containing the data you want to import. The target project argument is optional. If you leave it blank, the command will import the data into the local project. If you want to import the data into a remote project, you can specify the project using a DSN format like `contember://project:token@apiurl`. For example: ``` @@ -71,7 +71,7 @@ To use the `data:transfer` command, open a terminal window and navigate to the r ``` npm run contember data:transfer ``` -The source project and target project arguments should be the projects you want to transfer data between. You can specify a local project using a dot `.`, or a remote project using a DSN format like `contember://project:token@apiurl` +The source project and target project arguments should be the projects you want to transfer data between. You can specify a local project using a dot `.`, or a remote project using a DSN format like `contember://project:token@apiurl` For example: ``` @@ -125,7 +125,7 @@ curl --request POST \ ``` This will send a POST request to the `/export` endpoint with a bearer token in the `Authorization` header and a JSON body specifying the project you want to export. The exported data will be returned in the response body. -You can also use the `Content-Encoding: gzip` header to enable gzip compression for the export. +You can also use the `Content-Encoding: gzip` header to enable gzip compression for the export. # Data import @@ -153,7 +153,7 @@ The ability to import and export data is controlled by user roles and their perm For example, to grant the editor role the ability to export data but not import it, you could use following configuration: ```typescript -export const editorRole = acl.createRole('editor', { +export const editorRole = c.createRole('editor', { // ... content: { export: true, diff --git a/docs/docs/reference/engine/schema/acl.md b/docs/docs/reference/engine/schema/acl.md index 25b7b2d8c..a8d227837 100644 --- a/docs/docs/reference/engine/schema/acl.md +++ b/docs/docs/reference/engine/schema/acl.md @@ -4,7 +4,7 @@ title: Permissions and ACL Contember provides an easy way to create user roles with granular permission. -Using our declarative ACL, you can define not only row and column level permissions, but also cell level. In other words, you can define different conditions for accessing individual fields of a single row. +Using our declarative ACL, you can define not only row and column level permissions, but also cell level. In other words, you can define different conditions for accessing individual fields of a single row. In ACL definition, you use same filters you know from [Content API filters](/reference/engine/content/queries.md), so you can traverse through relations and build complex cross-entity rules. @@ -56,20 +56,20 @@ createRole(roleName, options) #### Function arguments: - `roleName`: a role identifier. You use this name in [Tenant API](/reference/engine/tenant/memberships.md) -- `options`: optional argument, where you can define [tenant](#tenant-permissions) and [system](#system-api-permissions) permissions. +- `options`: optional argument, where you can define [tenant](#tenant-permissions) and [system](#system-api-permissions) permissions. Each role must be exported from schema definition using `export const ...` #### Example: creating editorRole ```typescript -import { AclDefinition as acl } from '@contember/schema-definition' -export const editorRole = acl.createRole('editor') +import { c } from '@contember/schema-definition' +export const editorRole = c.createRole('editor') ``` #### Example: creating editorRole with additional options ```typescript -import { AclDefinition as acl } from '@contember/schema-definition' -export const editorRole = acl.createRole('editor', { +import { c } from '@contember/schema-definition' +export const editorRole = c.createRole('editor', { tenant: { invite: true, // ... @@ -98,9 +98,9 @@ createEntityVariable(variableName, entityName, role[, fallback]) #### Example: defining categoryId entity variable ```typescript -import { AclDefinition as acl } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' -export const categoryIdVariable = acl.createEntityVariable('categoryId', 'Category', editorRole) +export const categoryIdVariable = c.createEntityVariable('categoryId', 'Category', editorRole) ``` ### `createPredefinedVariable`: Defining a predefined variable {#create-predefined-variable} @@ -112,16 +112,16 @@ createConditionVariable(variableName, value, role[, fallback]) #### Function arguments: - `variableName`: a variable identifier. It must be unique for given role. You use this name in [Tenant API](/reference/engine/tenant/memberships.md) -- `value`: a value type passed to a variable, can be either `identityID` or `personID` +- `value`: a value type passed to a variable, can be either `identityID` or `personID` - `role`: a role reference (created using [createRole](#createrole)), for which this variable is defined. You can also pass an array of roles. - `fallback`: optional fallback condition, when a variable is not passed #### Example: defining personVariable predefined variable ```typescript -import { AclDefinition as acl } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' -export const personVariable = acl.createPredefinedVariable('person', 'personID', readerRole) +export const personVariable = c.createPredefinedVariable('person', 'personID', readerRole) ``` ### `createConditionVariable`: Defining a condition variable {#create-condition-variable} @@ -140,9 +140,9 @@ createConditionVariable(variableName, role[, fallback]) #### Example: defining subscriptionVariable condition variable ```typescript -import { AclDefinition as acl } from '@contember/schema-definition' +import { c } from '@contember/schema-definition' -export const subscriptionVariable = acl.createConditionVariable('subscription', readerRole) +export const subscriptionVariable = c.createConditionVariable('subscription', readerRole) ``` :::note @@ -273,4 +273,4 @@ import acl from './acl' export default { ...createSchema(model), acl } ``` -> Note, that this will override any ACL definition produced by decorators API. To combine these approaches, you must merge it deeply. +> Note, that this will override any ACL definition produced by decorators API. To combine these approaches, you must merge it deeply. diff --git a/docs/docs/reference/engine/schema/columns.md b/docs/docs/reference/engine/schema/columns.md index 777ac4d4a..76a66728e 100644 --- a/docs/docs/reference/engine/schema/columns.md +++ b/docs/docs/reference/engine/schema/columns.md @@ -8,8 +8,8 @@ To define columns in Contember, you can add properties to your entity class. Eac ```typescript export class Post { - title = def.stringColumn().notNull() - publishedAt = def.dateTimeColumn() + title = c.stringColumn().notNull() + publishedAt = c.dateTimeColumn() } ``` @@ -36,7 +36,7 @@ The type of column in PostgreSQL database can be changed using `.columnType(...) #### Example: changing database type of Json column ```typescript export class Post { - config = def.jsonColumn().columnType('json') + config = c.jsonColumn().columnType('json') } ``` ::: @@ -54,7 +54,7 @@ By default, columns are nullable, meaning that they can store a `null` value. Ho #### Example how to define a not-null string column: ```typescript -title = def.stringColumn().notNull() +title = c.stringColumn().notNull() ``` In this example, the title column is a string column that is defined as not nullable. This means that you must provide a value for the title column when you create a record in the Post entity. @@ -64,16 +64,16 @@ In this example, the title column is a string column that is defined as not null You can mark a column as unique by calling the `.unique()` method on it: ```typescript -slug = def.stringColumn().unique() +slug = c.stringColumn().unique() ``` You can also define composite unique keys by using a class decorator: ```typescript -@def.Unique("locale", "slug") +@c.Unique("locale", "slug") export class Post { - slug = def.stringColumn().notNull() - locale = def.stringColumn().notNull() + slug = c.stringColumn().notNull() + locale = c.stringColumn().notNull() } ``` @@ -90,18 +90,18 @@ To define ordinary non-unique index, you can use `Index` decorator in your schem #### Example how to define a single column index ```typescript -@def.Index('title') +@c.Index('title') export class Article { - title = def.stringColumn() + title = c.stringColumn() } ``` #### Example how to define a multi column index ```typescript -@def.Index('title', 'description') +@c.Index('title', 'description') export class Article { - title = def.stringColumn() - description = def.stringColumn() + title = c.stringColumn() + description = c.stringColumn() } ``` @@ -112,7 +112,7 @@ To change the name of a column in a database, you can use the `columnName` metho #### Example how to define a column with a custom column name: ```typescript -publishedAt = def.dateTimeColumn().columnName('published') +publishedAt = c.dateTimeColumn().columnName('published') ``` In this example, the publishedAt property is a date-time column that is defined with the column name `published`. This means that the column will be named `published` in the database, rather than `published_at`. @@ -130,7 +130,7 @@ However, you can use the columnType method to specify a custom column type in th #### Example how to use the columnType method to specify a custom column type in the database: ```typescript -config = def.jsonColumn().columnType('json') +config = c.jsonColumn().columnType('json') ``` In this example, the config property is a JSON column that is defined with the column type json in the database. This means that the config column will be of type json in the database, rather than the default jsonb type. @@ -140,7 +140,7 @@ The `default` method allows you to specify a default value for a column in your #### Example how to use the default method to specify a default value for a column: ```typescript -published = def.boolColumn().default(false) +published = c.boolColumn().default(false) ``` In this example, the published property is a boolean column that is defined with the default value false. This means that when a new record is created, the published column will be set to false if no value is explicitly provided. @@ -155,7 +155,7 @@ However, you can use the typeAlias method to specify a custom GraphQL type for a #### Example how to use the typeAlias method to specify a custom GraphQL type for a column: ```typescript -publishedAt = def.dateTimeColumn().typeAlias('CustomDateTime') +publishedAt = c.dateTimeColumn().typeAlias('CustomDateTime') ``` In this example, the publishedAt property is a date-time column that is mapped to the `CustomDateTime` GraphQL type in the schema. This means that the `publishedAt` column will be of type `CustomDateTime` in the GraphQL schema, rather than the default `DateTime` type. @@ -167,7 +167,7 @@ The `sequence` method allows you to enable a generated sequence on an integer co ### Example how to enable a sequence: ```typescript export class Task { - counter = def.intColumn().sequence().notNull() + counter = c.intColumn().sequence().notNull() } ``` :::caution @@ -179,7 +179,7 @@ You can also pass an optional configuration with start and precedence. The start #### Example of how to enable a sequence with different start and precedence: ```typescript export class Task { - counter = def.intColumn().notNull().sequence({ start: 1000, precedence: 'ALWAYS' }) + counter = c.intColumn().notNull().sequence({ start: 1000, precedence: 'ALWAYS' }) } ``` @@ -188,16 +188,16 @@ In this example, the counter column in the Task entity is defined as an integer ## Enums -Enums in Contember allow you to define a set of predefined values for a column in your entity schema. Enums can be used to limit the possible values that can be stored in a column, and can be useful for defining values that are used consistently throughout your application. The enum defined in a schema is mapped to a GraphQL enum. +Enums in Contember allow you to define a set of predefined values for a column in your entity schema. Enums can be used to limit the possible values that can be stored in a column, and can be useful for defining values that are used consistently throughout your application. The enum defined in a schema is mapped to a GraphQL enum. To define an enum, you can use the `createEnum` method. This method takes a list of string values, which will become the possible values of the enum. ### Example how to define an enum for a status column in a Task entity: ```typescript -export const TaskStatus = def.createEnum('pending', 'in_progress', 'completed') +export const TaskStatus = c.createEnum('pending', 'in_progress', 'completed') export class Task { - status = def.enumColumn(TaskStatus) + status = c.enumColumn(TaskStatus) } ``` diff --git a/docs/docs/reference/engine/schema/overview.md b/docs/docs/reference/engine/schema/overview.md index f8882019c..9b9f47f64 100644 --- a/docs/docs/reference/engine/schema/overview.md +++ b/docs/docs/reference/engine/schema/overview.md @@ -13,10 +13,10 @@ TODO: PICTURE OF PROJECT SCHEMA, MODEL SCHEMA, ACL SCHEMA AND INPUT VALIDATION S First let's look at the model schema, which is now the most important for us. -:::note -Make sure you have `SchemaDefinition` imported in each file +:::note +Make sure you have `c` imported in each file ```typescript -import { SchemaDefinition as def } from "@contember/schema-definition" +import { c } from "@contember/schema-definition" ``` ::: @@ -37,7 +37,7 @@ You don't have to define a primary key, because every entity has "id" column by ### Columns -See [columns chapter](columns.md). +See [columns chapter](columns.md). ### Relationships diff --git a/docs/docs/reference/engine/schema/relationships.md b/docs/docs/reference/engine/schema/relationships.md index 2c7fd9775..5bd3ce1c9 100644 --- a/docs/docs/reference/engine/schema/relationships.md +++ b/docs/docs/reference/engine/schema/relationships.md @@ -10,11 +10,11 @@ Let's define two entities - a *Category* and a *Post*: ```typescript export class Category { - name = def.stringColumn(); + name = c.stringColumn(); } export class Post { - title = def.stringColumn(); - content = def.stringColumn(); + title = c.stringColumn(); + content = c.stringColumn(); } ``` @@ -22,14 +22,14 @@ Now just add a relationship field to the *Post* entity definition: ```typescript export class Post { - title = def.stringColumn().notNull(); - content = def.stringColumn(); + title = c.stringColumn().notNull(); + content = c.stringColumn(); // highlight-next-line - category = def.manyHasOne(Category); + category = c.manyHasOne(Category); } ``` -That's all. In next sections, you'll find out how to setup inverse side, not null etc. +That's all. In next sections, you'll find out how to setup inverse side, not null etc. ## Types of relationships @@ -41,8 +41,8 @@ Owning side of this relationship references (at most) one entity, but that entit ![one has many relationship](/assets/one-has-many.svg) -- We define owning side of this relationship using `manyHasOne` method. -- Optionally, we define an inverse side using `oneHasMany` method. +- We define owning side of this relationship using `manyHasOne` method. +- Optionally, we define an inverse side using `oneHasMany` method. - Joining column with actual relationship value is located on owning side. - For this relationship, you can also configure: - [nullability](#nullability) on owning side @@ -51,9 +51,9 @@ Owning side of this relationship references (at most) one entity, but that entit #### Use case -This is probably the most common type of relationship. +This is probably the most common type of relationship. -An example is a *Post* having a many *PostComment*, but the *PostComment* belongs to one single *Post*. +An example is a *Post* having a many *PostComment*, but the *PostComment* belongs to one single *Post*. Here, the *PostComment* is owning side of this relationship, because it holds a *Post* identifier in its joining column. #### Example: Configuring only owning side @@ -61,10 +61,10 @@ Here, the *PostComment* is owning side of this relationship, because it holds a ```typescript export class PostComment { // highlight-next-line - post = def.manyHasOne(Post) + post = c.manyHasOne(Post) } export class Post { -} +} ``` #### Example: Configuring both owning and inverse side @@ -72,33 +72,33 @@ export class Post { ```typescript export class PostComment { // highlight-next-line - post = def.manyHasOne(Post, 'comments') + post = c.manyHasOne(Post, 'comments') } export class Post { // highlight-next-line - comments = def.oneHasMany(PostComment, 'post') + comments = c.oneHasMany(PostComment, 'post') } ``` ### Many-has-many -An owning entity can reference many inverse entities. Also, this inverse entity can be referenced from many owning entities. +An owning entity can reference many inverse entities. Also, this inverse entity can be referenced from many owning entities. ![many has many relationship](/assets/many-has-many.svg) -- Relationship is realized through a joining (also called junction) table. -- Although there is no joining column, we still recognize owning and inverse side (mainly for configuration purposes). -- We define owning side of this relationship using `manyHasMany` method. +- Relationship is realized through a joining (also called junction) table. +- Although there is no joining column, we still recognize owning and inverse side (mainly for configuration purposes). +- We define owning side of this relationship using `manyHasMany` method. - Optionally, we define an inverse side using `manyHasManyInverse` method. - For this relationship, you can also configure: - [default order](#default-order) on both sides - + #### Use case Useful when you need to just connect two entities without any additional metadata. -E.g. a *Post* has many *Tag*s, also there are many *Post*s of each *Tag*. -Downside is that you cannot attach any information on the relationship between them, e.g. you can't even sort *Tag*s of given *Post*. +E.g. a *Post* has many *Tag*s, also there are many *Post*s of each *Tag*. +Downside is that you cannot attach any information on the relationship between them, e.g. you can't even sort *Tag*s of given *Post*. In case you need such thing, you'd better create an extra entity representing the relationship (e.g. a *PostTag* referencing using ManyHasOne both *Post* and *Tag*) #### Example: Configuring only owning side @@ -106,10 +106,10 @@ In case you need such thing, you'd better create an extra entity representing th ```typescript export class Post { // highlight-next-line - tags = def.manyHasMany(Tag) + tags = c.manyHasMany(Tag) } export class Tag { -} +} ``` #### Example: Configuring both owning and inverse side @@ -117,12 +117,12 @@ export class Tag { ```typescript export class Post { // highlight-next-line - tags = def.manyHasMany(Tag, 'posts') + tags = c.manyHasMany(Tag, 'posts') } export class Category { // highlight-next-line - posts = def.manyHasManyInverse(Post, 'tags') + posts = c.manyHasManyInverse(Post, 'tags') } ``` @@ -130,20 +130,20 @@ export class Category { ```typescript export class Post { - tags = def.oneHasMany(PostTag, 'post') + tags = c.oneHasMany(PostTag, 'post') } export class PostTag { // highlight-next-line - post = def.manyHasOne(Post, 'tags').notNull().cascadeOnDelete() + post = c.manyHasOne(Post, 'tags').notNull().cascadeOnDelete() // highlight-next-line - tag = def.manyHasOne(Tag, 'posts').notNull().cascadeOnDelete() + tag = c.manyHasOne(Tag, 'posts').notNull().cascadeOnDelete() // highlight-next-line - order = def.intColumn() + order = c.intColumn() } export class Tag { - posts = def.oneHasMany(PostTag, 'tag') + posts = c.oneHasMany(PostTag, 'tag') } ``` @@ -153,21 +153,21 @@ There is at most one entity on each side of this relationship. ![one has one relationship](/assets/one-has-one.svg) -- We define owning side of this relationship using `oneHasOne` method. -- Optionally, we define an inverse side using `oneHasOneInverse` method. +- We define owning side of this relationship using `oneHasOne` method. +- Optionally, we define an inverse side using `oneHasOneInverse` method. - Joining column with actual relationship value is located on owning side. -- For this relationship, you can also configure +- For this relationship, you can also configure - [nullability](#nullability) on both sides - - [delete behaviour](#on-delete-behavior) on owning side + - [delete behaviour](#on-delete-behavior) on owning side - [orphan removal](#orphan-removal) on owning side #### Use case -Not as common, but sometimes useful type of relationship. -Imagine entities *Post* and *PostContent* - there is always single *PostContent* entity of each *Post* and a single *Post* for each *PostContent*. -In this case, it might seem a bit pointless - all fields *PostContent* entity can be safely inlined into *Post*. -Let's change it a bit - rename *PostContent* to *Content*. -Now we can reference this generic *Content* not only from a *Post*, but also from e.g. a *Category* and use same logic for storing, managing and rendering the *Content* of both entities. +Not as common, but sometimes useful type of relationship. +Imagine entities *Post* and *PostContent* - there is always single *PostContent* entity of each *Post* and a single *Post* for each *PostContent*. +In this case, it might seem a bit pointless - all fields *PostContent* entity can be safely inlined into *Post*. +Let's change it a bit - rename *PostContent* to *Content*. +Now we can reference this generic *Content* not only from a *Post*, but also from e.g. a *Category* and use same logic for storing, managing and rendering the *Content* of both entities. In this example, owning side would be in *Post* and *Category* entities, optional inverse side in *Content*. #### Example: Configuring only owning side @@ -175,7 +175,7 @@ In this example, owning side would be in *Post* and *Category* entities, optiona ```typescript export class Post { // highlight-next-line - content = def.oneHasOne(Content) + content = c.oneHasOne(Content) } export class Content { } @@ -186,12 +186,12 @@ export class Content { ```typescript export class Post { // highlight-next-line - content = def.oneHasOne(Content, 'post') + content = c.oneHasOne(Content, 'post') } export class Content { // highlight-next-line - post = def.oneHasOneInverse(Post, 'content') + post = c.oneHasOneInverse(Post, 'content') } ``` @@ -200,18 +200,18 @@ export class Content { ### Nullability You can also define `.notNull()` constraint for "one has one" relationships and owning side of "many has one" relationship. -This will ensure that there is an entity connected. +This will ensure that there is an entity connected. #### Example: making category of post not nullable ```typescript export class Post { // highlight-next-line - category = def.manyHasOne(Category).notNull(); + category = c.manyHasOne(Category).notNull(); } ``` ### On delete behavior -Using `.onDelete()` you can set what happens when referenced entity is deleted. +Using `.onDelete()` you can set what happens when referenced entity is deleted. E.g. you have a post, which is assigned to a category. When a category is deleted, three things can happen: - Restrict: this is default behavior. When you try to delete an entity, which is referenced from other entities, the delete operation will fail. @@ -220,8 +220,8 @@ E.g. you have a post, which is assigned to a category. When a category is delete Pay attention when you are choosing the strategy, because choosing a wrong strategy may lead to runtime errors or deleting more content than you wanted. -:::note -In database, all relationships are marked as "NO ACTION" and actual strategy is executed by Contember. +:::note +In database, all relationships are marked as "NO ACTION" and actual strategy is executed by Contember. This is because Contember can evaluate ACL rules. ::: @@ -232,7 +232,7 @@ This will delete Post entity when referenced Content is deleted. ```typescript export class Post { // highlight-next-line - content = def.oneHasOne(Content, 'post').cascadeOnDelete() + content = c.oneHasOne(Content, 'post').cascadeOnDelete() } ``` @@ -243,27 +243,27 @@ This will set content relationship to `null` when referenced Content is deleted ```typescript export class Post { // highlight-next-line - content = def.oneHasOne(Content, 'post').setNullOnDelete() + content = c.oneHasOne(Content, 'post').setNullOnDelete() } ``` ### Default order -You can use a method `.orderBy()` on "has many" relationships to set default order of this relationship. +You can use a method `.orderBy()` on "has many" relationships to set default order of this relationship. Of course, you can later override this order in a query. #### Example: sorting posts in a category by title ```typescript export class Category { - title = def.stringColumn(); + title = c.stringColumn(); // highlight-next-line - posts = def.oneHasMany(Post, "category").orderBy("title"); + posts = c.oneHasMany(Post, "category").orderBy("title"); } export class Post { - title = def.stringColumn().notNull(); - category = def.manyHasOne(Category, "posts"); + title = c.stringColumn().notNull(); + category = c.manyHasOne(Category, "posts"); } ``` @@ -271,9 +271,9 @@ export class Post { By calling this method multiple times, you can set subsequent order rules. ```typescript export class Category { - title = def.stringColumn(); + title = c.stringColumn(); // highlight-next-line - posts = def.oneHasMany(Post, "category").orderBy("title").orderBy('lead'); + posts = c.oneHasMany(Post, "category").orderBy("title").orderBy('lead'); } ``` ::: @@ -290,6 +290,6 @@ By enabling this option, *Content* will be removed once *Post* is removed. ```typescript export class Post { // highlight-next-line - content = def.oneHasOne(Content, 'post').removeOrphan() + content = c.oneHasOne(Content, 'post').removeOrphan() } ``` diff --git a/docs/docs/reference/engine/schema/tenant-acl.md b/docs/docs/reference/engine/schema/tenant-acl.md index d30fa3b08..752753f81 100644 --- a/docs/docs/reference/engine/schema/tenant-acl.md +++ b/docs/docs/reference/engine/schema/tenant-acl.md @@ -11,7 +11,7 @@ The `invite` permission controls the ability to invite other users to a project. #### Example: Simple Invite Permission ```typescript -export const editorRole = acl.createRole('editor', { +export const editorRole = c.createRole('editor', { tenant: { invite: true, }, @@ -19,7 +19,7 @@ export const editorRole = acl.createRole('editor', { ``` :::note -Before Engine 1.3, the `invite` and `unmanagedInvite` allowed only a boolean value. +Before Engine 1.3, the `invite` and `unmanagedInvite` allowed only a boolean value. ::: ### Engine 1.3+ Unmanaged Invite Permissions @@ -33,7 +33,7 @@ The `view` field enables you to specify which roles and their associated variabl #### Example: View Permissions ```typescript -export const editorRole = acl.createRole('editor', { +export const editorRole = c.createRole('editor', { tenant: { view: { editor: { @@ -53,7 +53,7 @@ The `manage` field helps you specify the roles and their variables that a user c #### Example: Manage Permissions ```typescript -export const editorRole = acl.createRole('editor', { +export const editorRole = c.createRole('editor', { tenant: { manage: { editor: { diff --git a/docs/docs/reference/engine/schema/validations.md b/docs/docs/reference/engine/schema/validations.md index ed64de6bb..c13fa49f6 100644 --- a/docs/docs/reference/engine/schema/validations.md +++ b/docs/docs/reference/engine/schema/validations.md @@ -5,15 +5,12 @@ title: Input validations Input validations are is a way to add more constraints to a field. They are specified using annotation on checked field. ```ts -import { - InputValidation as validation, - SchemaDefinition as def, -} from "@contember/schema-definition"; +import { c } from "@contember/schema-definition"; export class Article { // highlight-next-line - @validation.assertNotEmpty("Article title cannot be empty") - title = def.stringColumn().notNull(); + @c.AssertNotEmpty("Article title cannot be empty") + title = c.stringColumn().notNull(); } ``` diff --git a/docs/docs/reference/engine/schema/views.md b/docs/docs/reference/engine/schema/views.md index 48236e658..c548fb382 100644 --- a/docs/docs/reference/engine/schema/views.md +++ b/docs/docs/reference/engine/schema/views.md @@ -32,10 +32,10 @@ The first step is to write the SQL query representing the view. Ensure it adhere ### 2. Creating the View Entity -Use the `@def.View` decorator to wrap the SQL query. Then, define columns and relationships using Contember's standard methods. +Use the `@c.View` decorator to wrap the SQL query. Then, define columns and relationships using Contember's standard methods. :::note -View entities in Contember must hold the owning side of a relationship, so only `oneHasOne` and `manyHasOne` relations are allowed within them. +View entities in Contember must hold the owning side of a relationship, so only `oneHasOne` and `manyHasOne` relations are allowed within them. ::: Certainly! Here's a revised version that maintains the original structure but rewords the descriptions: @@ -44,7 +44,7 @@ Certainly! Here's a revised version that maintains the original structure but re Suppose you want to gather statistics on survey answers. You can define a view to handle this as follows: ```typescript -@d.View(` +@c.View(` SELECT gen_random_uuid() AS id, COUNT(*) as total_count, @@ -53,8 +53,8 @@ Suppose you want to gather statistics on survey answers. You can define a view t GROUP BY answer_id `) export class SurveyAnswerStats { - totalCount = d.intColumn().notNull() - answer = d.oneHasOne(SurveyAnswer, 'stats').notNull() + totalCount = c.intColumn().notNull() + answer = c.oneHasOne(SurveyAnswer, 'stats').notNull() } ``` @@ -64,9 +64,9 @@ The Inverse Side of the Relation in the Survey Answer Entity will look like this ```typescript export class SurveyAnswer { - survey = def.manyHasOne(Survey, 'answers').notNull() - answer = def.stringColumn() - stats = def.oneHasOneInverse(SurveyAnswerStats, 'answer') + survey = c.manyHasOne(Survey, 'answers').notNull() + answer = c.stringColumn() + stats = c.oneHasOneInverse(SurveyAnswerStats, 'answer') } ``` @@ -97,7 +97,7 @@ In Contember, if you are defining a view that relies on or selects data from ano #### Example: defining dependencies ```typescript -@d.View(`SELECT ....`, +@c.View(`SELECT ....`, { dependencies: () => [OrderSummary], }, @@ -106,8 +106,8 @@ In Contember, if you are defining a view that relies on or selects data from ano ### FAQs -**Q: Can I use any SQL function in the view?** +**Q: Can I use any SQL function in the view?** **A:** Yes, you can use any SQL function, but ensure that the output matches the defined Contember schema. -**Q: What happens if my mapping is incorrect?** +**Q: What happens if my mapping is incorrect?** **A:** Incorrect mapping between the SQL and the schema fields will result in runtime errors. diff --git a/docs/docs/reference/interface/data-binding/relationship-components.md b/docs/docs/reference/interface/data-binding/relationship-components.md index 3734e25d1..d016c17c3 100644 --- a/docs/docs/reference/interface/data-binding/relationship-components.md +++ b/docs/docs/reference/interface/data-binding/relationship-components.md @@ -69,12 +69,12 @@ To use the `Repeater` component, you must specify the `field` prop, which specif The example considers following model: ```typescript export class Question { - answers = def.oneHasMany(Answer, 'question') + answers = c.oneHasMany(Answer, 'question') } export class Answer { - question = def.manyHasOne(Question, 'answers') - answer = def.stringColumn() - order = def.intColumn() + question = c.manyHasOne(Question, 'answers') + answer = c.stringColumn() + order = c.intColumn() } ``` diff --git a/docs/package.json b/docs/package.json index 1767f6d55..de763f865 100644 --- a/docs/package.json +++ b/docs/package.json @@ -44,5 +44,6 @@ }, "engines": { "node": ">=18.0" - } + }, + "packageManager": "yarn@1.22.22" } diff --git a/docs/yarn.lock b/docs/yarn.lock index 9ae4d1219..9bcfad732 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -5037,9 +5037,9 @@ __metadata: linkType: hard "electron-to-chromium@npm:^1.4.796": - version: 1.4.796 - resolution: "electron-to-chromium@npm:1.4.796" - checksum: 29829ba285b2bb765e3abb82023b006f1d214333d045ab434b2c6be964c5ce0a761e992bd9eab09f51ac2b31712a5b003ed34cf891a627bf80f37e79ccddd6ac + version: 1.4.798 + resolution: "electron-to-chromium@npm:1.4.798" + checksum: 4ba9ef4bbe2c665a0e90a9944176aabc504fd14f3ebd70b96c5d7440d514010d2857875222801b1df19e5a44b9659774feb1d6d3bbf3b6c95a95b64afa5059f9 languageName: node linkType: hard @@ -6954,11 +6954,11 @@ __metadata: linkType: hard "jiti@npm:^1.20.0": - version: 1.21.3 - resolution: "jiti@npm:1.21.3" + version: 1.21.6 + resolution: "jiti@npm:1.21.6" bin: jiti: bin/jiti.js - checksum: c9d9d68704d7809d0ce68c86e620e4291b634b06a2623eebbbabe2568a28b2c78132f8621d099286ec0adc3def80a2a8397e9c6c0f978b09ea8d835e50e939ca + checksum: 9ea4a70a7bb950794824683ed1c632e2ede26949fbd348e2ba5ec8dc5efa54dc42022d85ae229cadaa60d4b95012e80ea07d625797199b688cc22ab0e8891d32 languageName: node linkType: hard