vona-module-a-orm 5.0.84 → 5.0.85

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,4 +1,7 @@
1
+ import type { IDecoratorDatabaseDialectOptions } from 'vona-module-a-orm';
1
2
  import { BeanDatabaseDialectBase, DatabaseDialect } from 'vona-module-a-orm';
2
3
 
3
- @DatabaseDialect()
4
+ export interface IDatabaseDialectOptions<%=argv.beanNameCapitalize%> extends IDecoratorDatabaseDialectOptions {}
5
+
6
+ @DatabaseDialect<IDatabaseDialectOptions<%=argv.beanNameCapitalize%>>()
4
7
  export class DatabaseDialect<%=argv.beanNameCapitalize%> extends BeanDatabaseDialectBase {}
@@ -1,12 +1,15 @@
1
1
  import type { FunctionAsync } from 'vona';
2
2
  import type { ConfigDatabaseClient } from '../types/config.ts';
3
- import type { IDatabaseClientRecord, IDbInfo } from '../types/database.ts';
3
+ import type { IDatabaseClientDialectRecord, IDatabaseClientRecord, IDbInfo } from '../types/database.ts';
4
+ import type { BeanDatabaseDialectBase } from './bean.databaseDialectBase.ts';
4
5
  import { BeanBase } from 'vona';
5
6
  import { ServiceDatabaseClient } from '../service/databaseClient_.ts';
6
7
  export declare class BeanDatabase extends BeanBase {
7
8
  get current(): import("vona-module-a-orm").ServiceDb;
8
9
  getClient(dbInfoOrClientName?: Partial<IDbInfo> | keyof IDatabaseClientRecord, clientConfig?: ConfigDatabaseClient): ServiceDatabaseClient;
9
10
  getDb(dbInfoOrClientName?: Partial<IDbInfo> | keyof IDatabaseClientRecord, clientConfig?: ConfigDatabaseClient): import("vona-module-a-orm").ServiceDb;
11
+ getDialect(client: keyof IDatabaseClientDialectRecord): BeanDatabaseDialectBase;
10
12
  switchDbIsolate<RESULT>(fn: FunctionAsync<RESULT>, dbInfoOrClientName?: Partial<IDbInfo> | keyof IDatabaseClientRecord): Promise<RESULT>;
11
13
  switchDb<RESULT>(fn: FunctionAsync<RESULT>, dbInfoOrClientName?: Partial<IDbInfo> | keyof IDatabaseClientRecord): Promise<RESULT>;
14
+ private _prepareClientConfig;
12
15
  }
@@ -2,18 +2,24 @@ import type { Knex } from 'knex';
2
2
  import type { TableIdentity } from 'table-identity';
3
3
  import type { ITableColumn } from '../types/columns.ts';
4
4
  import type { ConfigDatabaseClient } from '../types/config.ts';
5
- import type { IFetchDatabasesResultItem, IFetchIndexesResultItem } from '../types/dialect.ts';
5
+ import type { IDatabaseDialectCapabilities, IFetchDatabasesResultItem, IFetchIndexesResultItem, TypeDatabaseDialectTableColumnsFn } from '../types/dialect.ts';
6
6
  import { BeanBase } from 'vona';
