@egi/smart-db 2.4.4 → 2.4.7

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.
@@ -17,6 +17,7 @@ export declare abstract class AbstractModel<T extends AbstractModel<T, D>, D ext
17
17
  getValue(attribute: string): string | number | boolean;
18
18
  hasAttribute(attribute: string): boolean;
19
19
  clear(attributes: string | string[]): void;
20
- getPlainObject(style: FieldNamingStyle, includeVirtuals?: boolean, fields?: string[]): D;
20
+ getPlainObject(includeVirtuals?: boolean, fields?: string[]): D;
21
+ getPlainObject(style?: FieldNamingStyle, includeVirtuals?: boolean, fields?: string[]): GenericModelData;
21
22
  private toDbTimestamp;
22
23
  }
@@ -1 +1 @@
1
- import _ from"lodash";import{FieldNamingStyle}from"../smart-db-interfaces";export class AbstractModel{static getTableName(){return"overload this in child class"}static from(t){}assign(t,e){if("object"==typeof t){const i=this.getAttributeMap();let s=!e||!!e.skipUndefined;Object.keys(i).forEach(i=>{let a=!0;if(e&&(e.only&&!_.includes(e.only,i)&&(a=!1),e.exclude&&_.includes(e.exclude,i)&&(a=!1)),a)if(t instanceof AbstractModel&&t.hasAttribute(i)){const e=t.getValue(i);s&&void 0===e||this.setValue(i,e)}else if(t.hasOwnProperty(i)){const e=t[i];s&&void 0===e||this.setValue(i,e)}})}}setValue(t,e){const i=this.getAttributeMap()[t];if(!i)throw`unknown attribute ${t} for ${this.getClassName()}`;if(null===e)this[i.attribute]=null;else if(void 0===e)delete this[i.attribute];else{switch(i.type){case"SqlValueType":break;case"string":_.isNumber(e)?e=e.toString():_.isBoolean(e)?e=e?"true":"false":_.isDate(e)&&(e=this.toDbTimestamp(e));break;case"number":_.isString(e)?e=parseFloat(e):_.isBoolean(e)?e=e?1:0:_.isDate(e)&&(e=e.getTime());break;case"boolean":_.isString(e)?e=!e.match(/(F|N|false|no|0)/i):_.isNumber(e)?e=!!e:_.isDate(e)&&(e=!0);break;case"Date":_.isString(e)&&e.match(/^\d{4}-[01][0-9]-[0-3][0-9][ T][0-2][0-9]:[0-5][0-9]:[0-5][0-9]\s*$/)&&(e+=" GMT"),e=_.isNumber(e)||_.isString(e)||_.isDate(e)?new Date(e):new Date;break;default:throw`AbstractModel.setValue: unknown data type '${i.type}'`}this[i.attribute]=e}}getValue(t){return this[this.getAttributeMap()[t].attribute]}hasAttribute(t){return!!this.getAttributeMap()[t]}clear(t){_.isArray(t)||(t=[t]);const e=this.getAttributeMap();t.forEach(t=>{const i=e[t];i&&delete this[i.attribute]})}getPlainObject(t,e,i){const s=this.getAttributeMap(),a=[];void 0===e&&(e=!0),_.forOwn(s,(s,r)=>{let l=t==FieldNamingStyle.All||e&&s.virtual;if(!l)if(t==FieldNamingStyle.Database)l=s.physical;else{if(t!=FieldNamingStyle.TypeScript)throw"unknown style "+t;l=s.typeScriptStyle}l&&(i&&!_.includes(i,r)||a.push(r))});const r={};return a.forEach(t=>{const e=s[t];if(e){const i=this[e.attribute];void 0!==i&&(r[t]=i)}}),r}toDbTimestamp(t){let e;return t&&(_.isNumber(t)&&(t=new Date(t)),e=t.toISOString().substr(0,23).replace("T"," ")),e}}AbstractModel.attributeMap={};
1
+ import _ from"lodash";import{FieldNamingStyle}from"../smart-db-interfaces";export class AbstractModel{static getTableName(){return"overload this in child class"}static from(t){}assign(t,e){if("object"==typeof t){const i=this.getAttributeMap();let s=!e||!!e.skipUndefined;Object.keys(i).forEach(i=>{let a=!0;if(e&&(e.only&&!_.includes(e.only,i)&&(a=!1),e.exclude&&_.includes(e.exclude,i)&&(a=!1)),a)if(t instanceof AbstractModel&&t.hasAttribute(i)){const e=t.getValue(i);s&&void 0===e||this.setValue(i,e)}else if(t.hasOwnProperty(i)){const e=t[i];s&&void 0===e||this.setValue(i,e)}})}}setValue(t,e){const i=this.getAttributeMap()[t];if(!i)throw`unknown attribute ${t} for ${this.getClassName()}`;if(null===e)this[i.attribute]=null;else if(void 0===e)delete this[i.attribute];else{switch(i.type){case"SqlValueType":break;case"string":_.isNumber(e)?e=e.toString():_.isBoolean(e)?e=e?"true":"false":_.isDate(e)&&(e=this.toDbTimestamp(e));break;case"number":_.isString(e)?e=parseFloat(e):_.isBoolean(e)?e=e?1:0:_.isDate(e)&&(e=e.getTime());break;case"boolean":_.isString(e)?e=!e.match(/(F|N|false|no|0)/i):_.isNumber(e)?e=!!e:_.isDate(e)&&(e=!0);break;case"Date":_.isString(e)&&e.match(/^\d{4}-[01][0-9]-[0-3][0-9][ T][0-2][0-9]:[0-5][0-9]:[0-5][0-9]\s*$/)&&(e+=" GMT"),e=_.isNumber(e)||_.isString(e)||_.isDate(e)?new Date(e):new Date;break;default:throw`AbstractModel.setValue: unknown data type '${i.type}'`}this[i.attribute]=e}}getValue(t){return this[this.getAttributeMap()[t].attribute]}hasAttribute(t){return!!this.getAttributeMap()[t]}clear(t){_.isArray(t)||(t=[t]);const e=this.getAttributeMap();t.forEach(t=>{const i=e[t];i&&delete this[i.attribute]})}getPlainObject(t,e,i){let s,a=FieldNamingStyle.TypeScript,r=!1;void 0!==t&&("boolean"==typeof t?(r=t,s=e):(a=t,r=e,s=i));const l=this.getAttributeMap(),n=[];void 0===r&&(r=!0),_.forOwn(l,(t,e)=>{let i=a==FieldNamingStyle.All||r&&t.virtual;if(!i)if(a==FieldNamingStyle.Database)i=t.physical;else{if(a!=FieldNamingStyle.TypeScript)throw"unknown style "+a;i=t.typeScriptStyle}i&&(s&&!_.includes(s,e)||n.push(e))});const o={};return n.forEach(t=>{const e=l[t];if(e){const i=this[e.attribute];void 0!==i&&(o[t]=i)}}),o}toDbTimestamp(t){let e;return t&&(_.isNumber(t)&&(t=new Date(t)),e=t.toISOString().substr(0,23).replace("T"," ")),e}}AbstractModel.attributeMap={};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@egi/smart-db",
3
- "version": "2.4.4",
3
+ "version": "2.4.7",
4
4
  "description": "Unified Smart DB Access",
