@egi/smart-db 2.4.6 → 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.
- package/models/abstract-model.d.ts +2 -1
- package/models/abstract-model.js +1 -1
- package/package.json +1 -1
- package/smart-db-interfaces.d.ts +7 -5
- package/smart-db.d.ts +5 -5
- package/smart-db.js +1 -1
|
@@ -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(
|
|
20
|
+
getPlainObject(includeVirtuals?: boolean, fields?: string[]): D;
|
|
21
|
+
getPlainObject(style?: FieldNamingStyle, includeVirtuals?: boolean, fields?: string[]): GenericModelData;
|
|
21
22
|
private toDbTimestamp;
|
|
22
23
|
}
|
package/models/abstract-model.js
CHANGED
|
@@ -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){
|
|
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
package/smart-db-interfaces.d.ts
CHANGED
|
@@ -37,7 +37,9 @@ export declare enum FieldNamingStyle {
|
|
|
37
37
|
TypeScript = 1,
|
|
38
38
|
All = 2
|
|
39
39
|
}
|
|
40
|
-
export
|
|
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 =
|
|
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.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:
|
|
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}}
|