docs: updates to use DML and other changes (#7834)

- Change existing data model guides and add new ones for DML
- Change module's docs around service factory + remove guides that are now necessary
- Hide/remove all mentions of module relationships, or label them as coming soon.
- Change all data model creation snippets to use DML
- use `property` instead of `field` when referring to a data model's properties.
- Fix all snippets in commerce module guides to use new method suffix (no more main model methods)
- Rework recipes, removing/hiding a lot of sections as a lot of recipes are incomplete with the current state of DML.


### Other changes

- Highlight fixes in some guides
- Remove feature flags guide
- Fix code block styles when there are no line numbers.

### Upcoming changes in other PRs

- Re-generate commerce module references (for the updates in the method names)
- Ensure that the data model references are generated correctly for models using DML.
- (probably at a very later point) revisit recipes
This commit is contained in:
Shahed Nasser
2024-06-26 07:55:59 +00:00
committed by GitHub
parent 62dacdda75
commit 0462cc5acf
126 changed files with 1808 additions and 14242 deletions
@@ -4,24 +4,17 @@ export const metadata = {
# {metadata.title}
In this chapter, you'll learn about the module's container and how to register resources in that container.
In this chapter, you'll learn about the module's container and how to resolve resources in that container.
## Module's Container
Each module has a local container only used by the resources of that module.
So, resources in the module, such as services or loaders, can only resolve other resources registered in the module's container.
So, resources in the module, such as services or loaders, can only resolve other resources registered in the module's container, such as:
---
- `logger`: A utility to log message in the Medusa application's logs.
## Resources Registered in the Module's Container
Some resources registered in the module's container are:
- The module's main service.
- A generated service for each data model in your module. The registration name is the camel-case data model name suffixed by `Service`. For example, `myCustomService`.
![Example of registered resources in the container](https://res.cloudinary.com/dza7lstvk/image/upload/v1714400573/Medusa%20Book/modules-container_mkcbaq.jpg)
{/* TODO add other relevant resources, such as event bus */}
---
@@ -33,23 +26,25 @@ A service's constructor accepts as a first parameter an object used to resolve r
For example:
```ts highlights={[["5"], ["12"]]}
import { ModulesSdkTypes } from "@medusajs/types"
import { MyCustom } from "./models/my-custom"
```ts highlights={[["4"], ["10"]]}
import { Logger } from "@medusajs/medusa"
type InjectedDependencies = {
myCustomService: ModulesSdkTypes.InternalModuleService<any>
logger: Logger
}
export default class HelloModuleService {
protected myCustomService_:
ModulesSdkTypes.InternalModuleService<MyCustom>
constructor({ myCustomService }: InjectedDependencies) {
this.myCustomService_ = myCustomService
protected logger_: Logger
constructor({ logger }: InjectedDependencies) {
this.logger_ = logger
this.logger_.info("[HelloModuleService]: Hello World!")
}
// ...
}
```
### Loader
@@ -58,16 +53,18 @@ A loader function in a module accepts as a parameter an object having the proper
For example:
```ts highlights={[["8"]]}
```ts highlights={[["9"]]}
import {
LoaderOptions,
} from "@medusajs/modules-sdk"
import { Logger } from "@medusajs/medusa"
export default function helloWorldLoader({
container,
}: LoaderOptions) {
const myCustomService = container.resolve("myCustomService")
// ...
const logger: Logger = container.resolve("logger")
logger.info("[helloWorldLoader]: Hello, World!")
}
```
@@ -1,68 +0,0 @@
export const metadata = {
title: `${pageNumber} Database Operations in Service Methods`,
}
# {metadata.title}
In this document, youll learn how to implement database operations, such as creating a record, in the main service.
## Use the Data Model's Generated Service
To perform database operations on a data model, use the model's generated service in the module's container.
For example:
export const highlights = [
["13", "", "Inject myCustomService, which is the generated service of the `MyCustom` data model."],
["22", "", "Add a new field for the generated service of the MyCustom data model."],
["29", "", "Set the class field to the injected dependency."],
["35", "create", "Use the `create` method of the generated service."]
]
```ts title="src/modules/hello/service.ts" highlights={highlights}
// other imports...
import { ModulesSdkTypes } from "@medusajs/types"
import { MyCustom } from "./models/my-custom"
// ...
// recommended to define type in another file
type CreateMyCustomDTO = {
name: string
}
type InjectedDependencies = {
myCustomService: ModulesSdkTypes.InternalModuleService<any>
}
class HelloModuleService extends ModulesSdkUtils
.abstractModuleServiceFactory<
// ...
>(
// ...
) {
protected myCustomService_: ModulesSdkTypes.InternalModuleService<MyCustom>
constructor(
{ myCustomService }: InjectedDependencies
) {
// @ts-ignore
super(...arguments)
this.myCustomService_ = myCustomService
}
async create(
data: CreateMyCustomDTO
): Promise<MyCustomDTO> {
const myCustom = await this.myCustomService_.create(
data
)
return myCustom
}
}
```
In the above example, you resolve `myCustomService` in the main service's constructor. The `myCustomService` is the generated service for the `myCustom` data model.
Then, in the `create` method of the main service, you use `myCustomService`'s `create` method to create the record.
@@ -14,7 +14,7 @@ For example, Medusa has a link module that defines a relationship between the Pr
![Diagram showcasing the link module between the Product and Pricing modules](https://res.cloudinary.com/dza7lstvk/image/upload/v1709651569/Medusa%20Resources/product-pricing_vlxsiq.jpg)
Link modules provide more flexibility in managing relationships between modules while maintaining module isolation. The Medusa application only creates the link tables when both modules are available.
Link modules create the relationship between modules while maintaining module isolation. The Medusa application only creates the link tables when both modules are available.
<Note type="soon">
@@ -1,275 +0,0 @@
import { TypeList, CodeTabs, CodeTab } from "docs-ui"
export const metadata = {
title: `${pageNumber} Module Relationships`,
}
# {metadata.title}
In this document, youll learn about creating relationships between modules.
## What is a Module Relationship?
A module can have a relationship to another module in the form of a reference.
The Medusa application resolves these relationships while maintaining isolation between the modules and allowing you to retrieve data across them.
<Note title="Use module relationships when" type="success">
- You want to build relationships between the data models of modules.
- You want to assoaciate more fields with the data model of another module.
</Note>
<Note title="Don't use module relationships if" type="error">
- Youre building relationships between data models in the same module. Use foreign keys instead.
</Note>
---
## How to Create a Module Relationship?
<Note title="Steps Summary">
1. Define a `__joinerConfig` method in the module's main service.
2. Configure module to be queryable.
</Note>
Consider youre creating a data model that adds custom fields associated with a product:
```ts title="src/modules/hello/models/custom-product-data.ts" highlights={[["17"]]} collapsibleLines="1-8" expandButtonLabel="Show Imports"
import { BaseEntity } from "@medusajs/utils"
import {
Entity,
PrimaryKey,
Property,
} from "@mikro-orm/core"
@Entity()
export class CustomProductData extends BaseEntity {
@PrimaryKey({ columnType: "text" })
id!: string
@Property({ columnType: "text" })
custom_field: string
@Property({ columnType: "text", nullable: true })
product_id?: string
}
```
The `CustomProductData` data model has a `product_id` field to reference the product it adds custom fields for.
<Note title="Tip">
When you add a new data model, make sure to:
- [Create a migration for it.](../../../basics/data-models/page.mdx#create-a-migration)
- [Add it to the second parameter of the main service's factory function.](../service-factory/page.mdx#abstractModuleServiceFactory-parameters)
</Note>
### 1. Define `__joinerConfig` Method
To create a relationship to the `product` data model of the Product Module, create a public `__joinerConfig` method in your main module's service:
export const relationshipsHighlight = [
["39", "serviceName", "The name of the module that this relationship is referencing."],
["40", "alias", "The alias of the data model youre referencing in the other module."],
["41", "primaryKey", "The name of the field youre referencing in the other modules data model."],
["42", "foreignKey", "The name of the field in your data models referencing the other modules model."],
]
```ts title="src/modules/hello/service.ts" highlights={relationshipsHighlight} collapsibleLines="1-6" expandButtonLabel="Show Imports"
// other imports...
import { MyCustom } from "./models/custom-product-data"
import { CustomProductData } from "./models/custom-product-data"
import { ModuleJoinerConfig } from "@medusajs/types"
import { Modules } from "@medusajs/modules-sdk"
class HelloModuleService extends ModulesSdkUtils
.abstractModuleServiceFactory<
// ...
>(
// ...
) {
// ...
__joinerConfig(): ModuleJoinerConfig {
return {
serviceName: "helloModuleService",
alias: [
{
name: ["my_custom"],
args: {
entity: MyCustom.name,
},
},
{
name: ["custom_product_data"],
args: {
entity: CustomProductData.name,
// Only needed if data model isn't main data model
// of service
methodSuffix: "CustomProductDatas",
},
},
],
relationships: [
{
serviceName: Modules.PRODUCT,
alias: "product",
primaryKey: "id",
foreignKey: "product_id",
},
],
}
}
// ...
}
```
This creates a relationship to the `Product` data model of the Product Module using the alias `product`. The `product_id` fields in your data models are considered references to the `id` field of the `Product` data model.
#### `__joinerConfig` Return Type
<TypeList types={[
{
name: "serviceName",
type: "`string`",
optional: false,
description: "The name of your module (as added in `medusa-config.js`)."
},
{
name: "alias",
type: "`object[]`",
description: "The alias definitions for each data model in your module. This allows other modules to reference your module's data models in relationships.",
children: [
{
name: "name",
type: "`string[]`",
description: "The alias names of a data model used later when fetching or referencing the data model."
},
{
name: "args",
type: "`object`",
description: "The alias's arguments.",
children: [
{
name: "entity",
type: "string",
description: "The name of the data model this alias is defined for."
},
{
name: "methodSuffix",
type: "string",
description: "The plural name of the data model. This is only required if the data model isn't the main data model of the module's service."
}
]
}
]
},
{
name: "relationships",
type: "`object[]`",
description: "Your module's relationships to other modules.",
children: [
{
name: "serviceName",
type: "`string`",
optional: false,
description: "The name of the module (as added in `medusa-config.js`) that this relationship is referencing. When referencing a Medusa commerce module, use the `Modules` enum imported from `@medusajs/modules-sdk`."
},
{
name: "alias",
type: "`string`",
optional: false,
description: "The alias of the data model youre referencing in the other module. You can find it in the `__joinerConfig` method of the other module's service."
},
{
name: "primaryKey",
type: "`string`",
optional: false,
description: "The name of the field youre referencing in the other modules data model."
},
{
name: "foreignKey",
type: "`string`",
optional: false,
description: "The name of the field in your data models that references the other modules data model."
}
]
}
]} sectionTitle="Define __joinerConfig Method" />
### 2. Adjust Module Configuration
To use relationships in a module, adjust its configuration object passed to `modules` in `medusa-config.js`:
export const configHighlights = [
["7", "isQueryable", "Enable this property to use relationships in a module."]
]
```js title="medusa-config.js" highlights={configHighlights}
module.exports = defineConfig({
// ...
modules: {
helloModuleService: {
// ...
definition: {
isQueryable: true,
},
},
},
})
```
Enabling the `isQueryable` property is required to use relationships in a module.
---
## Reference Inner Data Models
If the data model youre referencing isnt the main data model of the main module service, pass to the relationship definition the `args` property:
```ts title="src/modules/hello/service.ts" highlights={[["20", "methodSuffix", "The suffix of the referenced data model's methods."]]}
class HelloModuleService extends ModulesSdkUtils
.abstractModuleServiceFactory<
// ...
>(
// ...
) {
// ...
__joinerConfig(): ModuleJoinerConfig {
return {
// ...
relationships: [
{
serviceName: Modules.PRODUCT,
primaryKey: "id",
foreignKey: "variant_id",
alias: "variant",
args: {
methodSuffix: "Variants",
},
},
],
}
}
}
```
The `args` propertys value is an object accepting a `methodSuffix` property. The `methodSuffix` propertys value is the plural name of the data model.
---
## Querying Module Relationships
The next chapter explains how to query data across module relationships.
@@ -34,7 +34,6 @@ module.exports = defineConfig({
},
},
})
```
The `options` propertys value is an object. You can pass any properties you want.
@@ -47,36 +46,30 @@ The modules main service receives the module options as a second parameter.
For example:
```ts title="src/modules/hello/service.ts" highlights={[["15"], ["21"], ["25"], ["26"], ["27"]]}
// ...
```ts title="src/modules/hello/service.ts" highlights={[["12"], ["14", "options?: ModuleOptions"], ["17"], ["18"], ["19"]]}
import { MedusaService } from "@medusajs/utils"
import MyCustom from "./models/my-custom"
// recommended to define type in another file
type HelloModuleOptions = {
type ModuleOptions = {
capitalize?: boolean
}
class HelloModuleService extends ModulesSdkUtils
.abstractModuleServiceFactory<
// ...
>(
// ...
) {
// ...
protected options_: HelloModuleOptions
constructor(
{
// ...
}: InjectedDependencies,
protected readonly moduleOptions: HelloModuleOptions
) {
//...
this.options_ = moduleOptions || {
capitalize: false,
}
export default class HelloModuleService extends MedusaService({
MyCustom,
}){
protected options_: ModuleOptions
constructor({}, options?: ModuleOptions) {
super(...arguments)
this.options_ = options || {
capitalize: false,
}
}
// ...
}
```
---
@@ -93,13 +86,13 @@ import {
} from "@medusajs/modules-sdk"
// recommended to define type in another file
type HelloModuleOptions = {
type ModuleOptions = {
capitalize?: boolean
}
export default function helloWorldLoader({
options,
}: LoaderOptions<HelloModuleOptions>) {
}: LoaderOptions<ModuleOptions>) {
console.log(
"[HELLO MODULE] Just started the Medusa application!",
@@ -10,21 +10,43 @@ In this chapter, youll learn about the remote query and how to use it to fetc
## What is the Remote Query?
The remote query fetches data across modules and their relationships having their `isQueryable` configuration enabled. Its a function registered in the Medusa container under the `remoteQuery` key.
The remote query fetches data across modules. Its a function registered in the Medusa container under the `remoteQuery` key.
In your resources, such as API routes or workflows, you can resolve the remote query to fetch data across custom modules and Medusas commerce modules.
---
## Example: Query Hello Module
## isQueryable Configuration
Before you use remote query on your module, you must enable the `isQueryable` configuration of the module.
For example:
```js
module.exports = defineConfig({
// ...
modules: {
helloModuleService: {
resolve: "./modules/hello",
definition: {
isQueryable: true,
},
},
},
})
```
---
## Remote Query Example
For example, create the route `src/api/store/query/route.ts` with the following content:
export const exampleHighlights = [
["18", "", "Resolve the remote query from the Medusa container."],
["21", "remoteQueryObjectFromString", "Utility function to build the query."],
["22", "entryPoint", "The alias name of the model youre querying."],
["23", "fields", "An array of the data models field names to retrieve in the result."],
["22", "entryPoint", "The name of the data model you're querying."],
["23", "fields", "An array of the data models properties to retrieve in the result."],
["27", "remoteQuery", "Run the query using the remote query."]
]
@@ -50,12 +72,12 @@ export async function GET(
)
const query = remoteQueryObjectFromString({
entryPoint: "custom_product_data",
fields: ["id", "custom_field", "product.title"],
entryPoint: "my_custom",
fields: ["id", "test"],
})
res.json({
custom_product_data: await remoteQuery(query),
my_customs: await remoteQuery(query),
})
}
```
@@ -64,8 +86,8 @@ In the above example, you resolve `remoteQuery` from the Medusa container.
Then, you create a query using the `remoteQueryObjectFromString` utility function imported from `@medusajs/utils`. This function accepts as a parameter an object with the following required properties:
- `entryPoint`: The alias name of the model youre querying. You defined the alias name in the `__joinerConfig` method of your main service.
- `fields`: An array of the data models field names to retrieve in the result. You can also specify fields of a relationship using dot notation.
- `entryPoint`: The data model's name, as specified in the first parameter of the `model.define` method used for the data model's definition.
- `fields`: An array of the data models properties to retrieve in the result.
You then pass the query to the `remoteQuery` function to retrieve the results.
@@ -75,17 +97,17 @@ You then pass the query to the `remoteQuery` function to retrieve the results.
```ts highlights={[["6"], ["7"], ["8"], ["9"]]}
const query = remoteQueryObjectFromString({
entryPoint: "custom_product_data",
fields: ["id", "custom_field", "product.title"],
entryPoint: "my_custom",
fields: ["id", "name"],
variables: {
filters: {
id: [
"cpd_01HWSVWR4D2XVPQ06DQ8X9K7AX",
"cpd_01HWSVWK3KYHKQEE6QGS2JC3FX",
"mc_01HWSVWR4D2XVPQ06DQ8X9K7AX",
"mc_01HWSVWK3KYHKQEE6QGS2JC3FX",
],
},
},
})
})
const result = await remoteQuery(query)
```
@@ -102,7 +124,7 @@ The `remoteQueryObjectFromString` function accepts a `variables` property. You c
{
name: "filters",
type: "`object`",
description: "The filters to apply on any of the data model's fields."
description: "The filters to apply on any of the data model's properties."
}
]
},
@@ -116,8 +138,8 @@ The `remoteQueryObjectFromString` function accepts a `variables` property. You c
```ts highlights={[["5"], ["6"], ["7"]]}
const query = remoteQueryObjectFromString({
entryPoint: "custom_product_data",
fields: ["id", "custom_field", "product.title"],
entryPoint: "my_custom",
fields: ["id", "name"],
variables: {
order: {
name: "DESC",
@@ -128,12 +150,12 @@ const query = remoteQueryObjectFromString({
const result = await remoteQuery(query)
```
To sort returned records, pass an `order` property to the `variables` property's value.
To sort returned records, pass an `order` property to `variables`.
The `order` property is an object whose keys are field names, and values are either:
The `order` property is an object whose keys are property names, and values are either:
- `ASC` to sort records by that field in ascending order.
- `DESC` to sort records by that field in descending order.
- `ASC` to sort records by that property in ascending order.
- `DESC` to sort records by that property in descending order.
---
@@ -141,8 +163,8 @@ The `order` property is an object whose keys are field names, and values are eit
```ts highlights={[["5", "skip", "The number of records to skip before fetching the results."], ["6", "take", "The number of records to fetch."]]}
const query = remoteQueryObjectFromString({
entryPoint: "custom_product_data",
fields: ["id", "custom_field", "product.title"],
entryPoint: "my_custom",
fields: ["id", "name"],
variables: {
skip: 0,
take: 10,
@@ -155,7 +177,7 @@ const {
} = await remoteQuery(query)
```
To paginate the returned records, pass the following properties to the `variables` property's value:
To paginate the returned records, pass the following properties to `variables`:
- `skip`: (required to apply pagination) The number of records to skip before fetching the results.
- `take`: The number of records to fetch.
@@ -215,7 +237,6 @@ The remote query function alternatively accepts a string with GraphQL syntax as
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { ContainerRegistrationKeys } from "@medusajs/utils"
import type {
RemoteQueryFunction,
@@ -231,20 +252,15 @@ The remote query function alternatively accepts a string with GraphQL syntax as
const query = `
query {
custom_product_data {
my_custom {
id
custom_field
product {
title
}
name
}
}
`
const result = await remoteQuery(query)
res.json({
custom_product_data: result,
my_customs: result,
})
}
```
@@ -256,15 +272,12 @@ The remote query function alternatively accepts a string with GraphQL syntax as
The `remoteQuery` function accepts as a second parameter an object of variables to reference in the GraphQL query.
```ts highlights={[["2"], ["3"], ["16"], ["17"], ["18"], ["19"]]}
```ts highlights={[["2"], ["3"], ["13"], ["14"], ["15"], ["16"]]}
const query = `
query($id: ID) {
custom_product_data(id: $id) {
my_custom(id: $id) {
id
custom_field
product {
title
}
name
}
}
`
@@ -273,8 +286,8 @@ The remote query function alternatively accepts a string with GraphQL syntax as
query,
{
id: [
"cpd_01HWSVWR4D2XVPQ06DQ8X9K7AX",
"cpd_01HWSVWK3KYHKQEE6QGS2JC3FX",
"mc_01HWSVWR4D2XVPQ06DQ8X9K7AX",
"mc_01HWSVWK3KYHKQEE6QGS2JC3FX",
]
}
)
@@ -285,22 +298,19 @@ The remote query function alternatively accepts a string with GraphQL syntax as
### Sort Records with GraphQL
To sort the records by a field, pass in the query an `order` argument whose value is an object. The objects key is the fields name, and the value is either:
To sort the records by a property, pass in the query an `order` argument whose value is an object. The objects key is the propertys name, and the value is either:
- `ASC` to sort items by that field in ascending order.
- `DESC` to sort items by that field in descending order.
- `ASC` to sort items by that property in ascending order.
- `DESC` to sort items by that property in descending order.
For example:
```ts highlights={[["3"]]}
const query = `
query {
custom_product_data(order: {custom_field: DESC}) {
my_custom(order: {name: DESC}) {
id
custom_field
product {
title
}
name
}
}
`
@@ -320,12 +330,9 @@ The remote query function alternatively accepts a string with GraphQL syntax as
```ts highlights={[["2"], ["3"]]}
const query = `
query($skip: Int, $take: Int) {
custom_product_data(skip: $skip, take: $take) {
my_custom(skip: $skip, take: $take) {
id
custom_field
product {
title
}
name
}
}
`
@@ -6,11 +6,13 @@ export const metadata = {
# {metadata.title}
In this document, youll learn about what the service factory is and how to use it to create a service.
In this chapter, youll learn about what the service factory is and how to use it.
## What is the Service Factory?
Medusa provides a service factory that your modules main service can extend. The service factory implements data management methods for your data models.
Medusa provides a service factory that your modules main service can extend.
The service factory generates data management methods for your data models, so you don't have to implement them manually.
<Note title="Use the service factory when" type="success">
@@ -22,34 +24,41 @@ Medusa provides a service factory that your modules main service can extend.
## How to Extend the Service Factory?
Medusa provides the service factory as a function your service extends. The function creates and returns a service class with generated data-management methods.
Medusa provides the service factory as a `MedusaService` function your service extends. The function creates and returns a service class with generated data-management methods.
For example, create the file `src/modules/hello/service.ts` with the following content:
```ts title="src/modules/hello/service.ts"
import { ModulesSdkUtils } from "@medusajs/utils"
import { MyCustom } from "./models/my-custom"
export const highlights = [
["4", "MedusaService", "The service factory function."],
["5", "MyCustom", "The data models to generate data-management methods for."]
]
class HelloModuleService extends ModulesSdkUtils
.abstractModuleServiceFactory(
MyCustom, []
) {
// TODO implement custom methods
}
```ts title="src/modules/hello/service.ts" highlights={highlights}
import { MedusaService } from "@medusajs/utils"
import MyCustom from "./models/my-custom"
class HelloModuleService extends MedusaService({
MyCustom,
}){
// TODO implement custom methods
}
export default HelloModuleService
```
### abstractModuleServiceFactory Parameters
### MedusaService Parameters
The `abstractModuleServiceFactory` function accepts two parameters:
The `MedusaService` function accepts one parameter, which is an object of data models to generate data-management methods for.
1. The first parameter is the main data model this service is creating methods for. For example, `MyCustom`.
2. The second parameter is an array of data models to generate methods for. If you have an `AnotherCustom` data model, this is where you add it.
In the example above, the `HelloModuleService` now has methods to manage the `MyCustom` data model, such as `createMyCustoms`.
### Generated Methods
The service factory generates the following methods for the main data model:
The service factory generates data-management methods for each of the data models provided in the first parameter.
The method's names are the operation's name, suffixed by the data model's name.
For example, the following methods are generated for the code snippet above:
<Table>
<Table.Header>
@@ -62,7 +71,7 @@ The service factory generates the following methods for the main data model:
<Table.Row>
<Table.Cell>
`list`
`listMyCustoms`
</Table.Cell>
<Table.Cell>
@@ -74,7 +83,7 @@ The service factory generates the following methods for the main data model:
<Table.Row>
<Table.Cell>
`listAndCount`
`listAndCountMyCustoms`
</Table.Cell>
<Table.Cell>
@@ -86,7 +95,7 @@ The service factory generates the following methods for the main data model:
<Table.Row>
<Table.Cell>
`retrieve`
`retrieveMyCustom`
</Table.Cell>
<Table.Cell>
@@ -98,7 +107,31 @@ The service factory generates the following methods for the main data model:
<Table.Row>
<Table.Cell>
`delete`
`createMyCustoms`
</Table.Cell>
<Table.Cell>
Create and retrieve records of the data model.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`updateMyCustoms`
</Table.Cell>
<Table.Cell>
Update and retrieve records of the data model.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`deleteMyCustoms`
</Table.Cell>
<Table.Cell>
@@ -110,77 +143,32 @@ The service factory generates the following methods for the main data model:
<Table.Row>
<Table.Cell>
`softDelete`
`softDeleteMyCustoms`
</Table.Cell>
<Table.Cell>
Soft-deletes a record by an ID or filter. This only applies if the data model has a `deleted_at` field.
Soft-deletes records using an array of IDs or an object of filters.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`restore`
`restoreMyCustoms`
</Table.Cell>
<Table.Cell>
Restores a soft-deleted record by an ID or filter. This only applies if the data model has a `deleted_at` field.
Restores soft-deleted records using an array of IDs or an object of filters.
</Table.Cell>
</Table.Row>
</Table.Body>
</Table>
The same methods are generated for data models passed in the second parameter of the service factory. The methods' names end with the data model's name. For example, `listAnotherCustom`.
<Note>
### Type Arguments
Except for the `retrieve` method, the suffixed data model's name is plural.
For a better development experience and accurate typing of the generated methods, the `abstractModuleServiceFactory` function accepts three type arguments:
export const typeArgsHighlights = [
["25", "InjectedDependencies", "The type of dependencies resolved from the Module's container."],
["26", "MyCustomDTO", "The expected input/output type of the main data model's generated methods."],
["27", "AllModelsDTO", "The expected input/output type of the generated methods of every data model."],
]
```ts title="src/modules/hello/service.ts" highlights={typeArgsHighlights} collapsibleLines="1-22" expandButtonLabel="Show More"
import { ModulesSdkUtils } from "@medusajs/utils"
import { MyCustom } from "./models/my-custom"
// recommended to define type in another file
type MyCustomDTO = {
id: string
name: string
}
type InjectedDependencies = {
// TODO add dependencies
}
type AllModelsDTO = {
MyCustom: {
dto: MyCustomDTO
}
}
// add other data models in your module here.
const generateMethodsFor = []
class HelloModuleService extends ModulesSdkUtils
.abstractModuleServiceFactory<
InjectedDependencies,
MyCustomDTO,
AllModelsDTO
>(MyCustom, generateMethodsFor) {
// TODO implement custom methods
}
export default HelloModuleService
```
1. The first one is the type of the dependencies to resolve from the module's container.
2. The second one is the expected input and output type of the main data models methods.
3. The third type is the expected input and output type of all data models that the service factory generates methods for.
</Note>