5
5
  "author": "Marcel Egloff",
6
6
  "type": "module",
@@ -59,21 +59,21 @@
59
59
  },
60
60
  "dependencies": {
61
61
  "lodash": "^4.17.21",
62
- "sqlite3": "^5.0.2"
62
+ "sqlite3": "^5.1.4"
63
63
  },
64
64
  "devDependencies": {
65
- "@types/better-sqlite3": "^5.4.2",
66
- "@types/glob": "^7.1.3",
67
- "@types/lodash": "^4.14.170",
65
+ "@types/better-sqlite3": "^7.6.3",
66
+ "@types/glob": "^8.0.1",
67
+ "@types/lodash": "^4.14.191",
68
68
  "@types/mysql": "^2.15.18",
69
- "@types/node": "^16.11.19",
69
+ "@types/node": "^18.11.18",
70
70
  "@types/sqlite3": "^3.1.7",
71
- "@types/uglify-js": "^3.13.0",
72
- "glob": "^7.1.7",
73
- "mocha": "^8.4.0",
71
+ "@types/uglify-js": "^3.17.1",
72
+ "glob": "^8.1.0",
73
+ "mocha": "^10.2.0",
74
74
  "npm-run-all": "^4.1.5",
75
- "terser": "^4.8.0",
76
- "uglify-js": "^3.13.10"
75
+ "terser": "^5.16.1",
76
+ "uglify-js": "^3.17.4"
77
77
  },
78
78
  "optionalDependencies": {
79
79
  "better-sqlite3": "^7.1.0",
@@ -37,7 +37,9 @@ export declare enum FieldNamingStyle {
37
37
  TypeScript = 1,
38
38
  All = 2
39
39
  }
40
- export declare type GenericModelData = Record<string, SqlValueType>;
40
+ export interface GenericModelData {
41
+ [key: string]: any;
42
+ }
41
43
  export interface AttributeInfo {
42
44
  attribute: string;
43
45
  type: string;
@@ -61,7 +63,7 @@ export interface SqlWhere {
61
63
  expression?: SmartDbSqlComparison[];
62
64
  [key: string]: SqlValueType | SqlValueType[] | SqlOperation | SqlWhere | SqlWhere[] | SmartDbSqlComparison[];
63
65
  }
64
- export declare type SqlUpdateValues = Record<string, SqlValueType>;
66
+ export declare type SqlUpdateValues = GenericModelData;
65
67
  export declare type SqlOrderBy = string | string[];
66
68
  declare type SqlGroupBy = string | string[];
67
69
  export interface SqlLimit {
@@ -140,9 +142,9 @@ export interface SmartDbApi {
140
142
  existsSync<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), type?: "view" | "table" | "index", indexTableName?: string): boolean;
141
143
  get<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), options: SmartDbSqlOptions<T, D>): Promise<(T | D)[] | T | D | SqlValueType | IndexedGenericModelData<T, D> | string | string[]>;
142
144
  getSync<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), options: SmartDbSqlOptions<T, D>): (T | D)[] | T | D | IndexedGenericModelData<T, D> | SqlValueType | string[] | false;
143
- getFirst<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy): Promise<T>;
144
- getFirstSync<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy): T | false;
145
- getAll<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy, limit?: SqlLimit): Promise<T[]>;
145
+ getFirst<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy): Promise<T | D | false>;
146
+ getFirstSync<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy): T | D | false;
147
+ getAll<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy, limit?: SqlLimit): Promise<T[] | false>;
146
148
  getAllSync<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy, limit?: SqlLimit): T[] | false;
147
149
  delete<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere): Promise<number>;
148
150
  deleteSync<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere): number | false;
