docs: revamped endpoints, services, and entities (#4660)

* revamp create endpoint docs

* docs: revamped endpoints, services, and entities

* eslint fixes

* fix metadata

* fix missing closing tag

* fixes to create migration doc

* fixes to create endpoint doc

* small fix in create service doc
This commit is contained in:
Shahed Nasser
2023-08-01 19:36:56 +03:00
committed by GitHub
parent 6c885ac2d6
commit c90191eb7e
11 changed files with 2092 additions and 694 deletions

View File

@@ -1,194 +0,0 @@
---
description: 'Learn how to create an entity in Medusa. This guide also explains how to create a repository and access and delete the entity.'
addHowToData: true
---
# How to Create an Entity
In this document, youll learn how you can create a custom [Entity](./overview.mdx).
## Step 1: Create the Entity
To create an entity, create a TypeScript file in `src/models`. For example, heres a `Post` entity defined in the file `src/models/post.ts`:
```ts title=src/models/post.ts
import {
BeforeInsert,
Column,
Entity,
PrimaryColumn,
} from "typeorm"
import { BaseEntity } from "@medusajs/medusa"
import { generateEntityId } from "@medusajs/medusa/dist/utils"
@Entity()
export class Post extends BaseEntity {
@Column({ type: "varchar" })
title: string | null
@BeforeInsert()
private beforeInsert(): void {
this.id = generateEntityId(this.id, "post")
}
}
```
This entity has one column `title` defined. However, since it extends `BaseEntity` it will also have the `id`, `created_at`, and `updated_at` columns.
Medusas core entities all have the following format for IDs: `<PREFIX>_<RANDOM>`. For example, an order might have the ID `order_01G35WVGY4D1JCA4TPGVXPGCQM`.
To generate an ID for your entity that matches the IDs generated for Medusas core entities, you should add a `BeforeInsert` event handler. Then, inside that handler use Medusas utility function `generateEntityId` to generate the ID. It accepts the ID as a first parameter and the prefix as a second parameter. The `Post` entity IDs will be of the format `post_<RANDOM>`.
If you want the entity to also be soft deletable then it should extend `SoftDeletableEntity` instead:
```ts
import { SoftDeletableEntity } from "@medusajs/medusa"
@Entity()
export class Post extends SoftDeletableEntity {
// ...
}
```
You can learn more about what decorators and column types you can use in [Typeorms documentation](https://typeorm.io/entities).
---
## Step 2: Create a Migration
Additionally, you must create a migration for your entity. Migrations are used to update the database schema with new tables or changes to existing tables.
You can learn more about Migrations, how to create or generate them, and how to run them in the [Migration documentation](./migrations/create.md).
---
## Step 3: Create a Repository
Entities data can be easily accessed and modified using Typeorm [Repositories](https://typeorm.io/working-with-repository). To create a repository, create a file in `src/repositories`. For example, heres a repository `PostRepository` created in `src/repositories/post.ts`:
```ts title=src/repositories/post.ts
import { Post } from "../models/post"
import {
dataSource,
} from "@medusajs/medusa/dist/loaders/database"
export const PostRepository = dataSource
.getRepository(Post)
export default PostRepository
```
The repository is created using the `getRepository` method of the data source exported from the core package in Medusa. This method accepts the entity as a parameter.
:::tip
A data source is Typeorms connection settings that allows you to connect to your database. You can learn more about it in [Typeorms documentation](https://typeorm.io/data-source).
:::
If you want to add methods to that repository or override Typeorm's Repository methods, you can do that using the `extend` method:
```ts title=src/repositories/post.ts
import { Post } from "../models/post"
import {
dataSource,
} from "@medusajs/medusa/dist/loaders/database"
export const PostRepository = dataSource
.getRepository(Post)
.extend({
customFunction(): void {
// TODO add custom implementation
return
},
})
export default PostRepository
```
You can learn about available Repository methods in [Typeorm's documentation](https://typeorm.io/repository-api).
---
## (Optional) Step 4: Run Migrations
Before you start using your entity, make sure to run the migrations that reflect the entity on your database schema. If you've already ran migrations, you can skip this step.
To run migrations, run the `build` command that transpiles your code:
```bash npm2yarn
npm run build
```
Then, run the `migration` command:
```bash
npx medusa migrations run
```
You should see that your migration have executed.
---
## Example: Use Entity in Service
You can access your custom entity data in the database in services or subscribers using the repository. For example, heres a service that lists all posts:
```ts
import { TransactionBaseService } from "@medusajs/medusa"
import PostRepository from "../repositories/post"
class PostService extends TransactionBaseService {
protected readonly postRepository_: typeof PostRepository
constructor({ postRepository, manager }) {
super({ postRepository, manager })
this.postRepository_ = postRepository
this.manager_ = manager
}
async list() {
const postRepo = this.manager_
.withRepository(this.postRepository_)
return await postRepo.find()
}
}
export default PostService
```
In the constructor, you can use dependency injection to get access to instances of services and repositories. Here, you initialize class fields `postRepository` and `manager`. The `manager` is a [Typeorm Entity Manager](https://typeorm.io/working-with-entity-manager).
Then, in the method `list`, you can create an instance of the `PostRepository` using the `this.manager_.withRepository` method passing it `this.postRepository` as a parameter.
After getting an instance of the repository, you can then use [Typeorms Repository methods](https://typeorm.io/repository-api) to perform Create, Read, Update, and Delete (CRUD) operations on your entity. You can also use any custom methods that you defined in the Repository.
:::note
This same usage of repositories can be done in other resources such as subscribers or endpoints.
:::
---
## Delete a Soft-Deletable Entity
To delete soft-deletable entities that extend the `SoftDeletableEntity` class, you can use the repository method `softDelete` method:
```ts
await postRepository.softDelete(post.id)
```
---
## Advanced Entity Definitions
With entities, you can create relationships, index keys, and more. As Medusa uses Typeorm, you can learn about using these functionalities through [Typeorm's documentation](https://typeorm.io/).
---
## See Also
- [Extend Entity](./extend-entity.md)
- [Create a Plugin](../plugins/create.mdx)

View File

@@ -0,0 +1,182 @@
---
description: 'Learn how to create an entity in Medusa. This guide also explains how to create a repository and access and delete the entity.'
addHowToData: true
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# How to Create an Entity
In this document, youll learn how you can create a custom [Entity](./overview.mdx).
## Step 1: Create the Entity
To create an entity, create a TypeScript file in `src/models`. For example, heres a `Post` entity defined in the file `src/models/post.ts`:
```ts title=src/models/post.ts
import {
BeforeInsert,
Column,
Entity,
PrimaryColumn,
} from "typeorm"
import { BaseEntity } from "@medusajs/medusa"
import { generateEntityId } from "@medusajs/medusa/dist/utils"
@Entity()
export class Post extends BaseEntity {
@Column({ type: "varchar" })
title: string | null
@BeforeInsert()
private beforeInsert(): void {
this.id = generateEntityId(this.id, "post")
}
}
```
This entity has one column `title` defined. However, since it extends `BaseEntity` it will also have the `id`, `created_at`, and `updated_at` columns.
Medusas core entities all have the following format for IDs: `<PREFIX>_<RANDOM>`. For example, an order might have the ID `order_01G35WVGY4D1JCA4TPGVXPGCQM`.
To generate an ID for your entity that matches the IDs generated for Medusas core entities, you should add a `BeforeInsert` event handler. Then, inside that handler use Medusas utility function `generateEntityId` to generate the ID. It accepts the ID as a first parameter and the prefix as a second parameter. The `Post` entity IDs will be of the format `post_<RANDOM>`.
You can learn more about what decorators and column types you can use in [Typeorms documentation](https://typeorm.io/entities).
### Soft-Deletable Entities
If you want the entity to also be soft deletable then it should extend `SoftDeletableEntity` instead:
```ts
import { SoftDeletableEntity } from "@medusajs/medusa"
@Entity()
export class Post extends SoftDeletableEntity {
// ...
}
```
### Adding Relations
Your entity may be related to another entity. You can showcase the relation with [Typeorm's relation decorators](https://typeorm.io/relations).
For example, you can create another entity `Author` and add a `ManyToOne` relation to it from the `Post`, and a `OneToMany` relation from the `Author` to the `Post`:
<Tabs groupId="files" isCodeTabs={true}>
<TabItem value="post" label="src/models/post.ts" default>
```ts
import {
BeforeInsert,
Column,
Entity,
ManyToOne,
} from "typeorm"
import { BaseEntity } from "@medusajs/medusa"
import { generateEntityId } from "@medusajs/medusa/dist/utils"
import { Author } from "./author"
@Entity()
export class Post extends BaseEntity {
@Column({ type: "varchar" })
title: string | null
@Column({ type: "varchar" })
author_id: string
@ManyToOne(() => Author, (author) => author.posts)
author: Author
@BeforeInsert()
private beforeInsert(): void {
this.id = generateEntityId(this.id, "post")
}
}
```
</TabItem>
<TabItem value="author" label="src/services/author.ts">
```ts
import { BaseEntity, generateEntityId } from "@medusajs/medusa"
import {
BeforeInsert,
Column,
Entity,
OneToMany,
} from "typeorm"
import { Post } from "./post"
@Entity()
export class Author extends BaseEntity {
@Column({ type: "varchar" })
name: string
@Column({ type: "varchar", nullable: true })
image?: string
@OneToMany(() => Post, (post) => post.author)
posts: Post[]
@BeforeInsert()
private beforeInsert(): void {
this.id = generateEntityId(this.id, "auth")
}
}
```
</TabItem>
</Tabs>
Adding these relations allows you to later on expand these relations when retrieving records of this entity with repositories.
---
## Step 2: Create a Migration
Additionally, you must create a migration for your entity. Migrations are used to update the database schema with new tables or changes to existing tables.
You can learn more about Migrations, how to create or generate them, and how to run them in the [Migration documentation](./migrations/create.md).
---
## Step 3: Create a Repository
An repository is required for every entity you create. They provide methods to access and modify an entity's records, and they're used by other resources such as services or endpoints to perform those functionalities.
To learn how to create a repository, refer to the [Repositories](./repositories.md) documentation.
---
## (Optional) Step 4: Run Migrations
Before you start using your entity, make sure to run the migrations that reflect the entity on your database schema. If you've already ran migrations, you can skip this step.
To run migrations, run the `build` command that transpiles your code:
```bash npm2yarn
npm run build
```
Then, run the `migration` command:
```bash
npx medusa migrations run
```
You should see that your migration have executed.
---
## Advanced Entity Definitions
With entities, you can create relationships, index keys, and more. As Medusa uses Typeorm, you can learn about using these functionalities through [Typeorm's documentation](https://typeorm.io/entities).
---
## See Also
- [How to use repositories](./repositories.md)
- [Extend an entity](./extend-entity.md)
- [Create a plugin](../plugins/create.mdx)

View File

@@ -9,75 +9,117 @@ In this document, youll learn how to create a [Migration](./overview.mdx) usi
## Step 1: Create Migration File
To create a migration that makes changes to your Medusa schema, run the following command:
There are two ways to create a migration file: create and write its content manually, or create and generate its content.
```bash
npx typeorm migration:create src/migrations/UserChanged
If you're creating a custom entity, then it's recommended to generate the migration file. However, if you're extending an entity from Medusa's core, then you should create and write the migration manually.
### Option 1: Generate Migration File
:::warning
Generating migration files for extended entities may cause unexpected errors. It's highly recommended to write them manually instead.
:::
Typeorm provides a `migration:generate` command that allows you to pass it a Typeorm [DataSource](https://typeorm.io/data-source). The `DataSource` includes database connection details, as well as the path to your custom entities.
Start by creating the file `datasource.js` in the root of your Medusa backend project with the following content:
```js
const { DataSource } = require("typeorm")
const AppDataSource = new DataSource({
type: "postgres",
port: 5432,
username: "<YOUR_DB_USERNAME>",
password: "<YOUR_DB_PASSWORD>",
database: "<YOUR_DB_NAME>",
entities: [
"dist/models/*.js",
],
migrations: [
"dist/migrations/*.js",
],
})
module.exports = {
datasource: AppDataSource,
}
```
This will create the migration file in the path you specify. You can use this without the need to install Typeorm's CLI tool. You can then go ahead and make changes to it as necessary.
Make sure to replace `<YOUR_DB_USERNAME>`, `<YOUR_DB_PASSWORD>`, and `<YOUR_DB_NAME>` with the necessary values for your database connection.
The migration file must be inside the `src/migrations` directory. When you run the build command, it will be transpiled into the directory `dist/migrations`. The `migrations run` command can only pick up migrations under the `dist/migrations` directory on a Medusa backend. This applies to migrations created in a Medusa backend, and not in a Medusa plugin. For plugins, check out the [Plugin's Structure section](../../plugins/create.mdx).
Then, after creating your entity, run the `build` command:
<details>
<summary>Generating Migrations for Entities</summary>
```bash npm2yarn
npm run build
```
You can alternatively use Typeorm's `generate` command to generate a Migration file from existing entity classes. As of v1.8, Medusa uses Typeorm v0.3.x. So, you have to create a [DataSource](https://typeorm.io/data-source) first before using the `migration:generate` command.
Finally, run the following command to generate a migration for your custom entity:
For example, create the file `datasource.js` in the root of your Medusa server with the following content:
```bash
npx typeorm migration:generate -d datasource.js src/migrations/PostCreate
```
```js
const { DataSource } = require("typeorm")
const AppDataSource = new DataSource({
type: "postgres",
port: 5432,
username: "<YOUR_DB_USERNAME>",
password: "<YOUR_DB_PASSWORD>",
database: "<YOUR_DB_NAME>",
entities: [
"dist/models/*.js",
],
migrations: [
"dist/migrations/*.js",
],
})
This will generate the migration file in the path you specify, where `PostCreate` is just an example of the name of the migration to create. The migration file must be inside the `src/migrations` directory. When you run the build command, it will be transpiled into the `dist/migrations` directory.
module.exports = {
datasource: AppDataSource,
The `migrations run` command can only pick up migrations under the `dist/migrations` directory on a Medusa backend. This applies to migrations created in a Medusa backend, and not in a Medusa plugin. For plugins, check out the [Plugin's Structure section](../../plugins/create.mdx).
You can now continue to [step 2](#step-2-build-files) of this guide.
### Option 2: Write Migration File
With this option, you'll use Typeorm's CLI tool to create the migration file, but you'll write the content yourself.
Run the following command in the root directory of your Medusa backend project:
```bash
npx typeorm migration:create src/migrations/PostCreate
```
This will create the migration file in the path you specify, where `PostCreate` is just an example of the name of the migration to create. The migration file must be inside the `src/migrations` directory. When you run the build command, it will be transpiled into the `dist/migrations` directory.
The `migrations run` command can only pick up migrations under the `dist/migrations` directory on a Medusa backend. This applies to migrations created in a Medusa backend, and not in a Medusa plugin. For plugins, check out the [Plugin's Structure section](../../plugins/create.mdx).
If you open the file, you'll find `up` and `down` methods. The `up` method is used to reflect the changes on the database. The `down` method is used to revert the changes, which will be executed if the `npx medusa migrations revert` command is used.
In each of the `up` and `down` methods, you can write the migration either with [SQL syntax](https://www.postgresql.org/docs/current/sql-syntax.html), or using the [migration API](https://typeorm.io/migrations#using-migration-api-to-write-migrations).
For example:
<!-- eslint-disable max-len -->
```ts
import { MigrationInterface, QueryRunner } from "typeorm"
export class AddAuthorsAndPosts1690876698954 implements MigrationInterface {
name = "AddAuthorsAndPosts1690876698954"
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "post" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "title" character varying NOT NULL, "author_id" character varying NOT NULL, "authorId" character varying, CONSTRAINT "PK_be5fda3aac270b134ff9c21cdee" PRIMARY KEY ("id"))`)
await queryRunner.query(`CREATE TABLE "author" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "name" character varying NOT NULL, "image" character varying, CONSTRAINT "PK_5a0e79799d372fe56f2f3fa6871" PRIMARY KEY ("id"))`)
await queryRunner.query(`ALTER TABLE "post" ADD CONSTRAINT "FK_c6fb082a3114f35d0cc27c518e0" FOREIGN KEY ("authorId") REFERENCES "author"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`)
}
```
Make sure to replace `<YOUR_DB_USERNAME>`, `<YOUR_DB_PASSWORD>`, and `<YOUR_DB_NAME>` with the necessary values for your database connection.
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "post" DROP CONSTRAINT "FK_c6fb082a3114f35d0cc27c518e0"`)
await queryRunner.query(`DROP TABLE "author"`)
await queryRunner.query(`DROP TABLE "post"`)
}
}
```
Then, after creating your entity, run the `build` command:
:::warning
```bash npm2yarn
npm run build
```
If you're copying the code snippet above, make sure to not copy the class name or the `name` attribute in it. Your migration should keep its timestamp.
Finally, run the following command to generate a Migration for your new entity:
```bash
npx typeorm migration:generate -d datasource.js src/migrations/PostCreate
```
Where `PostCreate` is just an example of the name of the migration to generate. The migration will then be generated in `src/migrations/<TIMESTAMP>-PostCreate.ts`. You can then skip to [step 3](#step-3-build-files) of this guide.
</details>
:::
---
## Step 2: Write Migration File
## Step 2: Build Files
The migration file contains the necessary commands to create the database columns, foreign keys, and more.
You can learn more about writing the migration file in You can learn more about writing migrations in [Typeorms Documentation](https://typeorm.io/migrations#using-migration-api-to-write-migrations).
---
## Step 3: Build Files
Before you can run the migrations you need to run the build command to transpile the TypeScript files to JavaScript files:
Before you can run the migrations, you need to run the build command to transpile the TypeScript files to JavaScript files:
```bash npm2yarn
npm run build

View File

@@ -15,7 +15,7 @@ Entities in medusa represent tables in the database as classes. An example of th
Aside from the entities in the Medusa core package, you can also create custom entities to use in your Medusa backend. Custom entities are TypeScript or JavaScript files located in the `src/models` directory of your Medusa backend. You then transpile these entities to be used during the backend's runtime using the `build` command, which moves them to the `dist/models` directory.
Entities are TypeScript files and they are based on [Typeorms Entities](https://typeorm.io/entities) and use Typeorm decorators.
Entities are based on [Typeorms Entities](https://typeorm.io/entities) and use Typeorm decorators. Each entity also require a [repository](./repositories.md) to be created. A repository provides basic methods to access and manipulate the entity's data.
---
@@ -68,19 +68,11 @@ If you want to remove a property from the `metadata` object, you can pass the `m
---
## What are Repositories
Repositories provide generic helper methods for entities. For example, a `list` method to retrieve all entities with pagination, or `retrieve` to retrieve a single entity record.
Repostories are [Typeorm repositories](https://typeorm.io/working-with-repository), so you can refer to Typeorm's documentation on all available methods.
---
## Custom Development
Developers can create custom entities in the Medusa backend, a plugin, or in a module, then ensure it reflects in the database using a migration.
<DocCardList colSize={6} items={[
<DocCardList colSize={4} items={[
{
type: 'link',
href: '/development/entities/create',
@@ -90,6 +82,15 @@ Developers can create custom entities in the Medusa backend, a plugin, or in a m
description: 'Learn how to create an entity in Medusa.'
}
},
{
type: 'link',
href: '/development/entities/repositories',
label: 'Create a Repository',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to use a repository in Medusa.'
}
},
{
type: 'link',
href: '/development/entities/migrations/create',

View File

@@ -0,0 +1,308 @@
---
description: "In this document, you'll learn what repositories are, how to use them within your Medusa backend, and what are some of their common methods."
---
# Repositories
In this document, you'll learn what repositories are, how to use them within your Medusa backend, and what are some of their common methods.
## Overview
Repositories provide generic helper methods for entities. For example, a `find` method to retrieve all entities with pagination, or `findOne` to retrieve a single entity record.
Repostories are [Typeorm repositories](https://typeorm.io/working-with-repository), so you can refer to Typeorm's documentation on all available methods.
This guide provides some basic methods you'll need during your custom development with Medusa.
---
## Basic Implementation
Each entity you create needs a repository. A repository is created under the `src/repositories` directory of your Medusa backend project. The file name is the name of the repository without `Repository`.
For example, to create a repository for a `Post` entity, create the file `src/repositories/post.ts` with the following content:
```ts src=src/repositories/post.ts
import { Post } from "../models/post"
import {
dataSource,
} from "@medusajs/medusa/dist/loaders/database"
export const PostRepository = dataSource
.getRepository(Post)
export default PostRepository
```
The repository is created using the `getRepository` method of the data source exported from the core package in Medusa. This method accepts the entity as a parameter.
:::tip
A data source is Typeorms connection settings that allows you to connect to your database. You can learn more about it in [Typeorms documentation](https://typeorm.io/data-source).
:::
---
## Customizing a Repository
If you want to add methods to the repository or override Typeorm's Repository methods, you can do that using the `extend` method:
```ts title=src/repositories/post.ts
import { Post } from "../models/post"
import {
dataSource,
} from "@medusajs/medusa/dist/loaders/database"
export const PostRepository = dataSource
.getRepository(Post)
.extend({
customFunction(): void {
// TODO add custom implementation
return
},
})
export default PostRepository
```
You can learn about available Repository methods in [Typeorm's documentation](https://typeorm.io/repository-api).
---
## Using Repositories in Other Resources
When you want to perform an action or use on an entity in one of your custom resources, such as an endpoint or a service, you need to use its repository.
### Endpoints
To access a repository within an endpoint, use the `req.scope.resolve` method. For example:
```ts
import { PostRepository } from "../repositories/post"
import { EntityManager } from "typeorm"
// ...
export default () => {
// ...
storeRouter.get("/posts", async (req, res) => {
const postRepository: typeof PostRepository =
req.scope.resolve("postRepository")
const manager: EntityManager = req.scope.resolve("manager")
const postRepo = manager.withRepository(postRepository)
return res.json({
posts: await postRepo.find(),
})
})
// ...
}
```
You can learn more about endpoints [here](../endpoints/overview.mdx).
### Services and Subscribers
As repositories are registered in the [dependency container](../fundamentals/dependency-injection.md#dependency-container-and-injection), they can be accessed through dependency injection in the constructor of a service or a subscriber.
For example:
```ts title=/src/services/post.ts
import { PostRepository } from "../repositories/post"
class PostService extends TransactionBaseService {
// ...
protected postRepository_: typeof PostRepository
constructor(container) {
super(container)
// ...
this.postRepository_ = container.postRepository
}
async list(): Promise<Post[]> {
const postRepo = this.activeManager_.withRepository(
this.postRepository_
)
return await postRepo.find()
}
// ...
}
```
You can learn more about services [here](../services/overview.mdx).
### Other Resources
Resources that have access to the dependency container can access repositories just like any other resources. You can learn more about the dependency container and dependency injection in [this documentation](../fundamentals/dependency-injection.md).
---
## Common Methods
This section covers some common methods and use cases you'll use with repositories. You can refer to [Typeorm's documentation](https://typeorm.io/repository-api) for full details on available methods.
### Retrieving a List of Records
To retrieve a list of records of an entity, use the `find` method:
```ts
const posts = await postRepository.find()
```
You can also filter the retrieved items by passing an object of type [FindOption](https://typeorm.io/find-options) as a first parameter:
```ts
const posts = await postRepository.find({
where: {
id: "1",
},
})
```
In addition, you can pass `skip` and `take` properties to the object for pagination purposes. `skip`'s value is a number that indicates how many items to skip before retrieving the results, and `take` indicates how many items to return:
```ts
const posts = await postRepository.find({
skip: 0,
take: 20,
})
```
To expand relations and retrieve them as part of each item in the result, you can pass the `relations` property to the parameter object:
```ts
const posts = await postRepository.find({
relations: ["authors"],
})
```
Medusa provides a utility method `buildQuery` that allows you to easily format the object to pass to the `find` method. `buildQuery` accepts two parameters:
1. The first parameter is an object whose keys are the attributes of the entity, and their values are the value to filter by.
2. The second parameter includes the options related to pagination (such as `skip` and `take`), the relations to expand, and fields to select in each returned item.
For example:
```ts
import { buildQuery } from "@medusajs/medusa"
// ...
const selector = {
id: "1",
}
const config = {
skip: 0,
take: 20,
relations: ["authors"],
select: ["title"],
}
const query = buildQuery(selector, config)
const posts = await postRepository.find(query)
```
### Retrieving a List of Records with Count
You can retrieve a list of records along with their count using the `findAndCount` method:
```ts
const [posts, count] = await postRepository.findAndCount()
```
This method also accepts the same options object as a parameter similar to the [find](#retrieving-a-list-of-records) method.
### Retrieving a Single Record
You can retrieve one record of an entity using the `findOne` method:
```ts
const post = await postRepository.findOne({
where: {
id: "1",
},
})
```
If the record does not exist, `null` will be returned instead.
You can also pass the method an options object similar to the [find](#retrieving-a-list-of-records) method to expand relations or specify what fields to select.
### Create Record
To create a new record of an entity, use the `create` and `save` methods of the repository:
```ts
const post = postRepository.create()
post.title = data.title
post.author_id = data.author_id
const result = await postRepository.save(post)
```
The `save` method is what actually persists the created record in the database.
### Update Record
To update a record of an entity, use the `save` method of the repository:
```ts
// const data = {
// title: ''
// }
// const post = await postRepository.findOne({
// where: {
// id: '1'
// }
// })
Object.assign(post, data)
const updatedPost = await postRepository.save(post)
```
### Delete a Record
To delete a record of an entity, use the `remove` method of the repository:
```ts
const post = await postRepository.findOne({
where: {
id: "1",
},
})
await postRepository.remove([post])
```
This method accepts an array of records to delete.
### Soft Delete a Record
If an entity extends the `SoftDeletableEntity` class, it can be soft deleted. This means that the entity won't be fully deleted from the database, but it can't be retrieved as a non-deleted entity would.
To soft-delete a record of an entity, use the `softRemove` method:
```ts
const post = await postRepository.findOne({
where: {
id: "1",
},
})
await postRepository.softRemove([post])
```
You can later retrieve that entity by passing the `withDeleted` option to methods like `find`, `findAndCount`, or `findOne`:
```ts
const posts = await postRepository.find({
withDeleted: true,
})
```