feat(link-modules,modules-sdk, utils, types, products) - Remote Link and Link modules (#4695)
What:
- Definition of all Modules links
- `link-modules` package to manage the creation of all pre-defined link or custom ones
```typescript
import { initialize as iniInventory } from "@medusajs/inventory";
import { initialize as iniProduct } from "@medusajs/product";
import {
initialize as iniLinks,
runMigrations as migrateLinks
} from "@medusajs/link-modules";
await Promise.all([iniInventory(), iniProduct()]);
await migrateLinks(); // create tables based on previous loaded modules
await iniLinks(); // load link based on previous loaded modules
await iniLinks(undefined, [
{
serviceName: "product_custom_translation_service_link",
isLink: true,
databaseConfig: {
tableName: "product_transalations",
},
alias: [
{
name: "translations",
},
],
primaryKeys: ["id", "product_id", "translation_id"],
relationships: [
{
serviceName: Modules.PRODUCT,
primaryKey: "id",
foreignKey: "product_id",
alias: "product",
},
{
serviceName: "custom_translation_service",
primaryKey: "id",
foreignKey: "translation_id",
alias: "transalation",
deleteCascade: true,
},
],
extends: [
{
serviceName: Modules.PRODUCT,
relationship: {
serviceName: "product_custom_translation_service_link",
primaryKey: "product_id",
foreignKey: "id",
alias: "translations",
isList: true,
},
},
{
serviceName: "custom_translation_service",
relationship: {
serviceName: "product_custom_translation_service_link",
primaryKey: "product_id",
foreignKey: "id",
alias: "product_link",
},
},
],
},
]); // custom links
```
Remote Link
```typescript
import { RemoteLink, Modules } from "@medusajs/modules-sdk";
// [...] initialize modules and links
const remoteLink = new RemoteLink();
// upsert the relationship
await remoteLink.create({ // one (object) or many (array)
[Modules.PRODUCT]: {
variant_id: "var_abc",
},
[Modules.INVENTORY]: {
inventory_item_id: "iitem_abc",
},
data: { // optional additional fields
required_quantity: 5
}
});
// dismiss (doesn't cascade)
await remoteLink.dismiss({ // one (object) or many (array)
[Modules.PRODUCT]: {
variant_id: "var_abc",
},
[Modules.INVENTORY]: {
inventory_item_id: "iitem_abc",
},
});
// delete
await remoteLink.delete({
// every key is a module
[Modules.PRODUCT]: {
// every key is a linkable field
variant_id: "var_abc", // single or multiple values
},
});
// restore
await remoteLink.restore({
// every key is a module
[Modules.PRODUCT]: {
// every key is a linkable field
variant_id: "var_abc", // single or multiple values
},
});
```
Co-authored-by: Riqwan Thamir <5105988+riqwan@users.noreply.github.com>
This commit is contained in:
co-authored by
Riqwan Thamir
parent
bc4c9e0d32
commit
4d16acf5f0
@@ -23,7 +23,7 @@
|
||||
"ioredis": "^5.2.5",
|
||||
"rimraf": "^5.0.1",
|
||||
"typeorm": "^0.3.16",
|
||||
"typescript": "^4.4.4",
|
||||
"typescript": "^5.1.6",
|
||||
"winston": "^3.8.2"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FindOptions } from "./index"
|
||||
import { RepositoryTransformOptions } from "../common"
|
||||
import { Context } from "../shared-context"
|
||||
import { FindOptions } from "./index"
|
||||
|
||||
/**
|
||||
* Data access layer (DAL) interface to implements for any repository service.
|
||||
@@ -54,7 +54,10 @@ export interface RepositoryService<T = any> extends BaseRepositoryService<T> {
|
||||
context?: Context
|
||||
): Promise<[T[], Record<string, unknown[]>]>
|
||||
|
||||
restore(ids: string[], context?: Context): Promise<T[]>
|
||||
restore(
|
||||
ids: string[],
|
||||
context?: Context
|
||||
): Promise<[T[], Record<string, unknown[]>]>
|
||||
}
|
||||
|
||||
export interface TreeRepositoryService<T = any>
|
||||
@@ -75,3 +78,11 @@ export interface TreeRepositoryService<T = any>
|
||||
|
||||
delete(id: string, context?: Context): Promise<void>
|
||||
}
|
||||
|
||||
export type SoftDeleteReturn<TReturnableLinkableKeys = string> = {
|
||||
returnLinkableKeys?: TReturnableLinkableKeys[]
|
||||
}
|
||||
|
||||
export type RestoreReturn<TReturnableLinkableKeys = string> = {
|
||||
returnLinkableKeys?: TReturnableLinkableKeys[]
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ export * from "./feature-flag"
|
||||
export * from "./file-service"
|
||||
export * from "./inventory"
|
||||
export * from "./joiner"
|
||||
export * from "./link-modules"
|
||||
export * from "./logger"
|
||||
export * from "./modules-sdk"
|
||||
export * from "./pricing"
|
||||
|
||||
@@ -13,11 +13,11 @@ import {
|
||||
} from "./common"
|
||||
|
||||
import { FindConfig } from "../common"
|
||||
import { JoinerServiceConfig } from "../joiner"
|
||||
import { SharedContext } from ".."
|
||||
import { ModuleJoinerConfig } from "../modules-sdk"
|
||||
import { SharedContext } from "../shared-context"
|
||||
|
||||
export interface IInventoryService {
|
||||
__joinerConfig(): JoinerServiceConfig
|
||||
__joinerConfig(): ModuleJoinerConfig
|
||||
listInventoryItems(
|
||||
selector: FilterableInventoryItemProps,
|
||||
config?: FindConfig<InventoryItemDTO>,
|
||||
|
||||
@@ -28,7 +28,11 @@ export interface JoinerServiceConfig {
|
||||
export interface JoinerArgument {
|
||||
name: string
|
||||
value?: any
|
||||
field?: string
|
||||
}
|
||||
|
||||
export interface JoinerDirective {
|
||||
name: string
|
||||
value?: any
|
||||
}
|
||||
|
||||
export interface RemoteJoinerQuery {
|
||||
@@ -38,10 +42,11 @@ export interface RemoteJoinerQuery {
|
||||
property: string
|
||||
fields: string[]
|
||||
args?: JoinerArgument[]
|
||||
relationships?: JoinerRelationship[]
|
||||
directives?: { [field: string]: JoinerDirective[] }
|
||||
}>
|
||||
fields: string[]
|
||||
args?: JoinerArgument[]
|
||||
directives?: { [field: string]: JoinerDirective[] }
|
||||
}
|
||||
|
||||
export interface RemoteNestedExpands {
|
||||
@@ -54,6 +59,7 @@ export interface RemoteNestedExpands {
|
||||
|
||||
export interface RemoteExpandProperty {
|
||||
property: string
|
||||
parent: string
|
||||
serviceConfig: JoinerServiceConfig
|
||||
fields: string[]
|
||||
args?: JoinerArgument[]
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { FindConfig } from "../common"
|
||||
import { RestoreReturn, SoftDeleteReturn } from "../dal"
|
||||
import { ModuleJoinerConfig } from "../modules-sdk"
|
||||
import { Context } from "../shared-context"
|
||||
|
||||
export interface ILinkModule {
|
||||
__joinerConfig(): ModuleJoinerConfig
|
||||
|
||||
list(
|
||||
filters?: Record<string, unknown>,
|
||||
config?: FindConfig<unknown>,
|
||||
sharedContext?: Context
|
||||
): Promise<unknown[]>
|
||||
|
||||
listAndCount(
|
||||
filters?: Record<string, unknown>,
|
||||
config?: FindConfig<unknown>,
|
||||
sharedContext?: Context
|
||||
): Promise<[unknown[], number]>
|
||||
|
||||
create(
|
||||
primaryKeyOrBulkData:
|
||||
| string
|
||||
| string[]
|
||||
| [string | string[], string, Record<string, unknown>?][],
|
||||
foreignKeyData?: string,
|
||||
sharedContext?: Context
|
||||
): Promise<unknown[]>
|
||||
|
||||
dismiss(
|
||||
primaryKeyOrBulkData: string | string[] | [string | string[], string][],
|
||||
foreignKeyData?: string,
|
||||
sharedContext?: Context
|
||||
): Promise<unknown[]>
|
||||
|
||||
delete(data: unknown | unknown[], sharedContext?: Context): Promise<void>
|
||||
|
||||
softDelete(
|
||||
data: unknown | unknown[],
|
||||
config?: SoftDeleteReturn,
|
||||
sharedContext?: Context
|
||||
): Promise<Record<string, unknown[]> | void>
|
||||
|
||||
restore(
|
||||
data: unknown | unknown[],
|
||||
config?: RestoreReturn,
|
||||
sharedContext?: Context
|
||||
): Promise<Record<string, unknown[]> | void>
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import { JoinerServiceConfig } from "../joiner"
|
||||
import { Logger } from "../logger"
|
||||
import { JoinerRelationship, JoinerServiceConfig } from "../joiner"
|
||||
|
||||
import { MedusaContainer } from "../common"
|
||||
import { RepositoryService } from "../dal"
|
||||
import { Logger } from "../logger"
|
||||
|
||||
export type Constructor<T> = new (...args: any[]) => T
|
||||
export * from "../common/medusa-container"
|
||||
@@ -30,6 +31,9 @@ export type InternalModuleDeclaration = {
|
||||
scope: MODULE_SCOPE.INTERNAL
|
||||
resources: MODULE_RESOURCE_TYPE
|
||||
dependencies?: string[]
|
||||
/**
|
||||
* @deprecated The property should not be used.
|
||||
*/
|
||||
resolve?: string
|
||||
options?: Record<string, unknown>
|
||||
alias?: string // If multiple modules are registered with the same key, the alias can be used to differentiate them
|
||||
@@ -43,6 +47,7 @@ export type ExternalModuleDeclaration = {
|
||||
url: string
|
||||
keepAlive: boolean
|
||||
}
|
||||
options?: Record<string, unknown>
|
||||
alias?: string // If multiple modules are registered with the same key, the alias can be used to differentiate them
|
||||
main?: boolean // If the module is the main module for the key when multiple ones are registered
|
||||
}
|
||||
@@ -61,17 +66,38 @@ export type ModuleDefinition = {
|
||||
registrationName: string
|
||||
defaultPackage: string | false
|
||||
label: string
|
||||
/**
|
||||
* @deprecated property will be removed in future versions
|
||||
*/
|
||||
canOverride?: boolean
|
||||
/**
|
||||
* @deprecated property will be removed in future versions
|
||||
*/
|
||||
isRequired?: boolean
|
||||
isQueryable?: boolean // If the modules should be queryable via Remote Joiner
|
||||
isQueryable?: boolean // If the module is queryable via Remote Joiner
|
||||
dependencies?: string[]
|
||||
defaultModuleDeclaration:
|
||||
| InternalModuleDeclaration
|
||||
| ExternalModuleDeclaration
|
||||
}
|
||||
|
||||
export type LinkModuleDefinition = {
|
||||
key: string
|
||||
registrationName: string
|
||||
label: string
|
||||
dependencies?: string[]
|
||||
defaultModuleDeclaration: InternalModuleDeclaration
|
||||
}
|
||||
|
||||
type ModuleDeclaration = ExternalModuleDeclaration | InternalModuleDeclaration
|
||||
export type ModuleConfig = ModuleDeclaration & {
|
||||
module: string
|
||||
path: string
|
||||
definition: ModuleDefinition
|
||||
}
|
||||
|
||||
export type LoadedModule = unknown & {
|
||||
__joinerConfig: JoinerServiceConfig
|
||||
__joinerConfig: ModuleJoinerConfig
|
||||
__definition: ModuleDefinition
|
||||
}
|
||||
|
||||
@@ -91,6 +117,60 @@ export type ModulesResponse = {
|
||||
resolution: string | false
|
||||
}[]
|
||||
|
||||
export type ModuleJoinerConfig = Omit<
|
||||
JoinerServiceConfig,
|
||||
"serviceName" | "primaryKeys" | "relationships" | "extends"
|
||||
> & {
|
||||
relationships?: ModuleJoinerRelationship[]
|
||||
extends?: {
|
||||
serviceName: string
|
||||
relationship: ModuleJoinerRelationship
|
||||
}[]
|
||||
serviceName?: string
|
||||
primaryKeys?: string[]
|
||||
isLink?: boolean // If the module is a link module
|
||||
linkableKeys?: string[] // Keys that can be used to link to other modules
|
||||
isReadOnlyLink?: boolean // If true it expands a RemoteQuery property but doesn't create a pivot table
|
||||
databaseConfig?: {
|
||||
tableName?: string // Name of the pivot table. If not provided it is auto generated
|
||||
idPrefix?: string // Prefix for the id column. If not provided it is "link"
|
||||
extraFields?: Record<
|
||||
string,
|
||||
{
|
||||
type:
|
||||
| "date"
|
||||
| "time"
|
||||
| "datetime"
|
||||
| "bigint"
|
||||
| "blob"
|
||||
| "uint8array"
|
||||
| "array"
|
||||
| "enumArray"
|
||||
| "enum"
|
||||
| "json"
|
||||
| "integer"
|
||||
| "smallint"
|
||||
| "tinyint"
|
||||
| "mediumint"
|
||||
| "float"
|
||||
| "double"
|
||||
| "boolean"
|
||||
| "decimal"
|
||||
| "string"
|
||||
| "uuid"
|
||||
| "text"
|
||||
defaultValue?: string
|
||||
nullable?: boolean
|
||||
options?: Record<string, unknown> // Mikro-orm options for the column
|
||||
}
|
||||
>
|
||||
}
|
||||
}
|
||||
|
||||
export declare type ModuleJoinerRelationship = JoinerRelationship & {
|
||||
deleteCascade?: boolean // If true, the link joiner will cascade deleting the relationship
|
||||
}
|
||||
|
||||
export type ModuleExports = {
|
||||
service: Constructor<any>
|
||||
loaders?: ModuleLoaderFunction[]
|
||||
@@ -114,6 +194,11 @@ export interface ModuleServiceInitializeOptions {
|
||||
connection?: any
|
||||
clientUrl?: string
|
||||
schema?: string
|
||||
host?: string
|
||||
port?: number
|
||||
user?: string
|
||||
password?: string
|
||||
database?: string
|
||||
driverOptions?: Record<string, unknown>
|
||||
debug?: boolean
|
||||
}
|
||||
|
||||
@@ -27,12 +27,13 @@ import {
|
||||
UpdateProductTypeDTO,
|
||||
} from "./common"
|
||||
|
||||
import { Context } from "../shared-context"
|
||||
import { FindConfig } from "../common"
|
||||
import { JoinerServiceConfig } from "../joiner"
|
||||
import { RestoreReturn, SoftDeleteReturn } from "../dal"
|
||||
import { ModuleJoinerConfig } from "../modules-sdk"
|
||||
import { Context } from "../shared-context"
|
||||
|
||||
export interface IProductModuleService {
|
||||
__joinerConfig(): JoinerServiceConfig
|
||||
__joinerConfig(): ModuleJoinerConfig
|
||||
|
||||
retrieve(
|
||||
productId: string,
|
||||
@@ -241,9 +242,13 @@ export interface IProductModuleService {
|
||||
|
||||
softDelete<TReturnableLinkableKeys extends string = string>(
|
||||
productIds: string[],
|
||||
config?: { returnLinkableKeys?: TReturnableLinkableKeys[] },
|
||||
config?: SoftDeleteReturn<TReturnableLinkableKeys>,
|
||||
sharedContext?: Context
|
||||
): Promise<Record<string, string[]> | void>
|
||||
|
||||
restore(productIds: string[], sharedContext?: Context): Promise<ProductDTO[]>
|
||||
restore<TReturnableLinkableKeys extends string = string>(
|
||||
productIds: string[],
|
||||
config?: RestoreReturn<TReturnableLinkableKeys>,
|
||||
sharedContext?: Context
|
||||
): Promise<Record<string, string[]> | void>
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import { FindConfig } from "../common/common"
|
||||
import { JoinerServiceConfig } from "../joiner"
|
||||
import { SharedContext } from "../shared-context"
|
||||
import {
|
||||
CreateStockLocationInput,
|
||||
FilterableStockLocationProps,
|
||||
@@ -8,8 +5,12 @@ import {
|
||||
UpdateStockLocationInput,
|
||||
} from "./common"
|
||||
|
||||
import { FindConfig } from "../common/common"
|
||||
import { ModuleJoinerConfig } from "../modules-sdk"
|
||||
import { SharedContext } from "../shared-context"
|
||||
|
||||
export interface IStockLocationService {
|
||||
__joinerConfig(): JoinerServiceConfig
|
||||
__joinerConfig(): ModuleJoinerConfig
|
||||
list(
|
||||
selector: FilterableStockLocationProps,
|
||||
config?: FindConfig<StockLocationDTO>,
|
||||
|
||||
Reference in New Issue
Block a user