package/smart-db-log.js CHANGED
@@ -1 +1 @@
1
- import _ from"lodash";import{SmartDbLogModel}from"./models/smart-db-log-model";import{SmartDbDateRegexp,SmartDbTimestampRegexp,toSmartDbTimestamp}from"./smart-db-globals";export const SmartDbLogLocation={Frontend:"frontend",Backend:"backend",Database:"database",UpgradeManager:"upgrade-manager",Other:"other"};export const SeverityCode={Fatal:"F",Error:"E",Warning:"W",Info:"I",Debug:"D",Local:"L"};export const SeverityLevel={None:0,Fatal:1,Error:2,Warning:3,Info:4,Debug:5,All:9};export class SmartDbLog{constructor(e){this.userId=null,this.dbLogging=!0,this.isLogging=!1,this.db=e,this.dbLogLevel=SeverityLevel.Info,this.consoleLogLevel=SeverityLevel.Info}getConsoleLogLevel(){return this.consoleLogLevel}setConsoleLogLevel(e){this.consoleLogLevel=e}getDbLogLevel(){return this.dbLogLevel}setDbLogLevel(e){this.dbLogLevel=e}setDb(e){this.db=e,this.db?this.db.exists(SmartDbLogModel).then(e=>{this.dbLogging=e}).catch(e=>{throw e}):this.dbLogging=!1}setUserId(e){this.userId=e}setDbLogging(e){this.dbLogging=e}getDbLogging(){return this.dbLogging}logFatal(e,t,o,r){this.writeLog(e,t,SeverityCode.Fatal,o,r)}logError(e,t,o,r){this.writeLog(e,t,SeverityCode.Error,o,r)}logWarning(e,t,o,r){this.writeLog(e,t,SeverityCode.Warning,o,r)}logInfo(e,t,o,r){this.writeLog(e,t,SeverityCode.Info,o,r)}logDebug(e,t,o,r){this.writeLog(e,t,SeverityCode.Debug,o,r)}writeLog(e,t,o,r,i,s){try{if(this.isLogging)console.error("recursive logging error:",e,t,o,r,i);else{this.isLogging=!0;let a,g,n=SeverityLevel.None;switch(o){case SeverityCode.Fatal:a=console.error,n=SeverityLevel.Fatal;break;case SeverityCode.Error:a=console.error,n=SeverityLevel.Error;break;case SeverityCode.Warning:a=console.warn,n=SeverityLevel.Warning;break;case SeverityCode.Info:a=console.info,n=SeverityLevel.Info;break;case SeverityCode.Debug:a=console.debug,n=SeverityLevel.Debug}if(_.isString(s)){const e=s.match(SmartDbTimestampRegexp),t=e&&s.match(SmartDbDateRegexp);g=e?e[1]:t?t[1]+".000":toSmartDbTimestamp(new Date)}else g=_.isDate(s)?toSmartDbTimestamp(s):_.isNumber(s)?toSmartDbTimestamp(new Date(s)):toSmartDbTimestamp(new Date);if(_.isObjectLike(r))if(r instanceof Error)i||(i=r),r=r.message;else try{r=JSON.stringify(r)}catch(e){r=r.toString()}else"boolean"==typeof r&&(r=r?"<true>":"<false>");if(i){if(i instanceof Error)i=i.stack;else if(_.isObject(i))try{i=JSON.stringify(i)}catch(e){i=i.toString(),this.db&&this.dbLogLevel>=n&&console.error("unable to stringify log data",i)}else i.toString?i=i.toString():(i=null,this.db&&this.dbLogLevel>=n&&console.error("unable to store log data",i));i&&(r+=` (${i})`)}if(this.consoleLogLevel>=n){const s=e.substr(0,1).toUpperCase();if(e==SmartDbLogLocation.Database&&this.db&&a(`${o}-${s}-${g}: last statement:`,this.db.getLastBuildData()),a(`${o}-${s}-${g}: ${r}`),this.dbLogging)try{e==SmartDbLogLocation.Database&&(i||(i=JSON.stringify(this.db.getLastBuildData()))),this.db.insertSync(SmartDbLogModel,{severity:o,type:e,location:t,info:r||"<empty>",data:i,user:this.userId,timestamp:new Date(g)})}catch(e){console.error(`F-B-${g}: unable to write the log statement below to database`,e,e.code,e.name,e.message);try{a(`F-B-${g}: last statement:`,this.db.getLastBuildData())}catch{a(`F-B-${g}: last statement not available`)}}}}this.isLogging=!1}catch(e){this.isLogging=!1,console.error("fatal logging error",e)}}}export const smartDbLog=new SmartDbLog;
1
+ import _ from"lodash";import{SmartDbLogModel}from"./models/smart-db-log-model";import{SmartDbDateRegexp,SmartDbTimestampRegexp,toSmartDbTimestamp}from"./smart-db-globals";export const SmartDbLogLocation={Frontend:"frontend",Backend:"backend",Database:"database",UpgradeManager:"upgrade-manager",Other:"other"};export const SeverityCode={Fatal:"F",Error:"E",Warning:"W",Info:"I",Debug:"D",Local:"L"};export const SeverityLevel={None:0,Fatal:1,Error:2,Warning:3,Info:4,Debug:5,All:9};export class SmartDbLog{constructor(e){this.userId=null,this.dbLogging=!0,this.isLogging=!1,this.db=e,this.dbLogLevel=SeverityLevel.Info,this.consoleLogLevel=SeverityLevel.Info}getConsoleLogLevel(){return this.consoleLogLevel}setConsoleLogLevel(e){this.consoleLogLevel=e}getDbLogLevel(){return this.dbLogLevel}setDbLogLevel(e){this.dbLogLevel=e}setDb(e){this.db=e,this.db?this.db.exists(SmartDbLogModel).then(e=>{this.dbLogging=e}).catch(e=>{throw e}):this.dbLogging=!1}setUserId(e){this.userId=e}setDbLogging(e){this.dbLogging=e}getDbLogging(){return this.dbLogging}logFatal(e,t,o,r){this.writeLog(e,t,SeverityCode.Fatal,o,r)}logError(e,t,o,r){this.writeLog(e,t,SeverityCode.Error,o,r)}logWarning(e,t,o,r){this.writeLog(e,t,SeverityCode.Warning,o,r)}logInfo(e,t,o,r){this.writeLog(e,t,SeverityCode.Info,o,r)}logDebug(e,t,o,r){this.writeLog(e,t,SeverityCode.Debug,o,r)}writeLog(e,t,o,r,i,s){try{if(this.isLogging)console.error("recursive logging error:",e,t,o,r,i);else{this.isLogging=!0;let a,g,n=SeverityLevel.None;switch(o){case SeverityCode.Fatal:a=console.error,n=SeverityLevel.Fatal;break;case SeverityCode.Error:a=console.error,n=SeverityLevel.Error;break;case SeverityCode.Warning:a=console.warn,n=SeverityLevel.Warning;break;case SeverityCode.Info:a=console.info,n=SeverityLevel.Info;break;case SeverityCode.Debug:a=console.debug,n=SeverityLevel.Debug}if(_.isString(s)){const e=s.match(SmartDbTimestampRegexp),t=e&&s.match(SmartDbDateRegexp);g=e?e[1]:t?t[1]+".000":toSmartDbTimestamp(new Date)}else g=_.isDate(s)?toSmartDbTimestamp(s):_.isNumber(s)?toSmartDbTimestamp(new Date(s)):toSmartDbTimestamp(new Date);if(_.isObjectLike(r))if(r instanceof Error)i||(i=r),r=r.message;else try{r=JSON.stringify(r)}catch(e){r=r.toString()}else"boolean"==typeof r&&(r=r?"<true>":"<false>");if(i){if(i instanceof Error)i=i.stack;else if(_.isObject(i))try{i=JSON.stringify(i)}catch(e){i=i.toString(),this.db&&this.dbLogLevel>=n&&console.error("unable to stringify log data",i)}else i.toString?i=i.toString():(i=null,this.db&&this.dbLogLevel>=n&&console.error("unable to store log data",i));i&&(r+=` (${i})`)}if(this.consoleLogLevel>=n){const s=e.substring(0,1).toUpperCase();if(e==SmartDbLogLocation.Database&&this.db&&a(`${o}-${s}-${g}: last statement:`,this.db.getLastBuildData()),a(`${o}-${s}-${g}: ${r}`),this.dbLogging)try{e==SmartDbLogLocation.Database&&(i||(i=JSON.stringify(this.db.getLastBuildData()))),this.db.insertSync(SmartDbLogModel,{severity:o,type:e,location:t,info:r||"<empty>",data:i,user:this.userId,timestamp:new Date(g)})}catch(e){console.error(`F-B-${g}: unable to write the log statement below to database`,e,e.code,e.name,e.message);try{a(`F-B-${g}: last statement:`,this.db.getLastBuildData())}catch{a(`F-B-${g}: last statement not available`)}}}}this.isLogging=!1}catch(e){this.isLogging=!1,console.error("fatal logging error",e)}}}export const smartDbLog=new SmartDbLog;
package/smart-db.d.ts CHANGED
@@ -32,11 +32,11 @@ export declare abstract class SmartDb implements SmartDbApi {
32
32
  getLogger(): SmartDbLog;
33
33
  getDb(): SmartDbDatabase;
34
34
  getLastBuildData(): SmartDbSqlBuildData;
35
- get<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), options: SmartDbSqlOptions<T, D>): Promise<(T | D)[] | T | D | SqlValueType | IndexedGenericModelData<T, D> | string | string[]>;
35
+ get<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), options: SmartDbSqlOptions<T, D>): Promise<(T | D)[] | T | D | SqlValueType | IndexedGenericModelData<T, D> | string | string[] | false>;
36
36
  getSync<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), options: SmartDbSqlOptions<T, D>): (T | D)[] | T | D | SqlValueType | IndexedGenericModelData<T, D> | string | string[] | false;
