Compare commits
16 Commits
release/1.
...
v1.0.10-rc
| Author | SHA1 | Date | |
|---|---|---|---|
| cd4ac54da4 | |||
| 3059e37a2e | |||
| 50384fa477 | |||
| ad74a635d4 | |||
| b9c15a7e80 | |||
| b6481e9134 | |||
| 9463ada410 | |||
| e9bee03f2e | |||
| bb1216becd | |||
| 4e3f087015 | |||
| d0605ab8f8 | |||
| 139386e8cd | |||
| 36f0521ba7 | |||
| 904cd6e457 | |||
| 55f5cebc86 | |||
| 8ea2ec726e |
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"moduleCode": "demo",
|
||||
"candidateVersion": "1.0.0-rc.1",
|
||||
"buildRevision": 1,
|
||||
"buildChecksum": "07cb8511791fc96f65d6353e47a1744e448158f2f766a4110d539806801c596c",
|
||||
"schemaInputChecksum": "8a55cecb643f802ef0f39ade2f31fe8313ad437d72d12b64525c0b1a6892813d",
|
||||
"branchName": "release/1.0.0-rc.1"
|
||||
"candidateVersion": "1.0.10-rc.10",
|
||||
"buildRevision": 10,
|
||||
"buildChecksum": "e4556add96ae3edd54c453115fb677f52d7f9eccb2232093e13f78fb92bed762",
|
||||
"schemaInputChecksum": "5a47ef42d5af4736ae307150625beb1cea177c191c30864747f3a4a66f9aad23",
|
||||
"branchName": "release/1.0.10-rc.10"
|
||||
}
|
||||
|
||||
5
bootstrap.js
vendored
5
bootstrap.js
vendored
@@ -11,10 +11,11 @@ function loadGeneratedSaasModule() {
|
||||
return require('./dist/saas/generated').GeneratedSaasModule;
|
||||
}
|
||||
|
||||
async function start() {
|
||||
await prepareSaasServiceHost({
|
||||
async function start(options = {}) {
|
||||
const session = await prepareSaasServiceHost({
|
||||
generated: loadGeneratedSaasModule(),
|
||||
});
|
||||
if (options.verifySession) await options.verifySession(session);
|
||||
requireExactReleaseEnvironment();
|
||||
return Bootstrap.configure({
|
||||
baseDir: path.join(__dirname, 'dist'),
|
||||
|
||||
12
package.json
12
package.json
@@ -10,17 +10,19 @@
|
||||
"build": "rimraf dist && mwtsc --cleanOutDir",
|
||||
"publish": "cool saas-model finalize",
|
||||
"start": "node bootstrap.js",
|
||||
"start:stable": "node start-stable.js",
|
||||
"test:stable": "node --test test/start-stable.test.cjs",
|
||||
"test:business": "node --test test/goods-business-input.test.cjs",
|
||||
"start:local": "cross-env NODE_ENV=local SAAS_RUNTIME_BOOTSTRAP_LOCAL_FALLBACK_ENABLED=true node bootstrap.js",
|
||||
"verify:packages": "node scripts/verify-local-packages.cjs",
|
||||
"start:frozen": "node start-frozen.js",
|
||||
"start:stable": "node start-stable.js",
|
||||
"test:stable": "node --test test/start-stable.test.cjs"
|
||||
"start:frozen": "node start-frozen.js"
|
||||
},
|
||||
"coolSaas": {
|
||||
"lifecycle": {
|
||||
"dev": "pnpm run build && pnpm run start:local",
|
||||
"test": "pnpm run typecheck",
|
||||
"build": "pnpm run build"
|
||||
"test": "pnpm run typecheck && pnpm run test:stable && pnpm run test:business",
|
||||
"build": "pnpm run build",
|
||||
"artifactDir": "dist"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import type { SaasCrudAfterChange, SaasCrudBeforeChange, SaasEventEnvelope } from '@cool-midway/module-runtime';
|
||||
|
||||
export type GoodsAddInput = {
|
||||
description?: string | null;
|
||||
price: string;
|
||||
status?: number;
|
||||
stock?: number;
|
||||
@@ -15,6 +16,7 @@ export type GoodsAddInput = {
|
||||
};
|
||||
|
||||
export type GoodsAddOutput = {
|
||||
description?: string | null;
|
||||
id: string;
|
||||
price: string;
|
||||
status: number;
|
||||
@@ -43,6 +45,7 @@ export type GoodsInfoInput = {
|
||||
};
|
||||
|
||||
export type GoodsInfoOutput = {
|
||||
description?: string | null;
|
||||
id: string;
|
||||
price: string;
|
||||
status: number;
|
||||
@@ -66,13 +69,14 @@ export type GoodsListInput = {
|
||||
};
|
||||
};
|
||||
|
||||
export type GoodsListOutput = {
|
||||
export type GoodsListOutput = ({
|
||||
description?: string | null;
|
||||
id: string;
|
||||
price: string;
|
||||
status: number;
|
||||
stock: number;
|
||||
title: string;
|
||||
}[];
|
||||
})[];
|
||||
|
||||
export type GoodsPageInput = {
|
||||
keyword?: string;
|
||||
@@ -92,13 +96,14 @@ export type GoodsPageInput = {
|
||||
};
|
||||
|
||||
export type GoodsPageOutput = {
|
||||
list: {
|
||||
list: ({
|
||||
description?: string | null;
|
||||
id: string;
|
||||
price: string;
|
||||
status: number;
|
||||
stock: number;
|
||||
title: string;
|
||||
}[];
|
||||
})[];
|
||||
pagination: {
|
||||
page: number;
|
||||
size: number;
|
||||
@@ -128,6 +133,7 @@ export type GoodsReserveStockOutput = {
|
||||
};
|
||||
|
||||
export type GoodsUpdateInput = {
|
||||
description?: string | null;
|
||||
id: string;
|
||||
price?: string;
|
||||
status?: number;
|
||||
@@ -192,6 +198,13 @@ export const Actions = {
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -199,7 +212,7 @@ export const Actions = {
|
||||
"price"
|
||||
]
|
||||
},
|
||||
"inputChecksum": "c2984884419729416e6cd81e4cddc6d82486b6dde2d9de0ca17533f69f55816a",
|
||||
"inputChecksum": "1631b9abe9afce3e828787e355f4c380fc3d6210f58260797109014763bddab7",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -221,6 +234,13 @@ export const Actions = {
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -231,7 +251,7 @@ export const Actions = {
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "bb691ac7eaa19bb231f9da14a80848262965255fb37726ab155fb9804c9a55b1",
|
||||
"outputChecksum": "744f5d2ad90a1c4e21a1ff66eaae83a3f900cdd685d6ee409f03555336c9a067",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:add"
|
||||
@@ -240,6 +260,7 @@ export const Actions = {
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -456,6 +477,13 @@ export const Actions = {
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -466,7 +494,7 @@ export const Actions = {
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "bb691ac7eaa19bb231f9da14a80848262965255fb37726ab155fb9804c9a55b1",
|
||||
"outputChecksum": "744f5d2ad90a1c4e21a1ff66eaae83a3f900cdd685d6ee409f03555336c9a067",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:info"
|
||||
@@ -475,6 +503,7 @@ export const Actions = {
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -587,6 +616,13 @@ export const Actions = {
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -598,7 +634,7 @@ export const Actions = {
|
||||
]
|
||||
}
|
||||
},
|
||||
"outputChecksum": "2182ab26245d80a9a40216cce7cadbe8217ea12813f1cf536b7a59ba0a4ed4ae",
|
||||
"outputChecksum": "909ff0a80769ea17a9a6159097c45c5097286e53f5010a514491df4d1f177518",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:list"
|
||||
@@ -607,6 +643,7 @@ export const Actions = {
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -727,6 +764,13 @@ export const Actions = {
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -768,7 +812,7 @@ export const Actions = {
|
||||
"pagination"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "15ee81575d900276aaa2437afa5ee6f41321e5b00ab58706322e5d5c0809bf8d",
|
||||
"outputChecksum": "476124b6a81b38277a80b1f773dffad01acee546c6140689abea6532d4216d2f",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:page"
|
||||
@@ -777,6 +821,7 @@ export const Actions = {
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -964,6 +1009,13 @@ export const Actions = {
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -971,7 +1023,7 @@ export const Actions = {
|
||||
],
|
||||
"minProperties": 2
|
||||
},
|
||||
"inputChecksum": "ced49f501c83dd1dce9725c913a1761566828004c851779a5db85ddd2bb9123c",
|
||||
"inputChecksum": "103a179289c7ad50a87b38efeb58b281ee2cc03c3dabbe20814e26f2b804cee8",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -994,6 +1046,7 @@ export const Actions = {
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -1044,7 +1097,7 @@ export const Crud = {
|
||||
moduleCode: "demo",
|
||||
tableCode: "goods",
|
||||
operations: ["add","delete","update","info","list","page"],
|
||||
descriptorChecksum: "22211efee07c5c1aada51d508d9c053e0d7388ad6fc0da12c95a4d1de2e3ca53",
|
||||
descriptorChecksum: "57f429f54ea377c92d648e4ffcc92611cbc288f227790cc1ff386f083bb7ce29",
|
||||
actions: {
|
||||
add: Actions.GoodsAdd,
|
||||
delete: Actions.GoodsDelete,
|
||||
|
||||
@@ -12,15 +12,16 @@ export interface GoodsRow extends Record<string, unknown> {
|
||||
price: string;
|
||||
stock: number;
|
||||
status: number;
|
||||
description?: string | null;
|
||||
}
|
||||
|
||||
export class Goods extends SaasTableModel<GoodsRow> {
|
||||
static readonly definition = defineSaasTableModel({
|
||||
"kind": "table",
|
||||
"moduleCode": "demo",
|
||||
"revision": 1,
|
||||
"schemaVersion": 1,
|
||||
"schemaInputChecksum": "8a55cecb643f802ef0f39ade2f31fe8313ad437d72d12b64525c0b1a6892813d",
|
||||
"revision": 10,
|
||||
"schemaVersion": 10,
|
||||
"schemaInputChecksum": "5a47ef42d5af4736ae307150625beb1cea177c191c30864747f3a4a66f9aad23",
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
{
|
||||
@@ -72,6 +73,16 @@ export class Goods extends SaasTableModel<GoodsRow> {
|
||||
"writable": true,
|
||||
"filterable": true,
|
||||
"sortable": true
|
||||
},
|
||||
{
|
||||
"code": "description",
|
||||
"type": "varchar",
|
||||
"nullable": true,
|
||||
"primary": false,
|
||||
"readable": true,
|
||||
"writable": true,
|
||||
"filterable": false,
|
||||
"sortable": false
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
@@ -4,9 +4,9 @@ import { defineGeneratedSaasModule } from '@cool-midway/module-runtime';
|
||||
export const GeneratedSaasModule = defineGeneratedSaasModule({
|
||||
"formatVersion": 2,
|
||||
"moduleCode": "demo",
|
||||
"revision": 1,
|
||||
"schemaVersion": 1,
|
||||
"schemaInputChecksum": "8a55cecb643f802ef0f39ade2f31fe8313ad437d72d12b64525c0b1a6892813d",
|
||||
"runtimeContractChecksum": "c1327810dd08dfd0cc1afeee99d7e9707fe14595272a3aa92ee13fc1d54aa0e5",
|
||||
"revision": 10,
|
||||
"schemaVersion": 10,
|
||||
"schemaInputChecksum": "5a47ef42d5af4736ae307150625beb1cea177c191c30864747f3a4a66f9aad23",
|
||||
"runtimeContractChecksum": "9ec90874dd2f0087423106ecffa0c17c9aa4362c597eca9eef9f25326b556c1e",
|
||||
"implementationManifestChecksum": "d18964a3d40e3c9a65d83996ca3141a56043986c395f5d4cac57c60aa72f4236"
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"manifestVersion": 1,
|
||||
"moduleCode": "demo",
|
||||
"revision": 1,
|
||||
"revision": 10,
|
||||
"schemaChecksum": null,
|
||||
"schemaInputChecksum": "8a55cecb643f802ef0f39ade2f31fe8313ad437d72d12b64525c0b1a6892813d",
|
||||
"schemaInputChecksum": "5a47ef42d5af4736ae307150625beb1cea177c191c30864747f3a4a66f9aad23",
|
||||
"actionManifestChecksum": null,
|
||||
"runtimeContractChecksum": "c1327810dd08dfd0cc1afeee99d7e9707fe14595272a3aa92ee13fc1d54aa0e5",
|
||||
"runtimeContractChecksum": "9ec90874dd2f0087423106ecffa0c17c9aa4362c597eca9eef9f25326b556c1e",
|
||||
"implementationManifestChecksum": "d18964a3d40e3c9a65d83996ca3141a56043986c395f5d4cac57c60aa72f4236",
|
||||
"actions": [
|
||||
"GoodsAdd",
|
||||
@@ -50,7 +50,7 @@
|
||||
"list",
|
||||
"page"
|
||||
],
|
||||
"descriptorChecksum": "22211efee07c5c1aada51d508d9c053e0d7388ad6fc0da12c95a4d1de2e3ca53",
|
||||
"descriptorChecksum": "57f429f54ea377c92d648e4ffcc92611cbc288f227790cc1ff386f083bb7ce29",
|
||||
"actions": {
|
||||
"add": "GoodsAdd",
|
||||
"delete": "GoodsDelete",
|
||||
@@ -86,6 +86,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -93,7 +100,7 @@
|
||||
"price"
|
||||
]
|
||||
},
|
||||
"inputChecksum": "c2984884419729416e6cd81e4cddc6d82486b6dde2d9de0ca17533f69f55816a",
|
||||
"inputChecksum": "1631b9abe9afce3e828787e355f4c380fc3d6210f58260797109014763bddab7",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -115,6 +122,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -125,7 +139,7 @@
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "bb691ac7eaa19bb231f9da14a80848262965255fb37726ab155fb9804c9a55b1",
|
||||
"outputChecksum": "744f5d2ad90a1c4e21a1ff66eaae83a3f900cdd685d6ee409f03555336c9a067",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:add"
|
||||
@@ -134,6 +148,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -343,6 +358,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -353,7 +375,7 @@
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "bb691ac7eaa19bb231f9da14a80848262965255fb37726ab155fb9804c9a55b1",
|
||||
"outputChecksum": "744f5d2ad90a1c4e21a1ff66eaae83a3f900cdd685d6ee409f03555336c9a067",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:info"
|
||||
@@ -362,6 +384,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -472,6 +495,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -483,7 +513,7 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"outputChecksum": "2182ab26245d80a9a40216cce7cadbe8217ea12813f1cf536b7a59ba0a4ed4ae",
|
||||
"outputChecksum": "909ff0a80769ea17a9a6159097c45c5097286e53f5010a514491df4d1f177518",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:list"
|
||||
@@ -492,6 +522,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -610,6 +641,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -651,7 +689,7 @@
|
||||
"pagination"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "15ee81575d900276aaa2437afa5ee6f41321e5b00ab58706322e5d5c0809bf8d",
|
||||
"outputChecksum": "476124b6a81b38277a80b1f773dffad01acee546c6140689abea6532d4216d2f",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:page"
|
||||
@@ -660,6 +698,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -842,6 +881,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -849,7 +895,7 @@
|
||||
],
|
||||
"minProperties": 2
|
||||
},
|
||||
"inputChecksum": "ced49f501c83dd1dce9725c913a1761566828004c851779a5db85ddd2bb9123c",
|
||||
"inputChecksum": "103a179289c7ad50a87b38efeb58b281ee2cc03c3dabbe20814e26f2b804cee8",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -872,6 +918,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"formatVersion": 2,
|
||||
"moduleCode": "demo",
|
||||
"revision": 1,
|
||||
"revision": 10,
|
||||
"releaseVersion": null,
|
||||
"schemaVersion": 1,
|
||||
"schemaInputChecksum": "8a55cecb643f802ef0f39ade2f31fe8313ad437d72d12b64525c0b1a6892813d",
|
||||
"schemaVersion": 10,
|
||||
"schemaInputChecksum": "5a47ef42d5af4736ae307150625beb1cea177c191c30864747f3a4a66f9aad23",
|
||||
"schemaChecksum": null,
|
||||
"actionManifestChecksum": null,
|
||||
"runtimeContractChecksum": "c1327810dd08dfd0cc1afeee99d7e9707fe14595272a3aa92ee13fc1d54aa0e5",
|
||||
"runtimeContractChecksum": "9ec90874dd2f0087423106ecffa0c17c9aa4362c597eca9eef9f25326b556c1e",
|
||||
"implementationManifestChecksum": "d18964a3d40e3c9a65d83996ca3141a56043986c395f5d4cac57c60aa72f4236",
|
||||
"models": [
|
||||
{
|
||||
@@ -65,6 +65,16 @@
|
||||
"writable": true,
|
||||
"filterable": true,
|
||||
"sortable": true
|
||||
},
|
||||
{
|
||||
"code": "description",
|
||||
"type": "varchar",
|
||||
"nullable": true,
|
||||
"primary": false,
|
||||
"readable": true,
|
||||
"writable": true,
|
||||
"filterable": false,
|
||||
"sortable": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -128,6 +138,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -135,7 +152,7 @@
|
||||
"price"
|
||||
]
|
||||
},
|
||||
"inputChecksum": "c2984884419729416e6cd81e4cddc6d82486b6dde2d9de0ca17533f69f55816a",
|
||||
"inputChecksum": "1631b9abe9afce3e828787e355f4c380fc3d6210f58260797109014763bddab7",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -157,6 +174,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -167,7 +191,7 @@
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "bb691ac7eaa19bb231f9da14a80848262965255fb37726ab155fb9804c9a55b1",
|
||||
"outputChecksum": "744f5d2ad90a1c4e21a1ff66eaae83a3f900cdd685d6ee409f03555336c9a067",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:add"
|
||||
@@ -176,6 +200,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -236,6 +261,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -243,7 +275,7 @@
|
||||
"price"
|
||||
]
|
||||
},
|
||||
"inputChecksum": "c2984884419729416e6cd81e4cddc6d82486b6dde2d9de0ca17533f69f55816a",
|
||||
"inputChecksum": "1631b9abe9afce3e828787e355f4c380fc3d6210f58260797109014763bddab7",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -265,6 +297,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -275,7 +314,7 @@
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "bb691ac7eaa19bb231f9da14a80848262965255fb37726ab155fb9804c9a55b1",
|
||||
"outputChecksum": "744f5d2ad90a1c4e21a1ff66eaae83a3f900cdd685d6ee409f03555336c9a067",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:add"
|
||||
@@ -284,6 +323,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -626,6 +666,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -636,7 +683,7 @@
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "bb691ac7eaa19bb231f9da14a80848262965255fb37726ab155fb9804c9a55b1",
|
||||
"outputChecksum": "744f5d2ad90a1c4e21a1ff66eaae83a3f900cdd685d6ee409f03555336c9a067",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:info"
|
||||
@@ -645,6 +692,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -696,6 +744,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -706,7 +761,7 @@
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "bb691ac7eaa19bb231f9da14a80848262965255fb37726ab155fb9804c9a55b1",
|
||||
"outputChecksum": "744f5d2ad90a1c4e21a1ff66eaae83a3f900cdd685d6ee409f03555336c9a067",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:info"
|
||||
@@ -715,6 +770,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -828,6 +884,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -839,7 +902,7 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"outputChecksum": "2182ab26245d80a9a40216cce7cadbe8217ea12813f1cf536b7a59ba0a4ed4ae",
|
||||
"outputChecksum": "909ff0a80769ea17a9a6159097c45c5097286e53f5010a514491df4d1f177518",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:list"
|
||||
@@ -848,6 +911,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -956,6 +1020,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -967,7 +1038,7 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"outputChecksum": "2182ab26245d80a9a40216cce7cadbe8217ea12813f1cf536b7a59ba0a4ed4ae",
|
||||
"outputChecksum": "909ff0a80769ea17a9a6159097c45c5097286e53f5010a514491df4d1f177518",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:list"
|
||||
@@ -976,6 +1047,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -1097,6 +1169,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1138,7 +1217,7 @@
|
||||
"pagination"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "15ee81575d900276aaa2437afa5ee6f41321e5b00ab58706322e5d5c0809bf8d",
|
||||
"outputChecksum": "476124b6a81b38277a80b1f773dffad01acee546c6140689abea6532d4216d2f",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:page"
|
||||
@@ -1147,6 +1226,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -1263,6 +1343,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1304,7 +1391,7 @@
|
||||
"pagination"
|
||||
]
|
||||
},
|
||||
"outputChecksum": "15ee81575d900276aaa2437afa5ee6f41321e5b00ab58706322e5d5c0809bf8d",
|
||||
"outputChecksum": "476124b6a81b38277a80b1f773dffad01acee546c6140689abea6532d4216d2f",
|
||||
"callerPolicy": {
|
||||
"kind": "permission",
|
||||
"permission": "demo:goods:page"
|
||||
@@ -1313,6 +1400,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -1642,6 +1730,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1649,7 +1744,7 @@
|
||||
],
|
||||
"minProperties": 2
|
||||
},
|
||||
"inputChecksum": "ced49f501c83dd1dce9725c913a1761566828004c851779a5db85ddd2bb9123c",
|
||||
"inputChecksum": "103a179289c7ad50a87b38efeb58b281ee2cc03c3dabbe20814e26f2b804cee8",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -1672,6 +1767,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -1736,6 +1832,13 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"maxLength": 500
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1743,7 +1846,7 @@
|
||||
],
|
||||
"minProperties": 2
|
||||
},
|
||||
"inputChecksum": "ced49f501c83dd1dce9725c913a1761566828004c851779a5db85ddd2bb9123c",
|
||||
"inputChecksum": "103a179289c7ad50a87b38efeb58b281ee2cc03c3dabbe20814e26f2b804cee8",
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -1766,6 +1869,7 @@
|
||||
{
|
||||
"tableCode": "goods",
|
||||
"fields": [
|
||||
"description",
|
||||
"id",
|
||||
"price",
|
||||
"status",
|
||||
@@ -1821,7 +1925,7 @@
|
||||
"list",
|
||||
"page"
|
||||
],
|
||||
"descriptorChecksum": "22211efee07c5c1aada51d508d9c053e0d7388ad6fc0da12c95a4d1de2e3ca53",
|
||||
"descriptorChecksum": "57f429f54ea377c92d648e4ffcc92611cbc288f227790cc1ff386f083bb7ce29",
|
||||
"actions": {
|
||||
"add": "GoodsAdd",
|
||||
"delete": "GoodsDelete",
|
||||
|
||||
@@ -44,6 +44,21 @@ export class GoodsService extends SaasCrudServiceBase<typeof Crud.Goods> {
|
||||
throw new SaasBusinessReject('STOCK_COMMAND_REQUIRED','现有商品库存只能通过受管库存命令变更');
|
||||
}
|
||||
}
|
||||
if (change.operation === 'add' || change.operation === 'update') {
|
||||
const input = change.input;
|
||||
if (Object.prototype.hasOwnProperty.call(input, 'title') && !input.title.trim()) {
|
||||
throw new SaasBusinessReject('GOODS_INPUT_INVALID', '商品名称不能为空');
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(input, 'price') && !/^(?:0|[1-9][0-9]*)(?:\.[0-9]+)?$/.test(input.price)) {
|
||||
throw new SaasBusinessReject('GOODS_INPUT_INVALID', '商品价格必须是非负金额');
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(input, 'stock') && (!Number.isSafeInteger(input.stock) || input.stock < 0 || input.stock > 2147483647)) {
|
||||
throw new SaasBusinessReject('GOODS_INPUT_INVALID', '商品库存必须是有效的非负整数');
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(input, 'status') && input.status !== 0 && input.status !== 1) {
|
||||
throw new SaasBusinessReject('GOODS_INPUT_INVALID', '商品状态仅允许下架或上架');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SaasAction(Actions.GoodsBatchInfo)
|
||||
|
||||
70
test/goods-business-input.test.cjs
Normal file
70
test/goods-business-input.test.cjs
Normal file
@@ -0,0 +1,70 @@
|
||||
'use strict';
|
||||
require('reflect-metadata');
|
||||
const assert = require('node:assert/strict');
|
||||
const test = require('node:test');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const ts = require('typescript');
|
||||
const { SaasBusinessReject } = require('@cool-midway/module-runtime');
|
||||
const sourceRoot = path.resolve(__dirname, '../src');
|
||||
const previous = require.extensions['.ts'];
|
||||
let GoodsService;
|
||||
try {
|
||||
require.extensions['.ts'] = (module, filename) => {
|
||||
assert.ok(filename.startsWith(sourceRoot + path.sep));
|
||||
const compiled = ts.transpileModule(fs.readFileSync(filename, 'utf8'), {
|
||||
fileName: filename,
|
||||
compilerOptions: { target: ts.ScriptTarget.ES2018, module: ts.ModuleKind.CommonJS,
|
||||
experimentalDecorators: true, emitDecoratorMetadata: true, esModuleInterop: true },
|
||||
});
|
||||
module._compile(compiled.outputText, filename);
|
||||
};
|
||||
({ GoodsService } = require('../src/service/goods.ts'));
|
||||
} finally {
|
||||
if (previous) require.extensions['.ts'] = previous;
|
||||
else delete require.extensions['.ts'];
|
||||
}
|
||||
function fixture(context = {}) {
|
||||
const service = new GoodsService();
|
||||
const calls = [];
|
||||
service.saasActionContext = context;
|
||||
service.inventory = { assertNoActiveReservations: async id => { calls.push(id); } };
|
||||
return { service, calls };
|
||||
}
|
||||
const rejects = code => error => error instanceof SaasBusinessReject && error.code === code;
|
||||
|
||||
test('new catalog records accept an explicit initial stock and nonnegative decimal price', async () => {
|
||||
const { service, calls } = fixture();
|
||||
await service.modifyBefore({ operation: 'add', input: { title: '验收商品', price: '12.50', stock: 20, status: 1 } });
|
||||
await service.modifyBefore({ operation: 'add', input: { title: '赠品', price: '0.00', stock: 0, status: 0 } });
|
||||
assert.deepEqual(calls, []);
|
||||
});
|
||||
|
||||
test('invalid catalog values are business rejections before persistence', async t => {
|
||||
const inputs = [{ title: ' ' }, { price: '-0.01' }, { stock: -1 }, { stock: 1.5 }, { stock: 2147483648 }, { status: 2 }];
|
||||
for (const input of inputs) await t.test(JSON.stringify(input), async () => {
|
||||
const { service } = fixture();
|
||||
await assert.rejects(service.modifyBefore({ operation: 'add', input: { title: '商品', price: '1.00', ...input } }), rejects('GOODS_INPUT_INVALID'));
|
||||
});
|
||||
});
|
||||
|
||||
test('catalog edits keep managed inventory protected even with valid stock values', async () => {
|
||||
const { service } = fixture();
|
||||
await service.modifyBefore({ operation: 'update', input: { id: '1', title: '更新名称', price: '0.00', status: 0 } });
|
||||
await assert.rejects(service.modifyBefore({ operation: 'update', input: { id: '1', stock: 2 } }), rejects('STOCK_COMMAND_REQUIRED'));
|
||||
await assert.rejects(service.modifyBefore({ operation: 'update', input: { id: '1', price: '-1.00' } }), rejects('GOODS_INPUT_INVALID'));
|
||||
});
|
||||
|
||||
test('managed stock updates retain the same domain validation', async () => {
|
||||
const { service } = fixture({ managedCrudCaller: { kind: 'business', actionName: 'goods.reserveStock' }, workflow: { coordinatorModule: 'order' } });
|
||||
await service.modifyBefore({ operation: 'update', input: { id: '1', stock: 0 } });
|
||||
await assert.rejects(service.modifyBefore({ operation: 'update', input: { id: '1', stock: -1 } }), rejects('GOODS_INPUT_INVALID'));
|
||||
});
|
||||
|
||||
test('deletion still requires the inventory reservation lock and rejects an active reservation', async () => {
|
||||
const { service, calls } = fixture();
|
||||
await service.modifyBefore({ operation: 'delete', input: { id: '1' } });
|
||||
assert.deepEqual(calls, ['1']);
|
||||
service.inventory.assertNoActiveReservations = async () => { throw new SaasBusinessReject('STOCK_RESERVATION_CONFLICT', '仍有库存预留'); };
|
||||
await assert.rejects(service.modifyBefore({ operation: 'delete', input: { id: '1' } }), rejects('STOCK_RESERVATION_CONFLICT'));
|
||||
});
|
||||
Reference in New Issue
Block a user