7
7
  export declare class BeanDatabaseDialectBase extends BeanBase {
8
+ protected _capabilities?: IDatabaseDialectCapabilities;
9
+ get capabilities(): IDatabaseDialectCapabilities;
8
10
  getConfigBase(): ConfigDatabaseClient | undefined;
9
11
  fetchDatabases(_schemaBuilder: Knex.SchemaBuilder, _databasePrefix: string): Promise<IFetchDatabasesResultItem[]>;
10
- createDatabase(_schemaBuilder: Knex.SchemaBuilder, _databaseName: string): Promise<void>;
12
+ createDatabase(_schemaBuilder: Knex.SchemaBuilder, _databaseName: string): Promise<string>;
11
13
  dropDatabase(_schemaBuilder: Knex.SchemaBuilder, _databaseName: string): Promise<void>;
12
14
  fetchIndexes(_schemaBuilder: Knex.SchemaBuilder, _tableName: string): Promise<IFetchIndexesResultItem[]>;
13
15
  insert(_builder: Knex.QueryBuilder, _datas: any[]): Promise<TableIdentity[]>;
16
+ select(_builder: Knex.QueryBuilder, datas: any[], _fn: TypeDatabaseDialectTableColumnsFn): Promise<any[]>;
14
17
  query(_result: any): void;
15
18
  viewDependents(_builder: Knex.QueryBuilder, _viewName: string): Promise<string[]>;
16
19
  coerceColumn(column: Knex.ColumnInfo): ITableColumn;
20
+ protected selectAsSqlite3(_builder: Knex.QueryBuilder, datas: any[], fn: TypeDatabaseDialectTableColumnsFn): Promise<any[]>;
21
+ protected insertAsMysql(builder: Knex.QueryBuilder, datas: any[]): Promise<TableIdentity[]>;
22
+ protected insertAsPg(builder: Knex.QueryBuilder, datas: any[]): Promise<TableIdentity[]>;
17
23
  protected _coerceColumnValue(type: string, value: any): any;
18
24
  protected _safeNumber(value: any): number | undefined;
19
25
  protected _columnTypePrefixes(type: string, prefixes: string[]): boolean;
@@ -1,3 +1,4 @@
1
1
  import type { Knex } from 'knex';
2
+ import type { ServiceDb } from '../service/db_.ts';
2
3
  import type { TypeModelWhere } from '../types/modelWhere.ts';
3
- export declare function buildWhere<TRecord>(knex: Knex, builder: Knex.QueryBuilder, wheres: TypeModelWhere<TRecord>, having?: boolean): void;
4
+ export declare function buildWhere<TRecord>(db: ServiceDb, builder: Knex.QueryBuilder, wheres: TypeModelWhere<TRecord>, having?: boolean): void;
@@ -1,9 +1,8 @@
1
1
  import type { TableIdentityType } from 'table-identity';
2
- import type { TypeBeanRecordGeneralSelectorKeys, VonaApplication } from 'vona';
2
+ import type { VonaApplication } from 'vona';
3
3
  import type { IOnionOptionsMeta } from 'vona-module-a-onion';
4
4
  import type { TSummerCachePreset } from 'vona-module-a-summer';
5
- import type { IDatabaseClientDialectRecord } from '../types/database.ts';
6
- export type TypeDataBaseConfigDialects = Record<keyof IDatabaseClientDialectRecord, TypeBeanRecordGeneralSelectorKeys<'databaseDialect'>>;
5
+ import type { IDataBaseConfigDialects } from '../types/config.ts';
7
6
  export declare function config(_app: VonaApplication): {
8
7
  sharding: {
9
8
  cache: {
@@ -34,7 +33,7 @@ export declare function config(_app: VonaApplication): {
34
33
  enable: boolean;
35
34
  expired: number;
36
35
  };
37
- dialects: TypeDataBaseConfigDialects;
36
+ dialects: IDataBaseConfigDialects;
38
37
  summer: {
39
38
  enable: boolean;
40
39
  meta: IOnionOptionsMeta;
@@ -5,7 +5,7 @@ declare module 'knex' {
5
5
  namespace Knex {
6
6
  interface SchemaBuilder {
7
7
  fetchDatabases(databasePrefix: string): Promise<IFetchDatabasesResultItem[]>;
8
- createDatabase(databaseName: string): Promise<void>;
8
+ createDatabase(databaseName: string): Promise<string>;
9
9
  dropDatabase(databaseName: string): Promise<void>;
10
10
  fetchIndexes(tableName: string): Promise<IFetchIndexesResultItem[]>;
11
11
  }
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import BigNumber from 'bignumber.js';
2
- import { BeanInfo, BeanAopMethodBase, BeanBase, deepExtend, appResource, Virtual, beanFullNameFromOnionName, cast, useApp, BeanSimple, combineConfigDefault, BeanScopeBase, createBeanDecorator, PickClassInner, $Class } from 'vona';
2
+ import { BeanInfo, BeanAopMethodBase, BeanBase, deepExtend, appResource, beanFullNameFromOnionName, Virtual, cast, useApp, BeanSimple, combineConfigDefault, BeanScopeBase, createBeanDecorator, PickClassInner, $Class } from 'vona';
3
3
  import { AopMethod } from 'vona-module-a-aspect';
4
4
  import { Service, Bean, Scope } from 'vona-module-a-bean';
5
5
  import { AsyncLocalStorage, AsyncResource } from 'node:async_hooks';
@@ -190,13 +190,6 @@ let ServiceDatabase = (_dec$r = Service(), _dec2$r = BeanInfo({
190
190
  get configDatabase() {
191
191
  return this.app.config.database;
192
192
  }
193
- getDialect(client) {
194
- if (!client) throw new Error('database dialect not specified');
195
- const beanFullName = this.scope.config.dialects[client];
196
- const dialect = this.app.bean._getBean(beanFullName);
197
- if (!dialect) throw new Error(`database dialect not found: ${client}`);
198
- return dialect;
199
- }
200
193
  getClientConfig(clientName, original = false) {
201
194
  // clientConfig
202
195
  let clientConfig = this.configDatabase.clients[clientName];
@@ -206,7 +199,7 @@ let ServiceDatabase = (_dec$r = Service(), _dec2$r = BeanInfo({
206
199
  throw new Error(`database config not found: ${clientName}`);
207
200
  }
208
201
  // configBaseClient
209
- const dialect = this.scope.service.database.getDialect(clientConfig.client);
202
+ const dialect = this.bean.database.getDialect(clientConfig.client);
210
203
  const configBaseClient = dialect.getConfigBase();
211
204
  // combine
212
205
  const configBase = this.configDatabase.base;
@@ -235,7 +228,9 @@ let ServiceDatabase = (_dec$r = Service(), _dec2$r = BeanInfo({
235
228
  clientName
236
229
  };
237
230
  }
238
- prepareClientNameSelector(dbInfo) {
231
+ prepareClientNameSelector(dbInfo, dialect) {
232
+ const dialect2 = typeof dialect === 'string' ? this.bean.database.getDialect(dialect) : dialect;
233
+ if (!dialect2.capabilities.level) return dbInfo.clientName;
239
234
  // combine
240
235
  return dbInfo.level === 0 ? dbInfo.clientName : `${dbInfo.clientName}:${dbInfo.level}`;
241
236
  }
@@ -390,18 +385,18 @@ let ServiceTransactionState = (_dec$o = Service(), _dec2$o = BeanInfo({
390
385
  get serviceDatabase() {
391
386
  return this.bean._getBean(ServiceDatabase);
392
387
  }
393
- get(dbInfo) {
394
- const selector = this.serviceDatabase.prepareClientNameSelector(dbInfo);
388
+ get(db) {
389
+ const selector = this.serviceDatabase.prepareClientNameSelector(db.info, db.dialect);
395
390
  return this._fibers[selector];
396
391
  }
397
- add(dbInfo, connection) {
398
- const selector = this.serviceDatabase.prepareClientNameSelector(dbInfo);
392
+ add(db, connection) {
393
+ const selector = this.serviceDatabase.prepareClientNameSelector(db.info, db.dialect);
399
394
  const fiber = this.bean._newBean(ServiceTransactionFiber, connection);
400
395
  this._fibers[selector] = fiber;
401
396
  return fiber;
402
397
  }
403
- remove(dbInfo) {
404
- const selector = this.serviceDatabase.prepareClientNameSelector(dbInfo);
398
+ remove(db) {
399
+ const selector = this.serviceDatabase.prepareClientNameSelector(db.info, db.dialect);
405
400
  delete this._fibers[selector];
406
401
  }
407
402
  }) || _class$o) || _class$o);
@@ -447,7 +442,7 @@ let ServiceTransaction = (_dec$m = Service(), _dec2$m = BeanInfo({
447
442
  return this.bean._getBean(ServiceTransactionAsyncLocalStorage).transactionState;
448
443
  }
449
444
  get transactionFiber() {
450
- return this.transactionState.get(this._db.info);
445
+ return this.transactionState.get(this._db);
451
446
  }
452
447
  get inTransaction() {
453
448
  return !!this.transactionFiber;
@@ -528,7 +523,7 @@ let ServiceTransaction = (_dec$m = Service(), _dec2$m = BeanInfo({
528
523
  if (!this.inTransaction) {
529
524
  const connection = this._db.client.connection;
530
525
  const transactionConnection = await connection.transaction(_translateTransactionOptions(options));
531
- fiber = this.transactionState.add(this._db.info, transactionConnection);
526
+ fiber = this.transactionState.add(this._db, transactionConnection);
532
527
  }
533
528
  // fn
534
529
  try {
@@ -536,19 +531,19 @@ let ServiceTransaction = (_dec$m = Service(), _dec2$m = BeanInfo({
536
531
  } catch (err) {
537
532
  if (fiber) {
538
533
  await fiber.doRollback();
539
- this.transactionState.remove(this._db.info);
534
+ this.transactionState.remove(this._db);
540
535
  }
541
536
  throw err;
542
537
  }
543
538
  try {
544
539
  if (fiber) {
545
540
  await fiber.doCommit();
546
- this.transactionState.remove(this._db.info);
541
+ this.transactionState.remove(this._db);
547
542
  }
548
543
  } catch (err) {
549
544
  if (fiber) {
550
545
  await fiber.doRollback();
551
- this.transactionState.remove(this._db.info);
546
+ this.transactionState.remove(this._db);
552
547
  }
553
548
  throw err;
554
549
  }
@@ -613,7 +608,7 @@ let ServiceDb = (_dec$l = Service(), _dec2$l = BeanInfo({
613
608
  return this.client.clientConfig.client;
614
609
  }
615
610
  get dialect() {
616
- return this.scope.service.database.getDialect(this.dialectName);
611
+ return this.bean.database.getDialect(this.dialectName);
617
612
  }
618
613
  async commit(cb, options) {
619
614
  return await this.transaction.commit(cb, options);
@@ -680,8 +675,8 @@ let ServiceDatabaseClient = (_dec$k = Service(), _dec2$k = BeanInfo({
680
675
  const dbInfo = this.scope.service.database.parseClientNameSelector(clientNameSelector);
681
676
  this.level = dbInfo.level;
682
677
  this.clientName = dbInfo.clientName;
683
- // config
684
- this.clientConfig = clientConfig ? deepExtend({}, clientConfig) : this.scope.service.database.getClientConfig(this.clientName);
678
+ // config: inited by bean.database.getClient
679
+ this.clientConfig = clientConfig;
685
680
  // knex
686
681
  this._knex = knex(this.clientConfig);
687
682
  }
@@ -704,9 +699,9 @@ let ServiceDatabaseClient = (_dec$k = Service(), _dec2$k = BeanInfo({
704
699
  _prepareDatabaseName(databaseName) {
705
700
  const result = {};
706
701
  const connection = this.clientConfig.connection;
707
- if (connection.database) {
702
+ if (connection.database !== undefined) {
708
703
  result.database = databaseName;
709
- } else if (connection.filename) {
704
+ } else if (connection.filename !== undefined) {
710
705
  result.filename = databaseName;
711
706
  }
712
707
  return result;
@@ -737,16 +732,26 @@ let BeanDatabase = (_dec$j = Bean(), _dec2$j = BeanInfo({
737
732
  }
738
733
  getClient(dbInfoOrClientName, clientConfig) {
739
734
  const dbInfo = this.scope.service.database.prepareDbInfo(dbInfoOrClientName);
740
- const selector = this.scope.service.database.prepareClientNameSelector(dbInfo);
741
- return this.app.bean._getBeanSelector(ServiceDatabaseClient, selector, clientConfig);
735
+ const clientConfigReal = this._prepareClientConfig(dbInfo.clientName, clientConfig);
736
+ const selector = this.scope.service.database.prepareClientNameSelector(dbInfo, clientConfigReal.client);
737
+ return this.app.bean._getBeanSelector(ServiceDatabaseClient, selector, clientConfigReal);
742
738
  }
743
739
  getDb(dbInfoOrClientName, clientConfig) {
744
740
  return this.getClient(dbInfoOrClientName, clientConfig).db;
745
741
  }
742
+ getDialect(client) {
743
+ if (!client) throw new Error('database dialect not specified');
744
+ const beanFullName = beanFullNameFromOnionName(this.scope.config.dialects[client], 'databaseDialect');
745
+ const dialect = this.app.bean._getBean(beanFullName);
746
+ if (!dialect) throw new Error(`database dialect not found: ${client}`);
747
+ return dialect;
748
+ }
746
749
  async switchDbIsolate(fn, dbInfoOrClientName) {
747
750
  const dbInfo = this.scope.service.database.prepareDbInfo(dbInfoOrClientName);
751
+ // const level = this.app.config.database.defaultClient === 'sqlite3' ? dbInfo.level : dbInfo.level + 1;
752
+ const level = dbInfo.level + 1;
748
753
  return this.switchDb(fn, {
749
- level: dbInfo.level + 1,
754
+ level,
750
755
  clientName: dbInfo.clientName
751
756
  });
752
757
  }
@@ -761,12 +766,25 @@ let BeanDatabase = (_dec$j = Bean(), _dec2$j = BeanInfo({
761
766
  return this.bean._getBean(ServiceTransactionAsyncLocalStorage).run(fn);
762
767
  });
763
768
  }
769
+
770
+ // only for bean.database.getClient
771
+ _prepareClientConfig(clientName, clientConfig) {
772
+ return clientConfig ? deepExtend({}, clientConfig) : this.scope.service.database.getClientConfig(clientName);
773
+ }
764
774
  }) || _class$j) || _class$j);
765
775
 
766
776
  var _dec$i, _dec2$i, _dec3$7, _class$i;
767
777
  let BeanDatabaseDialectBase = (_dec$i = Bean(), _dec2$i = Virtual(), _dec3$7 = BeanInfo({
768
778
  module: "a-orm"
769
779
  }), _dec$i(_class$i = _dec2$i(_class$i = _dec3$7(_class$i = class BeanDatabaseDialectBase extends BeanBase {
780
+ constructor(...args) {
781
+ super(...args);
782
+ this._capabilities = void 0;
783
+ }
784
+ get capabilities() {
785
+ if (!this._capabilities) throw new Error('Should provide dialect capabilities');
786
+ return this._capabilities;
787
+ }
770
788
  getConfigBase() {
771
789
  return undefined;
772
790
  }
@@ -785,6 +803,9 @@ let BeanDatabaseDialectBase = (_dec$i = Bean(), _dec2$i = Virtual(), _dec3$7 = B
785
803
  async insert(_builder, _datas) {
786
804
  throw new Error('Not Implemented');
787
805
  }
806
+ async select(_builder, datas, _fn) {
807
+ return datas;
808
+ }
788
809
  query(_result) {
789
810
  throw new Error('Not Implemented');
790
811
  }
@@ -801,6 +822,51 @@ let BeanDatabaseDialectBase = (_dec$i = Bean(), _dec2$i = Virtual(), _dec3$7 = B
801
822
  // ok
802
823
  return result;
803
824
  }
825
+ async selectAsSqlite3(_builder, datas, fn) {
826
+ const columns = await fn();
827
+ // data
828
+ for (const data of datas) {
829
+ for (const columnName in columns) {
830
+ const column = columns[columnName];
831
+ if (Object.prototype.hasOwnProperty.call(data, columnName)) {
832
+ const value = data[columnName];
833
+ if (column.type === 'json' && value !== undefined && typeof value === 'string') {
834
+ data[columnName] = JSON.parse(value);
835
+ }
836
+ }
837
+ }
838
+ }
839
+ return datas;
840
+ }
841
+ async insertAsMysql(builder, datas) {
842
+ if (datas.length === 0) return [];
843
+ if (isNil(datas[0].id)) {
844
+ const ids = [];
845
+ for (const data of datas) {
846
+ const builder2 = builder.clone();
847
+ builder2.insert(data);
848
+ const items = await builder2;
849
+ ids.push(items[0]);
850
+ }
851
+ return ids;
852
+ } else {
853
+ builder.insert(datas);
854
+ await builder;
855
+ return datas.map(item => item.id);
856
+ }
857
+ }
858
+ async insertAsPg(builder, datas) {
859
+ if (datas.length === 0) return [];
860
+ if (isNil(datas[0].id)) {
861
+ builder.insert(datas).returning('id');
862
+ const items = await builder;
863
+ return items.map(item => item.id);
864
+ } else {
865
+ builder.insert(datas);
866
+ await builder;
867
+ return datas.map(item => item.id);
868
+ }
869
+ }
804
870
  _coerceColumnValue(type, value) {
805
871
  // null
806
872
  if (isNil(value)) return undefined;
@@ -934,10 +1000,10 @@ function getClassEntityFromClassModel(modelClass) {
934
1000
  // return arr;
935
1001
  // }
936
1002
 
937
- function buildWhere(knex, builder, wheres, having = false) {
938
- _buildWhereInner(having, knex, builder, wheres);
1003
+ function buildWhere(db, builder, wheres, having = false) {
1004
+ _buildWhereInner(having, db, builder, wheres);
939
1005
  }
940
- function _buildWhereInner(having, knex, builder, wheres, column) {
1006
+ function _buildWhereInner(having, db, builder, wheres, column) {
941
1007
  // skip
942
1008
  if (wheres === Op.skip) {
943
1009
  return;
@@ -952,22 +1018,22 @@ function _buildWhereInner(having, knex, builder, wheres, column) {
952
1018
  const value = wheres[key];
953
1019
  if (key[0] !== '_') {
954
1020
  // columns
955
- _buildWhereColumn(having, knex, builder, key, value);
1021
+ _buildWhereColumn(having, db, builder, key, value);
956
1022
  } else if (OpNormalValues.includes(key)) {
957
1023
  // op: normal
958
1024
  if (column) {
959
- _buildWhereColumn(having, knex, builder, column, value, key);
1025
+ _buildWhereColumn(having, db, builder, column, value, key);
960
1026
  }
961
1027
  } else {
962
1028
  const op = _checkOpJoint(key);
963
1029
  if (op) {
964
1030
  // op: joint
965
- _buildWhereOpJoint(having, knex, builder, column, value, op);
1031
+ _buildWhereOpJoint(having, db, builder, column, value, op);
966
1032
  }
967
1033
  }
968
1034
  }
969
1035
  }
970
- function _buildWhereOpJoint(having, knex, builder, column, wheres, op) {
1036
+ function _buildWhereOpJoint(having, db, builder, column, wheres, op) {
971
1037
  // skip
972
1038
  if (wheres === Op.skip) {
973
1039
  return;
@@ -977,7 +1043,7 @@ function _buildWhereOpJoint(having, knex, builder, column, wheres, op) {
977
1043
  builder[having ? 'having' : 'where'](builder => {
978
1044
  for (const key in wheres) {
979
1045
  builder.andWhere(builder => {
980
- _buildWhereInner(false, knex, builder, {
1046
+ _buildWhereInner(false, db, builder, {
981
1047
  [key]: wheres[key]
982
1048
  }, column);
983
1049
  });
@@ -990,7 +1056,7 @@ function _buildWhereOpJoint(having, knex, builder, column, wheres, op) {
990
1056
  builder[having ? 'having' : 'where'](builder => {
991
1057
  for (const key in wheres) {
992
1058
  builder.orWhere(builder => {
993
- _buildWhereInner(false, knex, builder, {
1059
+ _buildWhereInner(false, db, builder, {
994
1060
  [key]: wheres[key]
995
1061
  }, column);
996
1062
  });
@@ -1001,7 +1067,7 @@ function _buildWhereOpJoint(having, knex, builder, column, wheres, op) {
1001
1067
  // not
1002
1068
  if (op === Op.not) {
1003
1069
  builder[having ? 'havingNot' : 'whereNot'](builder => {
1004
- _buildWhereInner(false, knex, builder, wheres, column);
1070
+ _buildWhereInner(false, db, builder, wheres, column);
1005
1071
  });
1006
1072
  return;
1007
1073
  }
@@ -1015,59 +1081,52 @@ function _buildWhereOpJoint(having, knex, builder, column, wheres, op) {
1015
1081
  builder[having ? 'havingNotExists' : 'whereNotExists'](wheres);
1016
1082
  }
1017
1083
  }
1018
- function _buildWhereColumn(having, knex, builder, column, value, op) {
1084
+ function _buildWhereColumn(having, db, builder, column, value, op) {
1019
1085
  // skip
1020
1086
  if (value === Op.skip) {
1021
1087
  return;
1022
1088
  }
1023
1089
  // raw
1024
1090
  if (isRaw(value) || isRef(value)) {
1025
- _buildWhereColumnOpNormal(having, knex, builder, column, value, op ?? Op.eq);
1091
+ _buildWhereColumnOpNormal(having, db, builder, column, value, op ?? Op.eq);
1026
1092
  return;
1027
1093
  }
1028
1094
  // null/undefined
1029
1095
  if (isNil(value)) {
1030
- _buildWhereColumnOpNormal(having, knex, builder, column, value, op ?? Op.is);
1096
+ _buildWhereColumnOpNormal(having, db, builder, column, value, op ?? Op.is);
1031
1097
  return;
1032
1098
  }
1033
1099
  // array
1034
1100
  if (Array.isArray(value)) {
1035
- _buildWhereColumnOpNormal(having, knex, builder, column, value, op ?? Op.in);
1101
+ _buildWhereColumnOpNormal(having, db, builder, column, value, op ?? Op.in);
1036
1102
  return;
1037
1103
  }
1038
1104
  // date
1039
1105
  if (value instanceof Date) {
1040
- _buildWhereColumnOpNormal(having, knex, builder, column, value, op ?? Op.eq);
1106
+ _buildWhereColumnOpNormal(having, db, builder, column, value, op ?? Op.eq);
1041
1107
  return;
1042
1108
  }
1043
1109
  // object
1044
1110
  if (typeof value === 'object') {
1045
1111
  builder[having ? 'having' : 'where'](builder => {
1046
- _buildWhereInner(false, knex, builder, value, column);
1112
+ _buildWhereInner(false, db, builder, value, column);
1047
1113
  });
1048
1114
  return;
1049
1115
  }
1050
1116
  // column
1051
- _buildWhereColumnOpNormal(having, knex, builder, column, value, op ?? Op.eq);
1117
+ _buildWhereColumnOpNormal(having, db, builder, column, value, op ?? Op.eq);
1052
1118
  }
1053
- function _buildWhereColumnOpNormal(having, knex, builder, column, value, op) {
1054
- column = _checkHavingColumn(knex, column);
1055
- if (_shouldPatchLike(knex)) {
1056
- if (op === Op.startsWith) op = Op.startsWithI;
1057
- if (op === Op.endsWith) op = Op.endsWithI;
1058
- if (op === Op.includes) op = Op.includesI;
1059
- if (op === Op.eqI) op = Op.eq;
1060
- if (op === Op.notEqI) op = Op.notEq;
1061
- }
1119
+ function _buildWhereColumnOpNormal(having, db, builder, column, value, op) {
1120
+ column = _checkHavingColumn(db, column);
1062
1121
  if (op === Op.eq) {
1063
1122
  builder[having ? 'having' : 'where'](column, '=', value);
1064
1123
  } else if (op === Op.notEq) {
1065
1124
  builder[having ? 'having' : 'where'](column, '<>', value);
1066
1125
  } else if (op === Op.eqI) {
1067
- builder[having ? 'havingILike' : 'whereILike'](column, value);
1126
+ builder[_getOpILikeReal(having, db)](column, value);
1068
1127
  } else if (op === Op.notEqI) {
1069
1128
  builder[having ? 'havingNot' : 'whereNot'](builder => {
1070
- builder[having ? 'havingILike' : 'whereILike'](column, value);
1129
+ builder[_getOpILikeReal(having, db)](column, value);
1071
1130
  });
1072
1131
  } else if (op === Op.gt) {
1073
1132
  builder[having ? 'having' : 'where'](column, '>', value);
@@ -1096,27 +1155,23 @@ function _buildWhereColumnOpNormal(having, knex, builder, column, value, op) {
1096
1155
  } else if (op === Op.includes) {
1097
1156
  builder[having ? 'havingLike' : 'whereLike'](column, `%${value}%`);
1098
1157
  } else if (op === Op.startsWithI) {
1099
- builder[having ? 'havingILike' : 'whereILike'](column, `${value}%`);
1158
+ builder[_getOpILikeReal(having, db)](column, `${value}%`);
1100
1159
  } else if (op === Op.endsWithI) {
1101
- builder[having ? 'havingILike' : 'whereILike'](column, `%${value}`);
1160
+ builder[_getOpILikeReal(having, db)](column, `%${value}`);
1102
1161
  } else if (op === Op.includesI) {
1103
- builder[having ? 'havingILike' : 'whereILike'](column, `%${value}%`);
1162
+ builder[_getOpILikeReal(having, db)](column, `%${value}%`);
1104
1163
  } else if (op === Op.ref) {
1105
- builder[having ? 'having' : 'where'](column, '=', knex.ref(value));
1164
+ builder[having ? 'having' : 'where'](column, '=', db.connection.ref(value));
1106
1165
  }
1107
1166
  }
1108
- function _shouldPatchLike(knex) {
1109
- const dialectName = _getDialectName(knex);
1110
- return dialectName === 'mysql' || dialectName === 'mysql2';
1111
- }
1112
- function _getDialectName(knex) {
1113
- return knex.client.config.client;
1167
+ function _getOpILikeReal(having, db) {
1168
+ return db.dialect.capabilities.ilike ? having ? 'havingILike' : 'whereILike' : having ? 'havingLike' : 'whereLike';
1114
1169
  }
1115
- function _checkHavingColumn(knex, column) {
1170
+ function _checkHavingColumn(db, column) {
1116
1171
  let [aggr, name] = cast(column).split('_');
1117
1172
  if (!OpAggrs.includes(aggr) || !name) return column;
1118
1173
  if (aggr === 'count' && name === 'all') name = '*';
1119
- return knex.raw(`${_safeOp(aggr)}(${_safeColumn(name)})`);
1174
+ return db.connection.raw(`${_safeOp(aggr)}(${_safeColumn(name)})`);
1120
1175
  }
1121
1176
  function _checkOpJoint(op) {
1122
1177
  for (const item of OpJointValues) {
@@ -1589,7 +1644,7 @@ class BeanModelUtils extends BeanModelMeta {
1589
1644
 
1590
1645
  buildWhere(builder, wheres) {
1591
1646
  if (!wheres) return;
1592
- return buildWhere(this.connection, builder, wheres);
1647
+ return buildWhere(this.db, builder, wheres);
1593
1648
  }
1594
1649
  buildJoin(builder, join) {
1595
1650
  if (!join) return;
@@ -1677,7 +1732,7 @@ class BeanModelUtils extends BeanModelMeta {
1677
1732
  this.buildHaving(builder, having);
1678
1733
  }
1679
1734
  buildHaving(builder, having) {
1680
- return buildWhere(this.connection, builder, having, true);
1735
+ return buildWhere(this.db, builder, having, true);
1681
1736
  }
1682
1737
  prepareWhere(builder, table, where, options) {
1683
1738
  // table
@@ -1958,7 +2013,9 @@ class BeanModelCrudInner extends BeanModelView {
1958
2013
  builder = builder ?? this._select_buildParams(table, params, options);
1959
2014
  // ready
1960
2015
  this.$loggerChild('model').debug(() => `model.select: ${builder.toQuery()}`);
1961
- return await builder;
2016
+ // datas
2017
+ const datas = await builder;
2018
+ return await this.dialect.select(builder, datas, () => this.columns(table));
1962
2019
  }
1963
2020
  _select_buildParams(table, params, options) {
1964
2021
  // builder
@@ -3718,9 +3775,10 @@ function config(_app) {
3718
3775
  expired: 14 * 24 * 3600 * 1000
3719
3776
  },
3720
3777
  dialects: {
3721
- mysql: 'a-ormdialect.databaseDialect.mysql',
3722
- mysql2: 'a-ormdialect.databaseDialect.mysql3',
3723
- pg: 'a-ormdialect.databaseDialect.pg'
3778
+ 'better-sqlite3': 'a-ormdialect:betterSqlite3',
3779
+ 'mysql': 'a-ormdialect:mysql',
3780
+ 'mysql2': 'a-ormdialect:mysql3',
3781
+ 'pg': 'a-ormdialect:pg'
3724
3782
  },
3725
3783
  summer: {
3726
3784
  enable: true,
@@ -3763,7 +3821,7 @@ function ExtendSchemaBuilder(app) {
3763
3821
  ['fetchDatabases', 'createDatabase', 'dropDatabase', 'fetchIndexes'].forEach(method => {
3764
3822
  knex.SchemaBuilder.extend(method, async function (...args) {
3765
3823
  const client = cast(cast(this).client).config.client;
3766
- const dialect = app.scope('a-orm').service.database.getDialect(client);
3824
+ const dialect = app.bean.database.getDialect(client);
3767
3825
  return await dialect[method](this, ...args);
3768
3826
  });
3769
3827
  });
@@ -3911,8 +3969,8 @@ function $locale(key) {
3911
3969
  }
3912
3970
  /** scope: end */
3913
3971
 
3914
- function DatabaseDialect() {
3915
- return createBeanDecorator('databaseDialect');
3972
+ function DatabaseDialect(options) {
3973
+ return createBeanDecorator('databaseDialect', options);
3916
3974
  }
3917
3975
 
3918
3976
  function DtoAggregate(modelLike, aggrs) {
@@ -1 +1,2 @@
1
- export declare function DatabaseDialect(): ClassDecorator;
1
+ import type { IDecoratorDatabaseDialectOptions } from '../types/index.ts';
2
+ export declare function DatabaseDialect<T extends IDecoratorDatabaseDialectOptions>(options?: T): ClassDecorator;
@@ -4,10 +4,9 @@ import type { IDatabaseClientDialectRecord, IDatabaseClientRecord, IDbInfo } fro
4
4
  import { BeanBase } from 'vona';
5
5
  export declare class ServiceDatabase extends BeanBase {
6
6
  get configDatabase(): import("../types/config.ts").ConfigDatabase;
7
- getDialect(client: keyof IDatabaseClientDialectRecord): BeanDatabaseDialectBase;
8
7
  getClientConfig(clientName: keyof IDatabaseClientRecord, original?: boolean): ConfigDatabaseClient;
9
8
  prepareDbInfo(dbInfoOrClientName?: Partial<IDbInfo> | keyof IDatabaseClientRecord): IDbInfo;
10
- prepareClientNameSelector(dbInfo: IDbInfo): string;
9
+ prepareClientNameSelector(dbInfo: IDbInfo, dialect: BeanDatabaseDialectBase | keyof IDatabaseClientDialectRecord): string;
11
10
  parseClientNameSelector(clientNameSelector: string): IDbInfo;
12
11
  prepareClientName(clientName?: keyof IDatabaseClientRecord): keyof IDatabaseClientRecord;
13
12
  getDefaultClientName(): keyof IDatabaseClientRecord;
@@ -1,11 +1,11 @@
1
1
  import type knex from 'knex';
2
- import type { IDbInfo } from '../types/index.ts';
2
+ import type { ServiceDb } from './db_.ts';
3
3
  import { BeanBase } from 'vona';
4
4
  import { ServiceTransactionFiber } from './transactionFiber_.ts';
5
5
  export declare class ServiceTransactionState extends BeanBase {
6
6
  private _fibers;
7
7
  private get serviceDatabase();
8
- get(dbInfo: IDbInfo): ServiceTransactionFiber | undefined;
9
- add(dbInfo: IDbInfo, connection: knex.Knex.Transaction): ServiceTransactionFiber;
10
- remove(dbInfo: IDbInfo): void;
8
+ get(db: ServiceDb): ServiceTransactionFiber | undefined;
9
+ add(db: ServiceDb, connection: knex.Knex.Transaction): ServiceTransactionFiber;
10
+ remove(db: ServiceDb): void;
11
11
  }
@@ -1,6 +1,7 @@
1
1
  import type { Knex } from 'knex';
2
2
  import type { VonaContext } from 'vona';
3
3
  import type { IDatabaseClientDialectRecord, IDatabaseClientRecord } from './database.ts';
4
+ import type { IDatabaseDialectRecord } from './onion/databaseDialect.ts';
4
5
  export type TypeDefaultClientNameFn = (ctx?: VonaContext) => keyof IDatabaseClientRecord;
5
6
  export type TypeDefaultClientName = TypeDefaultClientNameFn | keyof IDatabaseClientRecord;
6
7
  export interface ConfigDatabaseClient extends Omit<Knex.Config, 'client'> {
@@ -12,3 +13,6 @@ export interface ConfigDatabase {
12
13
  clients: Record<keyof IDatabaseClientRecord, ConfigDatabaseClient>;
13
14
  base: ConfigDatabaseClient;
14
15
  }
16
+ export type IDataBaseConfigDialects = {
17
+ [KEY in keyof IDatabaseClientDialectRecord]: keyof IDatabaseDialectRecord;
18
+ };
@@ -8,13 +8,15 @@ export interface IDbInfo {
8
8
  }
9
9
  export interface IDatabaseClientRecord {
10
10
  default: never;
11
+ sqlite3: never;
11
12
  pg: never;
12
13
  mysql: never;
13
14
  }
14
15
  export interface IDatabaseClientDialectRecord {
15
- pg: never;
16
- mysql: never;
17
- mysql2: never;
16
+ 'better-sqlite3': never;
17
+ 'pg': never;
18
+ 'mysql': never;
19
+ 'mysql2': never;
18
20
  }
19
21
  export interface IDatabaseSwitchOptions {
20
22
  clientName?: keyof IDatabaseClientRecord;
@@ -33,6 +35,8 @@ declare module 'vona' {
33
35
  }
34
36
  interface VonaConfigEnv {
35
37
  DATABASE_DEFAULT_CLIENT: string | undefined;
38
+ DATABASE_CLIENT_SQLITE3_FILENAME: string | undefined;
39
+ DATABASE_CLIENT_SQLITE3_NATIVEBINDING: string | undefined;
36
40
  DATABASE_CLIENT_PG_HOST: string | undefined;
37
41
  DATABASE_CLIENT_PG_PORT: string | undefined;
38
42
  DATABASE_CLIENT_PG_USER: string | undefined;
@@ -1,6 +1,12 @@
1
+ import type { ITableColumns } from './columns.ts';
1
2
  export interface IFetchDatabasesResultItem {
2
3
  name: string;
3
4
  }
4
5
  export interface IFetchIndexesResultItem {
5
6
  indexName: string;
6
7
  }
8
+ export type TypeDatabaseDialectTableColumnsFn = () => Promise<ITableColumns>;
9
+ export interface IDatabaseDialectCapabilities {
10
+ ilike: boolean;
11
+ level: boolean;
12
+ }
@@ -1,3 +1,4 @@
1
+ import type { OmitNever } from 'vona';
1
2
  import type { ServiceOnion } from 'vona-module-a-onion';
2
3
  export interface IDatabaseDialectRecord {
3
4
  }
@@ -10,6 +11,7 @@ declare module 'vona-module-a-onion' {
10
11
  }
11
12
  declare module 'vona' {
12
13
  interface ConfigOnions {
14
+ databaseDialect: OmitNever<IDatabaseDialectRecord>;
13
15
  }
14
16
  interface IBeanSceneRecord {
15
17
  databaseDialect: never;
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.84",
4
+ "version": "5.0.85",
5
5
  "title": "a-orm",
6
6
  "vonaModule": {
7
7
  "capabilities": {
@@ -33,6 +33,8 @@
33
33
  },
34
34
  "databaseDialect": {
35
35
  "beanGeneral": true,
36
+ "optionsGlobalInterfaceName": "IDecoratorDatabaseDialectOptions",
37
+ "optionsGlobalInterfaceFrom": "vona-module-a-orm",
36
38
  "boilerplate": "cli/databaseDialect/boilerplate"
37
39
  }
38
40
  }