37
- getFirst<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy): Promise<T>;
38
- getFirstSync<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy): T | false;
39
- getAll<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy, limit?: SqlLimit): Promise<T[]>;
37
+ getFirst<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy): Promise<T | D | false>;
38
+ getFirstSync<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy): T | D | false;
39
+ getAll<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy, limit?: SqlLimit): Promise<T[] | false>;
40
40
  getAllSync<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy, limit?: SqlLimit): T[] | false;
41
41
  delete<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere): Promise<number>;
42
42
  deleteSync<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere): number | false;
@@ -51,7 +51,7 @@ export declare abstract class SmartDb implements SmartDbApi {
51
51
  toDbDate(d: Date | number): string;
52
52
  protected buildWhere<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where: SqlWhere, op?: string): SmartDbSqlBuildData;
53
53
  protected buildDeleteStatement<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere): SmartDbSqlBuildData;
54
- protected buildUpdateStatement<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), values: SqlUpdateValues | T, where?: SqlWhere): SmartDbSqlBuildData;
54
+ protected buildUpdateStatement<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), values: D | T, where?: SqlWhere): SmartDbSqlBuildData;
55
55
  protected buildInsertStatement<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), values: SqlUpdateValues | T): SmartDbSqlBuildData;
56
56
  protected prepareFieldValue<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), fieldOperation: SqlFieldDescriptor): string;
57
57
  protected prepareField<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), field: SqlValueType | SqlFieldDescriptor, values?: SqlValueType[]): string;
