vona-module-a-orm 5.0.60 → 5.0.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,6 @@
1
1
  import type { IMetadataCustomGenerateOptions } from '@cabloy/cli';
2
2
  import { types as t } from '@babel/core';
3
+ import { __parseMagics } from './magic.ts';
3
4
 
4
5
  export default async function (options: IMetadataCustomGenerateOptions): Promise<string> {
5
6
  const { sceneName, moduleName, globFiles, cli } = options;
@@ -13,6 +14,7 @@ export default async function (options: IMetadataCustomGenerateOptions): Promise
13
14
  const astNodes = ast.find(`@Model<$$$0>({$$$1})export class ${className} extends $$$2 {}`).match.$$$1;
14
15
  const entityName = __parseEntityName(__getAstNode(astNodes as any, 'entity'));
15
16
  const relations = __parseRelations(__getAstNode(astNodes as any, 'relations'));
17
+ const magics = __parseMagics(cli, ast, globFile, entityName);
16
18
  const entityMetaName = `${entityName}Meta`;
17
19
  const opionsName = `IModelOptions${beanNameCapitalize}`;
18
20
  if (relations && relations.length > 0) {
@@ -41,6 +43,7 @@ export default async function (options: IMetadataCustomGenerateOptions): Promise
41
43
  count<T extends IModelSelectCountParams<${entityName},${className},ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<BigNumber | undefined>;
42
44
  aggregate<T extends IModelSelectAggrParams<${entityName},${className},ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelAggrRelationResult<T>>;
43
45
  group<T extends IModelSelectGroupParams<${entityName},${className},ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelGroupRelationResult<${entityName}, T>[]>;
46
+ ${magics.join('\n')}
44
47
  }`);
45
48
  contentModels.push(`'${moduleName}:${beanName}': ${className};`);
46
49
  // only override cache.keyAux which not enough
@@ -0,0 +1,119 @@
1
+ import type { BeanCliBase } from '@cabloy/cli';
2
+ import type { IGlobBeanFile } from '@cabloy/module-info';
3
+ import type GoGoCode from 'gogocode';
4
+ import { readFileSync } from 'node:fs';
5
+ import path from 'node:path';
6
+ import { ensureArray } from '@cabloy/utils';
7
+ import { toUpperCaseFirstChar } from '@cabloy/word-utils';
8
+
9
+ type TypeMagicFieldMethod = 'getBy' | 'selectBy' | 'updateBy' | 'deleteBy';
10
+ type TypeMagicFieldOp = '' | 'eqI';
11
+ interface IMagicField {
12
+ optional: boolean;
13
+ type: 'auto' | 'number' | 'TableIdentity' | 'string' | 'boolean';
14
+ methods: TypeMagicFieldMethod | Array<TypeMagicFieldMethod>;
15
+ ops?: TypeMagicFieldOp | Array<TypeMagicFieldOp>;
16
+ }
17
+
18
+ // id/name/enabled/disabled/closed/active/current/
19
+ const __MagicFields: Record<string, IMagicField> = {
20
+ id: {
21
+ optional: false,
22
+ type: 'auto',
23
+ methods: ['getBy', 'updateBy', 'deleteBy'],
24
+ },
25
+ name: {
26
+ optional: true,
27
+ type: 'string',
28
+ methods: ['getBy', 'selectBy'],
29
+ ops: ['', 'eqI'],
30
+ },
31
+ enabled: {
32
+ optional: true,
33
+ type: 'boolean',
34
+ methods: ['getBy', 'selectBy'],
35
+ },
36
+ disabled: {
37
+ optional: true,
38
+ type: 'boolean',
39
+ methods: ['getBy', 'selectBy'],
40
+ },
41
+ closed: {
42
+ optional: true,
43
+ type: 'boolean',
44
+ methods: ['getBy', 'selectBy'],
45
+ },
46
+ active: {
47
+ optional: true,
48
+ type: 'boolean',
49
+ methods: ['getBy', 'selectBy'],
50
+ },
51
+ current: {
52
+ optional: true,
53
+ type: 'boolean',
54
+ methods: ['getBy', 'selectBy'],
55
+ },
56
+ };
57
+
58
+ export function __parseMagics(cli: BeanCliBase, ast: GoGoCode.GoGoAST, globFile: IGlobBeanFile, entityName: string) {
59
+ const { className, file } = globFile;
60
+ const astImportEntity = ast.find(`import { ${entityName} } from '$$$0'`);
61
+ const fileEntity = path.join(path.dirname(file), (astImportEntity as any).value.source.value);
62
+ const entityInfo = __parseEntityInfo(cli, fileEntity, entityName);
63
+ const modelInfo = __parseModelInfo(cli, file, className);
64
+ const contentRecords: string[] = [];
65
+ for (const fieldName in __MagicFields) {
66
+ const magicField = __MagicFields[fieldName];
67
+ if (!entityInfo.fieldNames.includes(fieldName)) continue;
68
+ for (const method of ensureArray(magicField.methods)!) {
69
+ const ops = ensureArray(magicField.ops || [''])!;
70
+ for (const op of ops) {
71
+ const actionName = `${method}${toUpperCaseFirstChar(fieldName)}${toUpperCaseFirstChar(op)}`;
72
+ if (modelInfo.fieldNames.includes(actionName)) continue;
73
+ const optional = magicField.optional ? '?' : '';
74
+ const type = fieldName === 'id' ? entityInfo.idType : magicField.type;
75
+ if (method === 'getBy') {
76
+ contentRecords.push(`${actionName}<T extends IModelGetOptions<${entityName},${className}>>(${fieldName}${optional}: ${type}, options?: T): Promise<TypeModelRelationResult<${entityName}, ${className}, T> | undefined>;`);
77
+ } else if (method === 'selectBy') {
78
+ contentRecords.push(`${actionName}<T extends IModelSelectParams<${entityName},${className},ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(${fieldName}${optional}: ${type}, params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelRelationResult<${entityName}, ${className}, T>[]>;`);
79
+ } else if (method === 'updateBy') {
80
+ contentRecords.push(`${actionName}<T extends IModelUpdateOptions<${entityName},${className}>>(${fieldName}: ${type}${optional ? ' | undefined' : ''}, data: TypeModelMutateRelationData<${entityName},${className}, T>, options?: T): Promise<TypeModelMutateRelationData<${entityName},${className}, T>>;`);
81
+ } else if (method === 'deleteBy') {
82
+ contentRecords.push(`${actionName}<T extends IModelDeleteOptions<${entityName},${className}>>(${fieldName}${optional}: ${type}, options?: T): Promise<void>;`);
83
+ }
84
+ }
85
+ }
86
+ }
87
+ return contentRecords;
88
+ }
89
+
90
+ function __parseEntityInfo(cli: BeanCliBase, fileEntity: string, entityName: string) {
91
+ const content = readFileSync(fileEntity).toString();
92
+ const regexpSimple = new RegExp(`export class ${entityName} extends.*?EntityBaseSimple.*?{`);
93
+ const regexpBase = new RegExp(`export class ${entityName} extends.*?EntityBase.*?{`);
94
+ let idType;
95
+ if (content.match(regexpSimple)) {
96
+ idType = 'number';
97
+ } else if (content.match(regexpBase)) {
98
+ idType = 'TableIdentity';
99
+ }
100
+ const ast = cli.helper.gogocode(content);
101
+ const astNodes = ast.find(`export class ${entityName} extends $$$0 {$$$1}`).match.$$$1;
102
+ const fieldNames: string[] = [];
103
+ for (const astNode of astNodes) {
104
+ fieldNames.push((astNode as any).key.name);
105
+ }
106
+ if (idType) fieldNames.push('id');
107
+ return { idType, fieldNames };
108
+ }
109
+
110
+ function __parseModelInfo(cli: BeanCliBase, fileModel: string, modelName: string) {
111
+ const content = readFileSync(fileModel).toString();
112
+ const ast = cli.helper.gogocode(content);
113
+ const astNodes = ast.find(`export class ${modelName} extends $$$0 {$$$1}`).match.$$$1;
114
+ const fieldNames: string[] = [];
115
+ for (const astNode of astNodes) {
116
+ fieldNames.push((astNode as any).key.name);
117
+ }
118
+ return { fieldNames };
119
+ }
@@ -58,5 +58,6 @@ export declare class BeanModelCache<TRecord extends {} = {}> extends BeanModelCr
58
58
  protected _checkDisableCacheEntityByOptions(options?: IModelMethodOptionsGeneral): boolean;
59
59
  private __checkIfOnlyKey;
60
60
  private __checkCacheKeyValid;
61
+ protected __get__(prop: string): ((fieldValue?: any, options?: any) => Promise<Partial<TRecord> | undefined>) | ((fieldValue?: any, params?: any, options?: any, modelJoins?: any) => Promise<any[]>) | ((fieldValue: any, data: any, options?: any) => Promise<Partial<TRecord>>) | ((fieldValue: any, options?: any) => Promise<void>) | undefined;
61
62
  }
62
63
  export {};
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ import { swapDeps } from '@cabloy/deps';
10
10
  import { prepareClassType, getTargetDecoratorRules, getTargetDecoratorRuleColumnsMap, Api, v, OrderMaxBase, OrderCoreBase, getSchemaDynamic, SymbolSchemaDynamicRefId, addSchemaDynamic, mergeFieldsOpenapiMetadata } from 'vona-module-a-openapi';
11
11
  import { ZodMetadata } from '@cabloy/zod-openapi';
12
12
  import z from 'zod';
13
+ import { parseFirstWord, toLowerCaseFirstChar } from '@cabloy/word-utils';
13
14
  import { Broadcast, BeanBroadcastBase } from 'vona-module-a-broadcast';
14
15
  import { Event, BeanEventBase } from 'vona-module-a-event';
15
16
  import { Queue, BeanQueueBase } from 'vona-module-a-queue';
@@ -3520,6 +3521,62 @@ class BeanModelCache extends BeanModelCrud {
3520
3521
  if (!columnId) return undefined;
3521
3522
  return ['number', 'string', 'bigint', 'array'].includes(typeof where[columnId]) ? where[columnId] : undefined;
3522
3523
  }
3524
+ __get__(prop) {
3525
+ if (prop.startsWith('getBy')) {
3526
+ const [fieldName, op] = __parseMagicField(prop.substring('getBy'.length));
3527
+ if (!fieldName) throw new Error(`invalid magic method: ${prop}`);
3528
+ return (fieldValue, options) => {
3529
+ const where = __combineMagicWhere(fieldName, op, fieldValue);
3530
+ return this.get(where, options);
3531
+ };
3532
+ } else if (prop.startsWith('selectBy')) {
3533
+ const [fieldName, op] = __parseMagicField(prop.substring('selectBy'.length));
3534
+ if (!fieldName) throw new Error(`invalid magic method: ${prop}`);
3535
+ return (fieldValue, params, options, modelJoins) => {
3536
+ const where = __combineMagicWhere(fieldName, op, fieldValue);
3537
+ const params2 = params ? deepExtend({}, params, {
3538
+ where
3539
+ }) : {
3540
+ where
3541
+ };
3542
+ return this.select(params2, options, modelJoins);
3543
+ };
3544
+ } else if (prop.startsWith('updateBy')) {
3545
+ const [fieldName, op] = __parseMagicField(prop.substring('updateBy'.length));
3546
+ if (!fieldName) throw new Error(`invalid magic method: ${prop}`);
3547
+ return (fieldValue, data, options) => {
3548
+ const where = __combineMagicWhere(fieldName, op, fieldValue);
3549
+ if (fieldName === 'id') {
3550
+ data = Object.assign({}, data, where);
3551
+ } else {
3552
+ options = deepExtend({}, options, {
3553
+ where
3554
+ });
3555
+ }
3556
+ return this.update(data, options);
3557
+ };
3558
+ } else if (prop.startsWith('deleteBy')) {
3559
+ const [fieldName, op] = __parseMagicField(prop.substring('deleteBy'.length));
3560
+ if (!fieldName) throw new Error(`invalid magic method: ${prop}`);
3561
+ return (fieldValue, options) => {
3562
+ const where = __combineMagicWhere(fieldName, op, fieldValue);
3563
+ return this.delete(where, options);
3564
+ };
3565
+ }
3566
+ }
3567
+ }
3568
+ function __combineMagicWhere(fieldName, op, fieldValue) {
3569
+ return {
3570
+ [fieldName]: fieldValue === undefined ? undefined : op === 'eq' ? fieldValue : {
3571
+ [`_${op}_`]: fieldValue
3572
+ }
3573
+ };
3574
+ }
3575
+ function __parseMagicField(str) {
3576
+ const fieldName = parseFirstWord(str, true);
3577
+ if (!fieldName) return [fieldName, undefined];
3578
+ const op = toLowerCaseFirstChar(str.substring(fieldName.length)) || 'eq';
3579
+ return [fieldName, op];
3523
3580
  }
3524
3581
 
3525
3582
  var _dec$8, _dec2$8, _dec3$2, _class$8;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vona-module-a-orm",
3
3
  "type": "module",
4
- "version": "5.0.60",
4
+ "version": "5.0.62",
5
5
  "title": "a-orm",
6
6
  "vonaModule": {
7
7
  "capabilities": {