vona-module-a-orm 5.0.59 → 5.0.61

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,110 @@
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';
10
+ type TypeMagicFieldOp = '' | 'eqI';
11
+ interface IMagicField {
12
+ type: 'auto' | 'number' | 'TableIdentity' | 'string' | 'boolean';
13
+ methods: TypeMagicFieldMethod | Array<TypeMagicFieldMethod>;
14
+ ops?: TypeMagicFieldOp | Array<TypeMagicFieldOp>;
15
+ }
16
+
17
+ // id/name/enabled/disabled/closed/active/current/
18
+ const __MagicFields: Record<string, IMagicField> = {
19
+ id: {
20
+ type: 'auto',
21
+ methods: 'getBy',
22
+ },
23
+ name: {
24
+ type: 'string',
25
+ methods: ['getBy', 'selectBy'],
26
+ ops: ['', 'eqI'],
27
+ },
28
+ enabled: {
29
+ type: 'boolean',
30
+ methods: ['getBy', 'selectBy'],
31
+ },
32
+ disabled: {
33
+ type: 'boolean',
34
+ methods: ['getBy', 'selectBy'],
35
+ },
36
+ closed: {
37
+ type: 'boolean',
38
+ methods: ['getBy', 'selectBy'],
39
+ },
40
+ active: {
41
+ type: 'boolean',
42
+ methods: ['getBy', 'selectBy'],
43
+ },
44
+ current: {
45
+ type: 'boolean',
46
+ methods: ['getBy', 'selectBy'],
47
+ },
48
+ };
49
+
50
+ export function __parseMagics(cli: BeanCliBase, ast: GoGoCode.GoGoAST, globFile: IGlobBeanFile, entityName: string) {
51
+ const { className, file } = globFile;
52
+ const astImportEntity = ast.find(`import { ${entityName} } from '$$$0'`);
53
+ const fileEntity = path.join(path.dirname(file), (astImportEntity as any).value.source.value);
54
+ const entityInfo = __parseEntityInfo(cli, fileEntity, entityName);
55
+ const modelInfo = __parseModelInfo(cli, file, className);
56
+ const contentRecords: string[] = [];
57
+ for (const fieldName in __MagicFields) {
58
+ const magicField = __MagicFields[fieldName];
59
+ if (fieldName === 'id') {
60
+ if (!modelInfo.fieldNames.includes('getById') && entityInfo.idType) {
61
+ contentRecords.push(`getById<T extends IModelGetOptions<${entityName},${className}>>(id: ${entityInfo.idType}, options?: T): Promise<TypeModelRelationResult<${entityName}, ${className}, T> | undefined>;`);
62
+ }
63
+ continue;
64
+ }
65
+ if (!entityInfo.fieldNames.includes(fieldName)) continue;
66
+ for (const method of ensureArray(magicField.methods)!) {
67
+ const ops = ensureArray(magicField.ops || [''])!;
68
+ for (const op of ops) {
69
+ const actionName = `${method}${toUpperCaseFirstChar(fieldName)}${toUpperCaseFirstChar(op)}`;
70
+ if (modelInfo.fieldNames.includes(actionName)) continue;
71
+ if (method === 'getBy') {
72
+ contentRecords.push(`${actionName}<T extends IModelGetOptions<${entityName},${className}>>(${fieldName}?: ${magicField.type}, options?: T): Promise<TypeModelRelationResult<${entityName}, ${className}, T> | undefined>;`);
73
+ } else if (method === 'selectBy') {
74
+ contentRecords.push(`${actionName}<T extends IModelSelectParams<${entityName},${className},ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(${fieldName}?: ${magicField.type}, params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelRelationResult<${entityName}, ${className}, T>[]>;`);
75
+ }
76
+ }
77
+ }
78
+ }
79
+ return contentRecords;
80
+ }
81
+
82
+ function __parseEntityInfo(cli: BeanCliBase, fileEntity: string, entityName: string) {
83
+ const content = readFileSync(fileEntity).toString();
84
+ const regexpSimple = new RegExp(`export class ${entityName} extends.*?EntityBaseSimple.*?{`);
85
+ const regexpBase = new RegExp(`export class ${entityName} extends.*?EntityBase.*?{`);
86
+ let idType;
87
+ if (content.match(regexpSimple)) {
88
+ idType = 'number';
89
+ } else if (content.match(regexpBase)) {
90
+ idType = 'TableIdentity';
91
+ }
92
+ const ast = cli.helper.gogocode(content);
93
+ const astNodes = ast.find(`export class ${entityName} extends $$$0 {$$$1}`).match.$$$1;
94
+ const fieldNames: string[] = [];
95
+ for (const astNode of astNodes) {
96
+ fieldNames.push((astNode as any).key.name);
97
+ }
98
+ return { idType, fieldNames };
99
+ }
100
+
101
+ function __parseModelInfo(cli: BeanCliBase, fileModel: string, modelName: string) {
102
+ const content = readFileSync(fileModel).toString();
103
+ const ast = cli.helper.gogocode(content);
104
+ const astNodes = ast.find(`export class ${modelName} extends $$$0 {$$$1}`).match.$$$1;
105
+ const fieldNames: string[] = [];
106
+ for (const astNode of astNodes) {
107
+ fieldNames.push((astNode as any).key.name);
108
+ }
109
+ return { fieldNames };
110
+ }
@@ -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[]>) | 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';
@@ -680,7 +681,6 @@ let ServiceDatabaseClient = (_dec$k = Service(), _dec2$k = BeanInfo({
680
681
  this.clientName = dbInfo.clientName;
681
682
  // config
682
683
  this.clientConfig = clientConfig ? deepExtend({}, clientConfig) : this.scope.service.database.getClientConfig(this.clientName);
683
- this.$loggerChild('database').debug('clientName: %s, clientConfig: %j', this.clientName, this.clientConfig);
684
684
  // knex
685
685
  this._knex = knex(this.clientConfig);
686
686
  }
@@ -3521,6 +3521,41 @@ class BeanModelCache extends BeanModelCrud {
3521
3521
  if (!columnId) return undefined;
3522
3522
  return ['number', 'string', 'bigint', 'array'].includes(typeof where[columnId]) ? where[columnId] : undefined;
3523
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
+ }
3545
+ }
3546
+ }
3547
+ function __combineMagicWhere(fieldName, op, fieldValue) {
3548
+ return {
3549
+ [fieldName]: fieldValue === undefined ? undefined : {
3550
+ [`_${op}_`]: fieldValue
3551
+ }
3552
+ };
3553
+ }
3554
+ function __parseMagicField(str) {
3555
+ const fieldName = parseFirstWord(str, true);
3556
+ if (!fieldName) return [fieldName, undefined];
3557
+ const op = toLowerCaseFirstChar(str.substring(fieldName.length)) || 'eq';
3558
+ return [fieldName, op];
3524
3559
  }
3525
3560
 
3526
3561
  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.59",
4
+ "version": "5.0.61",
5
5
  "title": "a-orm",
6
6
  "vonaModule": {
7
7
  "capabilities": {