package/smart-db.js CHANGED
@@ -1 +1 @@
1
- import _ from"lodash";import{AbstractModel}from"./models/abstract-model";import{SmartDbDictionary}from"./models/smart-db-dictionary";import{SmartDbLogModel}from"./models/smart-db-log-model";import{IN,smartDbToDate,toSmartDbDate,toSmartDbTimestamp}from"./smart-db-globals";import{FieldNamingStyle,SqlFieldOperationType,SqlOperationType}from"./smart-db-interfaces";import{SmartDbLog,SmartDbLogLocation}from"./smart-db-log";import{SmartDbSqlBuildData}from"./smart-db-sql-build-data";import{SmartDbUpgradeManager}from"./smart-db-upgrade-manager";export class SmartDb{constructor(e){this.dictionaries=[],this.dbConnector=e,this.smartDbLog=new SmartDbLog(this)}initDb(e){return new Promise((t,a)=>{this.dictionaries.push(SmartDbDictionary);const r=new SmartDbUpgradeManager(this);let i;i=import.meta&&import.meta.url?import.meta.url.replace(/file:\/\//,"").replace(/\/[^/]*$/,""):__dirname;const s={module:"smart-db-core",sqlFilesDirectory:i+"/assets/"+this.getDatabaseType()};r.prepareDatabase(s).then(i=>{this.exists(SmartDbLogModel).then(s=>{this.smartDbLog.setDbLogging(s),r.prepareDatabase(e).then(e=>{t([i,e])},e=>{a(e)})})}).catch(e=>{a(e)})})}getLogger(){return this.smartDbLog}getDb(){return this.db}getLastBuildData(){return this.lastBuildData}get(e,t){return new Promise((a,r)=>{t||(t={});const i=this.buildSelectStatement(e,t);t.firstOnly||t.count?this.statementGet(i).then(r=>{a(this.prepareResultRow(e,r,t))}).catch(e=>{r(e)}):this.statementGetAll(i).then(r=>{a(this.prepareResultRows(e,r,t))}).catch(e=>{r(e)})})}getSync(e,t){return this.saveExecute(()=>{t||(t={});const a=this.buildSelectStatement(e,t);let r;if(t.firstOnly||t.count){const i=this.statementGetSync(a);r=this.prepareResultRow(e,i,t)}else{const i=this.statementGetAllSync(a);r=this.prepareResultRows(e,i,t)}return r})}getFirst(e,t,a,r){return this.get(e,{firstOnly:!0,where:t,fields:a,orderBy:r})}getFirstSync(e,t,a,r){return this.getSync(e,{firstOnly:!0,where:t,fields:a,orderBy:r})}getAll(e,t,a,r,i){return this.get(e,{where:t,fields:a,orderBy:r,limit:i})}getAllSync(e,t,a,r,i){return this.getSync(e,{where:t,fields:a,orderBy:r,limit:i})}delete(e,t){return new Promise((a,r)=>{const i=this.buildDeleteStatement(e,t);this.statementRun(i).then(e=>{e?a(e.changes):r(this.getLastError())}).catch(e=>{r(e)})})}deleteSync(e,t){return this.saveExecute(()=>{const a=this.buildDeleteStatement(e,t);return this.statementRunSync(a).changes})}update(e,t,a){return new Promise((r,i)=>{const s=this.buildUpdateStatement(e,t,a);this.statementRun(s).then(e=>{e?r(e.changes):i(this.getLastError())}).catch(e=>{i(e)})})}updateSync(e,t,a){return this.saveExecute(()=>{const r=this.buildUpdateStatement(e,t,a);return this.statementRunSync(r).changes})}insert(e,t){return new Promise((a,r)=>{const i=this.buildInsertStatement(e,t);this.statementRun(i).then(e=>{e?a(e.lastId):r(this.getLastError())}).catch(e=>{r(e)})})}insertSync(e,t){return this.saveExecute(()=>{const a=this.buildInsertStatement(e,t);return this.statementRunSync(a).lastId})}getLastError(){return this.lastError}buildSelectStatement(e,t){t||(t={});const a=this.buildSelectSectionStatement(e,t);if(_.forEach(["union","minus","intersect"],e=>{let r=_.get(t,e);r&&(_.isArray(r)||(r=[r]),_.forEach(r,t=>{const r=this.buildSelectSectionStatement(t.model,t);a.sql+=" "+e.toUpperCase()+" ",a.append(r)}))}),t.orderBy){a.sql+=" ORDER BY ";const r=_.isString(t.orderBy)?t.orderBy.split(/ *, */):t.orderBy;a.sql+=r.map(t=>{let a="";const r=t.match(/^(\w*) (asc|desc)$/i);return r&&(t=r[1],a=r[2].toUpperCase()),t=this.translateFieldName(e,t),a&&(t+=" "+a),t}).join(", ")}return t.limit&&(t.limit.limit&&(a.sql+=" LIMIT "+t.limit.limit.toString()),t.limit.offset&&(a.sql+=" OFFSET "+t.limit.offset.toString())),this.lastBuildData=a,a}toDate(e){return smartDbToDate(e)}toDbTimestamp(e){return toSmartDbTimestamp(e)}toDbDate(e){return toSmartDbDate(e)}buildWhere(e,t,a){const r=new SmartDbSqlBuildData;return t&&_.keys(t).length>0&&(a||(a="AND",r.sql+=" WHERE "),r.sql+=_.map(t,(t,i)=>{const s=i.toUpperCase();if("AND"==s||"OR"==s){let a="";return(_.isArray(t)?t:[t]).forEach((t,i)=>{const l=this.buildWhere(e,t,s);i>0&&(a+=" "+s+" "),a+=l.sql,r.values=_.concat(r.values,l.values)}),a="("+a+")",a}if("EXPRESSION"==s){let i=[];return _.forEach(t,t=>{const a=this.prepareField(e,t.compare,r.values),s=this.prepareField(e,t.with,r.values);let l;l=_.isString(t.operation)&&SqlOperationType[t.operation]?SqlOperationType[t.operation]:t.operation||SqlOperationType.EQ,i.push(`${a} ${l} ${s}`)}),i.join(" "+a+" ")}{let a,s,l=!0;if(_.isArray(t)&&(t=IN(t)),_.isObject(t)){const e=t;switch(_.isString(e.operation)&&SqlOperationType[e.operation]&&(e.operation=SqlOperationType[e.operation]),e.operation){case SqlOperationType.IN:const t=new Array(e.value.length);t.fill("?"),a=SqlOperationType.IN+" ("+t.join(", ")+")",r.values=_.concat(r.values,e.value);break;case SqlOperationType.IS_NULL:case SqlOperationType.IS_NOT_NULL:a=e.operation;break;case SqlOperationType.LITERAL:i=e.key;const s=e.literalOperation||SqlOperationType.EQ;if(s==SqlOperationType.IN){const t=new Array(e.value.length);t.fill("?"),a=SqlOperationType.IN+" ("+t.join(", ")+")",r.values=_.concat(r.values,e.value)}else _.isUndefined(e.value)?a=s:(a=s+" ?",r.values.push(this.makeDbValue(e.value)));l=!1;break;default:a=e.operation+" ?",r.values.push(this.makeDbValue(e.value))}}else null===t?a=SqlOperationType.IS_NULL:void 0===t?(i="1",a="= 1",l=!1):(a=_.isString(t)&&t.match(/[%_]/)?SqlOperationType.LIKE+" ?":SqlOperationType.EQ+" ?",r.values.push(this.makeDbValue(t)));return s=l?this.translateFieldName(e,i)+" "+a:i+" "+a,s}}).join(" "+a+" ")),r}buildDeleteStatement(e,t){const a=this.getTableName(e),r=new SmartDbSqlBuildData("DELETE FROM");return r.sql+=" "+a,t&&r.append(this.buildWhere(e,t)),this.lastBuildData=r,r}buildUpdateStatement(e,t,a){const r=this.getTableName(e),i=new SmartDbSqlBuildData("UPDATE");i.sql+=" "+r+" SET ";const s=[];return t instanceof AbstractModel&&(t=t.getPlainObject(FieldNamingStyle.Database)),_.forOwn(t,(t,a)=>{s.push(this.translateFieldName(e,a)+" = ?"),i.values.push(this.makeDbValue(t))}),i.sql+=s.join(", "),a&&i.append(this.buildWhere(e,a)),this.lastBuildData=i,i}buildInsertStatement(e,t){const a=this.getTableName(e),r=new SmartDbSqlBuildData("INSERT");r.sql+=" INTO "+a;const i=[];t instanceof AbstractModel&&(t=t.getPlainObject(FieldNamingStyle.Database)),_.forOwn(t,(t,a)=>{a=this.translateFieldName(e,a),i.push(a),r.values.push(this.makeDbValue(t))});const s=new Array(i.length);return s.fill("?"),r.sql+=" ("+i.join(", ")+") VALUES ("+s.join(", ")+")",this.lastBuildData=r,r}prepareFieldValue(e,t){let a="<undefined>";switch(t.operation){case SqlFieldOperationType.FIELD:a=this.translateFieldName(e,t.value);break;case SqlFieldOperationType.VALUE:null===t.value?a="NULL":t.literal?a=t.value:_.isString(t.value)?!isNaN(parseFloat(t.value))&&isFinite(t.value)||(a="'"+t.value+"'"):_.isNumber(t.value)?a=t.value.toString():_.isBoolean(t.value)?a=t.value?"1":"0":_.isDate(t.value)?a="'"+t.value.toISOString().substr(0,23).replace("T"," ")+"'":console.error("unhandled field data type",typeof t.value,t.value);break;case SqlFieldOperationType.COUNT:a=_.isArray(t.value)?"COUNT("+t.value.join(",")+")":"COUNT("+(t.value||"")+")";break;case SqlFieldOperationType.COALESCE:const r=_.isArray(t.value)?t.value:[t.value];a="COALESCE("+this.buildFieldList(e,r).join(",")+")"}if(t.alias){const e=this.getDbQuote();a+=` as ${e}${t.alias}${e}`}return a}prepareField(e,t,a){let r;if(null===t)r="NULL";else if(_.isString(t)){const i=t.match(/^'(.*)'$/);i?a?(r="?",a.push(i[1])):r=t:r=this.translateFieldName(e,t)}else t.operation?r=this.prepareFieldValue(e,t):a?(r="?",a.push(t)):r=this.makeArgumentDbValue(t).toString();return r}buildFieldList(e,t){const a=[];return _.forEach(t,t=>{a.push(this.prepareField(e,t))}),a}buildSelectSectionStatement(e,t){const a=this.getTableName(e);let r,i;if(_.isArray(t.fields))r=t.fields;else if(_.isString(t.fields)){const e=t.fields.trim();r=""===e||"*"==e?[]:e.split(/,/)}else r=t.fields&&t.fields.operation?[t.fields]:[];if(r.length>0){i=this.buildFieldList(e,r).join(", ")}else i="*";t.distinct&&(i="DISTINCT "+i),t.count&&(i=`COUNT(${i})`);const s=new SmartDbSqlBuildData(`SELECT ${i} FROM ${a}`);if(t.where&&s.append(this.buildWhere(e,t.where)),t.groupBy){s.sql+=" GROUP BY ";const a=_.isArray(t.groupBy)?t.groupBy:[t.groupBy];s.sql+=a.map(t=>this.translateFieldName(e,t)).join(", ")}return s}translateFieldName(e,t){if(_.isString(e)){const t=e;let a=!1;_.forEach(this.dictionaries,r=>(r.models&&r.models[t]&&(e=r.models[t].cls,a=!0),!a))}if(!_.isString(e)){const a=e.attributeMap[t];if(a)a.alias&&(t=a.alias);else{const a=e.getTableName();this.lastError=new Error(`unknown field '${t}' in table '${a}'`),this.smartDbLog.logError(SmartDbLogLocation.Database,"translateFieldName",this.lastError)}}return t}makeDbValue(e){return _.isBoolean(e)?e=e?1:0:_.isDate(e)&&(e=toSmartDbDate(e)),e}makeArgumentDbValue(e){return _.isBoolean(e)?e=e?1:0:_.isDate(e)?e=`'${toSmartDbDate(e)}'`:_.isString(e)&&(e=`'${e.replace(/'/,"''").replace(/\\/,"\\\\")}'`),e}saveExecute(e){let t;try{t=e()}catch(e){this.lastError=e instanceof Error?e:new Error(e||"Unknown error"),this.smartDbLog.logFatal(SmartDbLogLocation.Database,"saveExecute-catch",this.lastError),t=!1}return t}prepareResultRow(e,t,a){let r;if(a.indexedBy&&this.smartDbLog.logWarning(SmartDbLogLocation.Database,"AbstractModel.get","option 'indexedBy' not supported without 'all'"),t)if(a.count)r=parseInt(_.values(t)[0],10);else if(a.collapseRow)r=_.values(t).join(",");else{r=e.from(t),a.style==FieldNamingStyle.TypeScript&&(r=r.getPlainObject(FieldNamingStyle.TypeScript))}return r}prepareResultRows(e,t,a){let r;if(a.indexedBy||a.collapseRow||!_.isString(e)){const i=e;r=a.indexedBy?{}:new Array(t.length),_.forEach(t,(e,t)=>{let s=i.from?i.from(e):null,l=null;if(a.indexedBy&&(l=s?s.getValue(a.indexedBy):e[a.indexedBy]),a.collapseRow){const a=_.values(e).join(",");l?r[l]=a:r[t]=a}else s&&a.style==FieldNamingStyle.TypeScript&&(s=s.getPlainObject(FieldNamingStyle.TypeScript)),l?r[l]=s||e:r[t]=s||e})}else r=t;return r}getTableName(e){let t;if(_.isString(e)){let a=e;_.forEach(this.dictionaries,e=>(e.models&&e.models[a]&&(t=e.models[a].cls.getTableName()),!t)),t||(t=a)}else{if(!e||!e.getTableName)throw new Error("unknown model: "+e);t=e.getTableName()}return t}}
1
+ import _ from"lodash";import{AbstractModel}from"./models/abstract-model";import{SmartDbDictionary}from"./models/smart-db-dictionary";import{SmartDbLogModel}from"./models/smart-db-log-model";import{IN,smartDbToDate,toSmartDbDate,toSmartDbTimestamp}from"./smart-db-globals";import{FieldNamingStyle,SqlFieldOperationType,SqlOperationType}from"./smart-db-interfaces";import{SmartDbLog,SmartDbLogLocation}from"./smart-db-log";import{SmartDbSqlBuildData}from"./smart-db-sql-build-data";import{SmartDbUpgradeManager}from"./smart-db-upgrade-manager";export class SmartDb{constructor(e){this.dictionaries=[],this.dbConnector=e,this.smartDbLog=new SmartDbLog(this)}initDb(e){return new Promise((t,a)=>{this.dictionaries.push(SmartDbDictionary);const r=new SmartDbUpgradeManager(this);let i;i=import.meta&&import.meta.url?import.meta.url.replace(/file:\/\//,"").replace(/\/[^/]*$/,""):__dirname;const s={module:"smart-db-core",sqlFilesDirectory:i+"/assets/"+this.getDatabaseType()};r.prepareDatabase(s).then(i=>{this.exists(SmartDbLogModel).then(s=>{this.smartDbLog.setDbLogging(s),r.prepareDatabase(e).then(e=>{t([i,e])},e=>{a(e)})})}).catch(e=>{a(e)})})}getLogger(){return this.smartDbLog}getDb(){return this.db}getLastBuildData(){return this.lastBuildData}get(e,t){return new Promise((a,r)=>{t||(t={});const i=this.buildSelectStatement(e,t);t.firstOnly||t.count?this.statementGet(i).then(r=>{a(this.prepareResultRow(e,r,t))}).catch(e=>{r(e)}):this.statementGetAll(i).then(r=>{a(this.prepareResultRows(e,r,t))}).catch(e=>{r(e)})})}getSync(e,t){return this.saveExecute(()=>{t||(t={});const a=this.buildSelectStatement(e,t);let r;if(t.firstOnly||t.count){const i=this.statementGetSync(a);r=this.prepareResultRow(e,i,t)}else{const i=this.statementGetAllSync(a);r=this.prepareResultRows(e,i,t)}return r})}getFirst(e,t,a,r){return this.get(e,{firstOnly:!0,where:t,fields:a,orderBy:r})}getFirstSync(e,t,a,r){return this.getSync(e,{firstOnly:!0,where:t,fields:a,orderBy:r})}getAll(e,t,a,r,i){return this.get(e,{where:t,fields:a,orderBy:r,limit:i})}getAllSync(e,t,a,r,i){return this.getSync(e,{where:t,fields:a,orderBy:r,limit:i})}delete(e,t){return new Promise((a,r)=>{const i=this.buildDeleteStatement(e,t);this.statementRun(i).then(e=>{e?a(e.changes):r(this.getLastError())}).catch(e=>{r(e)})})}deleteSync(e,t){return this.saveExecute(()=>{const a=this.buildDeleteStatement(e,t);return this.statementRunSync(a).changes})}update(e,t,a){return new Promise((r,i)=>{const s=this.buildUpdateStatement(e,t,a);this.statementRun(s).then(e=>{e?r(e.changes):i(this.getLastError())}).catch(e=>{i(e)})})}updateSync(e,t,a){return this.saveExecute(()=>{const r=this.buildUpdateStatement(e,t,a);return this.statementRunSync(r).changes})}insert(e,t){return new Promise((a,r)=>{const i=this.buildInsertStatement(e,t);this.statementRun(i).then(e=>{e?a(e.lastId):r(this.getLastError())}).catch(e=>{r(e)})})}insertSync(e,t){return this.saveExecute(()=>{const a=this.buildInsertStatement(e,t);return this.statementRunSync(a).lastId})}getLastError(){return this.lastError}buildSelectStatement(e,t){t||(t={});const a=this.buildSelectSectionStatement(e,t);if(_.forEach(["union","minus","intersect"],e=>{let r=_.get(t,e);r&&(_.isArray(r)||(r=[r]),_.forEach(r,t=>{const r=this.buildSelectSectionStatement(t.model,t);a.sql+=" "+e.toUpperCase()+" ",a.append(r)}))}),t.orderBy){a.sql+=" ORDER BY ";const r=_.isString(t.orderBy)?t.orderBy.split(/ *, */):t.orderBy;a.sql+=r.map(t=>{let a="";const r=t.match(/^(\w*) (asc|desc)$/i);return r&&(t=r[1],a=r[2].toUpperCase()),t=this.translateFieldName(e,t),a&&(t+=" "+a),t}).join(", ")}return t.limit&&(t.limit.limit&&(a.sql+=" LIMIT "+t.limit.limit.toString()),t.limit.offset&&(a.sql+=" OFFSET "+t.limit.offset.toString())),this.lastBuildData=a,a}toDate(e){return smartDbToDate(e)}toDbTimestamp(e){return toSmartDbTimestamp(e)}toDbDate(e){return toSmartDbDate(e)}buildWhere(e,t,a){const r=new SmartDbSqlBuildData;return t&&_.keys(t).length>0&&(a||(a="AND",r.sql+=" WHERE "),r.sql+=_.map(t,(t,i)=>{const s=i.toUpperCase();if("AND"==s||"OR"==s){let a="";return(_.isArray(t)?t:[t]).forEach((t,i)=>{const l=this.buildWhere(e,t,s);i>0&&(a+=" "+s+" "),a+=l.sql,r.values=_.concat(r.values,l.values)}),a="("+a+")",a}if("EXPRESSION"==s){let i=[];return _.forEach(t,t=>{const a=this.prepareField(e,t.compare,r.values),s=this.prepareField(e,t.with,r.values);let l;l=_.isString(t.operation)&&SqlOperationType[t.operation]?SqlOperationType[t.operation]:t.operation||SqlOperationType.EQ,i.push(`${a} ${l} ${s}`)}),i.join(" "+a+" ")}{let a,s,l=!0;if(_.isArray(t)&&(t=IN(t)),_.isObject(t)){const e=t;switch(_.isString(e.operation)&&SqlOperationType[e.operation]&&(e.operation=SqlOperationType[e.operation]),e.operation){case SqlOperationType.IN:const t=new Array(e.value.length);t.fill("?"),a=SqlOperationType.IN+" ("+t.join(", ")+")",r.values=_.concat(r.values,e.value);break;case SqlOperationType.IS_NULL:case SqlOperationType.IS_NOT_NULL:a=e.operation;break;case SqlOperationType.LITERAL:i=e.key;const s=e.literalOperation||SqlOperationType.EQ;if(s==SqlOperationType.IN){const t=new Array(e.value.length);t.fill("?"),a=SqlOperationType.IN+" ("+t.join(", ")+")",r.values=_.concat(r.values,e.value)}else _.isUndefined(e.value)?a=s:(a=s+" ?",r.values.push(this.makeDbValue(e.value)));l=!1;break;default:a=e.operation+" ?",r.values.push(this.makeDbValue(e.value))}}else null===t?a=SqlOperationType.IS_NULL:void 0===t?(i="1",a="= 1",l=!1):(a=_.isString(t)&&t.match(/[%_]/)?SqlOperationType.LIKE+" ?":SqlOperationType.EQ+" ?",r.values.push(this.makeDbValue(t)));return s=l?this.translateFieldName(e,i)+" "+a:i+" "+a,s}}).join(" "+a+" ")),r}buildDeleteStatement(e,t){const a=this.getTableName(e),r=new SmartDbSqlBuildData("DELETE FROM");return r.sql+=" "+a,t&&r.append(this.buildWhere(e,t)),this.lastBuildData=r,r}buildUpdateStatement(e,t,a){const r=this.getTableName(e),i=new SmartDbSqlBuildData("UPDATE");i.sql+=" "+r+" SET ";const s=[],l=t instanceof AbstractModel?t.getPlainObject(FieldNamingStyle.Database):t;return _.forOwn(l,(t,a)=>{s.push(this.translateFieldName(e,a)+" = ?"),i.values.push(this.makeDbValue(t))}),i.sql+=s.join(", "),a&&i.append(this.buildWhere(e,a)),this.lastBuildData=i,i}buildInsertStatement(e,t){const a=this.getTableName(e),r=new SmartDbSqlBuildData("INSERT");r.sql+=" INTO "+a;const i=[];t instanceof AbstractModel&&(t=t.getPlainObject(FieldNamingStyle.Database)),_.forOwn(t,(t,a)=>{a=this.translateFieldName(e,a),i.push(a),r.values.push(this.makeDbValue(t))});const s=new Array(i.length);return s.fill("?"),r.sql+=" ("+i.join(", ")+") VALUES ("+s.join(", ")+")",this.lastBuildData=r,r}prepareFieldValue(e,t){let a="<undefined>";switch(t.operation){case SqlFieldOperationType.FIELD:a=this.translateFieldName(e,t.value);break;case SqlFieldOperationType.VALUE:null===t.value?a="NULL":t.literal?a=t.value:_.isString(t.value)?!isNaN(parseFloat(t.value))&&isFinite(t.value)||(a="'"+t.value+"'"):_.isNumber(t.value)?a=t.value.toString():_.isBoolean(t.value)?a=t.value?"1":"0":_.isDate(t.value)?a="'"+t.value.toISOString().substr(0,23).replace("T"," ")+"'":console.error("unhandled field data type",typeof t.value,t.value);break;case SqlFieldOperationType.COUNT:a=_.isArray(t.value)?"COUNT("+t.value.join(",")+")":"COUNT("+(t.value||"")+")";break;case SqlFieldOperationType.COALESCE:const r=_.isArray(t.value)?t.value:[t.value];a="COALESCE("+this.buildFieldList(e,r).join(",")+")"}if(t.alias){const e=this.getDbQuote();a+=` as ${e}${t.alias}${e}`}return a}prepareField(e,t,a){let r;if(null===t)r="NULL";else if(_.isString(t)){const i=t.match(/^'(.*)'$/);i?a?(r="?",a.push(i[1])):r=t:r=this.translateFieldName(e,t)}else t.operation?r=this.prepareFieldValue(e,t):a?(r="?",a.push(t)):r=this.makeArgumentDbValue(t).toString();return r}buildFieldList(e,t){const a=[];return _.forEach(t,t=>{a.push(this.prepareField(e,t))}),a}buildSelectSectionStatement(e,t){const a=this.getTableName(e);let r,i;if(_.isArray(t.fields))r=t.fields;else if(_.isString(t.fields)){const e=t.fields.trim();r=""===e||"*"==e?[]:e.split(/,/)}else r=t.fields&&t.fields.operation?[t.fields]:[];if(r.length>0){i=this.buildFieldList(e,r).join(", ")}else i="*";t.distinct&&(i="DISTINCT "+i),t.count&&(i=`COUNT(${i})`);const s=new SmartDbSqlBuildData(`SELECT ${i} FROM ${a}`);if(t.where&&s.append(this.buildWhere(e,t.where)),t.groupBy){s.sql+=" GROUP BY ";const a=_.isArray(t.groupBy)?t.groupBy:[t.groupBy];s.sql+=a.map(t=>this.translateFieldName(e,t)).join(", ")}return s}translateFieldName(e,t){if(_.isString(e)){const t=e;let a=!1;_.forEach(this.dictionaries,r=>(r.models&&r.models[t]&&(e=r.models[t].cls,a=!0),!a))}if(!_.isString(e)){const a=e.attributeMap[t];if(a)a.alias&&(t=a.alias);else{const a=e.getTableName();this.lastError=new Error(`unknown field '${t}' in table '${a}'`),this.smartDbLog.logError(SmartDbLogLocation.Database,"translateFieldName",this.lastError)}}return t}makeDbValue(e){return _.isBoolean(e)?e=e?1:0:_.isDate(e)&&(e=toSmartDbDate(e)),e}makeArgumentDbValue(e){return _.isBoolean(e)?e=e?1:0:_.isDate(e)?e=`'${toSmartDbDate(e)}'`:_.isString(e)&&(e=`'${e.replace(/'/,"''").replace(/\\/,"\\\\")}'`),e}saveExecute(e){let t;try{t=e()}catch(e){this.lastError=e instanceof Error?e:new Error(e||"Unknown error"),this.smartDbLog.logFatal(SmartDbLogLocation.Database,"saveExecute-catch",this.lastError),t=!1}return t}prepareResultRow(e,t,a){let r;if(a.indexedBy&&this.smartDbLog.logWarning(SmartDbLogLocation.Database,"AbstractModel.get","option 'indexedBy' not supported without 'all'"),t)if(a.count)r=parseInt(_.values(t)[0],10);else if(a.collapseRow)r=_.values(t).join(",");else{const i=e.from(t);r=a.style==FieldNamingStyle.TypeScript?i.getPlainObject():i}return r}prepareResultRows(e,t,a){let r;if(!t||!a.indexedBy&&!a.collapseRow&&_.isString(e))r=t;else{const i=e;r=a.indexedBy?{}:new Array(t.length),_.forEach(t,(e,t)=>{let s=i.from?i.from(e):null,l=null;if(a.indexedBy&&(l=s?s.getValue(a.indexedBy):e[a.indexedBy]),a.collapseRow){const a=_.values(e).join(",");l?r[l]=a:r[t]=a}else s&&a.style==FieldNamingStyle.TypeScript&&(s=s.getPlainObject()),l?r[l]=s||e:r[t]=s||e})}return r}getTableName(e){let t;if(_.isString(e)){let a=e;_.forEach(this.dictionaries,e=>(e.models&&e.models[a]&&(t=e.models[a].cls.getTableName()),!t)),t||(t=a)}else{if(!e||!e.getTableName)throw new Error("unknown model: "+e);t=e.getTableName()}return t}}