@egi/smart-db 2.6.0 → 2.6.2
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/drivers/smart-db-better-sqlite3.d.ts +1 -1
- package/drivers/smart-db-better-sqlite3.js +1 -1
- package/drivers/smart-db-sqlite3.js +1 -1
- package/helpers/extract-db-api.js +1 -1
- package/package.json +1 -3
- package/smart-db-api.d.ts +1 -0
- package/smart-db-api.js +1 -1
- package/smart-db-log.d.ts +7 -27
- package/smart-db-log.js +1 -1
- package/smart-db-upgrade-manager.js +1 -1
- package/smart-db.d.ts +5 -2
- package/smart-db.js +1 -1
- package/smart-error.d.ts +41 -0
- package/smart-error.js +1 -0
|
@@ -9,7 +9,7 @@ export declare class SmartDbBetterSqlite3 extends SmartDb {
|
|
|
9
9
|
constructor(connectorOrDb: string | BetterSqlite3.Database, options?: BetterSqlite3.Options);
|
|
10
10
|
aggregate(name: string, options: BetterSqlite3.AggregateOptions): boolean;
|
|
11
11
|
backup(destinationFile: string, options?: BetterSqlite3.BackupOptions): Promise<BetterSqlite3.BackupMetadata>;
|
|
12
|
-
|
|
12
|
+
closeSync(): boolean;
|
|
13
13
|
commitSync(): void;
|
|
14
14
|
defaultSafeIntegers(toggleState?: boolean): boolean;
|
|
15
15
|
execSync(script: string): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import BetterSqlite3 from"better-sqlite3";import _ from"lodash";import{SqliteMasterModel}from"../models/sqlite-master-model";import{SmartDb}from"../smart-db";export class SmartDbBetterSqlite3 extends SmartDb{constructor(t,e){_.isString(t)?(super(t),this.db=new BetterSqlite3(t,e)):(super(null),this.db=t,this.db.inTransaction),this.isReady=!0}aggregate(t,e){return!!this.saveExecute((()=>this.db.aggregate(t,e)))}backup(t,e){return new Promise(((s,r)=>{const n=this.saveExecute((()=>this.db.backup(t,e)));0==n?r(this.getLastError()):s(n)}))}
|
|
1
|
+
import BetterSqlite3 from"better-sqlite3";import _ from"lodash";import{SqliteMasterModel}from"../models/sqlite-master-model";import{SmartDb}from"../smart-db";export class SmartDbBetterSqlite3 extends SmartDb{constructor(t,e){_.isString(t)?(super(t),this.db=new BetterSqlite3(t,e)):(super(null),this.db=t,this.db.inTransaction),this.isReady=!0}aggregate(t,e){return!!this.saveExecute((()=>this.db.aggregate(t,e)))}backup(t,e){return new Promise(((s,r)=>{const n=this.saveExecute((()=>this.db.backup(t,e)));0==n?r(this.getLastError()):s(n)}))}closeSync(){return this.smartDbLog.setDb(null),!!this.db.close()}commitSync(){this.db.inTransaction&&this.db.exec("commit")}defaultSafeIntegers(t){return!!this.saveExecute((()=>this.db.defaultSafeIntegers(t)))}execSync(t){return!!this.saveExecute((()=>this.db.exec(t)))}existsSync(t,e,s){let r=!1;const n=_.isString(t)?t:t.getTableName(),a=this.getFirstSync(SqliteMasterModel,{name:n,type:e,tblName:s});if(!1===a)throw this.getLastError();return r=!!a,r}func(t,e,s){return this.saveExecute((()=>{let r;return r=_.isFunction(e)?this.db.function(t,e):this.db.function(t,e,s),r}))}getDatabaseType(){return"sqlite3"}getTableInfo(t){return new Promise((e=>{const s=this.pragma(`table_info(${t})`);let r=[];s&&(r=s.map((t=>({cid:t.cid,name:t.name,type:t.type,notNull:0!==t.notnull,defaultValue:t.dflt_value,isPk:0!==t.pk}))),e({name:t,fields:r}))}))}hasTransaction(){return this.db.inTransaction}loadExtension(t){return!!this.saveExecute((()=>this.db.loadExtension(t)))}pragma(t,e){return this.saveExecute((()=>this.db.pragma(t,e)))}rollbackSync(){this.db.inTransaction&&this.db.exec("rollback")}transaction(t){return!!this.saveExecute((()=>this.db.transaction(t)))}statementRun(t,e=0){return new Promise(((s,r)=>{try{s(this.statementRunSync(t))}catch(n){"SQLITE_BUSY"==n.code&&e<10?setTimeout((()=>{this.statementRun(t,e+1).then((t=>{s(t)})).catch((t=>{r(t)}))}),100):(this.lastError=n,r(n))}}))}statementRunSync(t){const e=this.db.prepare(t.sql),s=e&&e.run(t.values);return s&&{changes:s.changes,affected:s.changes,lastId:s.lastInsertRowid}}statementGetSync(t){const e=this.db.prepare(t.sql);return e&&e.get(t.values)}statementGetAllSync(t){const e=this.db.prepare(t.sql);return e&&e.all(t.values)}get supportSyncCalls(){return!0}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import _ from"lodash";import Sqlite3 from"sqlite3";import{SqliteMasterModel}from"../models/sqlite-master-model";import{SmartDb}from"../smart-db";export class SmartDbSqlite3 extends SmartDb{constructor(t,r){_.isString(t)?(super(t),this.db=new Sqlite3.Database(t,r&&r.mode,r&&r.callback)):(super(null),this.db=t)}close(){return new Promise(((t,r)=>{try{this.smartDbLog.setDb(null),this.db.close((
|
|
1
|
+
import _ from"lodash";import Sqlite3 from"sqlite3";import{SqliteMasterModel}from"../models/sqlite-master-model";import{SmartDb}from"../smart-db";export class SmartDbSqlite3 extends SmartDb{constructor(t,r){_.isString(t)?(super(t),this.db=new Sqlite3.Database(t,r&&r.mode,r&&r.callback)):(super(null),this.db=t)}close(){return new Promise(((t,r)=>{try{this.smartDbLog.setDb(null),this.db.close((r=>{r?(this.lastError=r,t(!1)):t(!0)}))}catch(t){this.lastError=t,r(t)}}))}commit(){return this.exec("commit")}exec(t){return new Promise(((r,e)=>{try{this.db.exec(t,(t=>{t?(this.lastError=t,e(t)):r()}))}catch(t){this.lastError=t,e(t)}}))}exists(t,r,e){return new Promise(((s,a)=>{try{const i=_.isString(t)?t:t.getTableName();this.getFirst(SqliteMasterModel,{name:i,type:r,tblName:e}).then((t=>{s(!!t)})).catch((t=>{a(t)}))}catch(t){this.lastError=t,a(t)}}))}getDatabaseType(){return"sqlite3"}getTableInfo(t){throw new Error("Method not implemented (getTableInfo)")}rollback(){return this.exec("rollback")}statementRun(t){return new Promise(((r,e)=>{try{const s=this;this.db.run(t.sql,t.values,(function(t){t?(s.lastError=t,e(t)):r({changes:this.changes,affected:this.changes,lastId:this.lastID})}))}catch(t){this.lastError=t,e(t)}}))}statementGet(t){return new Promise(((r,e)=>{try{const s=this;this.db.prepare(t.sql,(function(a){a?e(a):this.get(t.values,(function(t,a){t?(s.lastError=t,e(t)):r(a)}))}))}catch(t){this.lastError=t,e(t)}}))}statementGetAll(t){return new Promise(((r,e)=>{try{const s=this;this.db.prepare(t.sql,(function(a){a?(s.lastError=a,e(a)):this.all(t.values,(function(t,a){t?(s.lastError=t,e(t)):r(a)}))}))}catch(t){this.lastError=t,e(t)}}))}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import fs from"fs";import _ from"lodash";import process from"process";import{SmartDbBetterSqlite3}from"../drivers/smart-db-better-sqlite3";import{SmartDbOracle}from"../drivers/smart-db-oracle";import{OracleCatModel}from"../models/oracle-cat-model";import{SmartDbCoreTableModel}from"../models/smart-db-core-table-model";import{SqliteMasterModel}from"../models/sqlite-master-model";import{IN,NE,NOT_LIKE}from"../smart-db-globals";function getType(e){let t;return t=e?e.match(/varchar/i)||e.match(/text/i)?"string":e.match(/integer\(1\)/i)?"boolean":e.match(/date/i)?"Date":e.match(/integer/i)||e.match(/number/i)?"number":e.match(/long/i)||e.match(/raw/i)?"any":"SqlValueType":"SqlValueType",t}function getRelations(e){return new Promise((async(t,r)=>{e instanceof SmartDbOracle?e.getAll(OracleCatModel,{type:IN(["TABLE","VIEW"]),name:NOT_LIKE("BIN$%")}).then((a=>{a?t(a.map((e=>e.name.toLowerCase()))):r(e.getLastError())})).catch((e=>{r(e)})):e instanceof SmartDbBetterSqlite3?e.getAll(SqliteMasterModel,{type:IN(["table","view"]),name:NE("sqlite_sequence")}).then((a=>{a?t(a.map((e=>e.name))):r(e.getLastError())})).catch((e=>{r(e)})):r("unimplemented database type")}))}async function extractDbApi(e){console.log(`extract interface from '${e.db.getDbConnector()}' to '${e.modelDirectory}'`);const t=["break","case","catch","class","const","continue","debugger","default","delete","do","else","enum","export","extends","false","finally","for","function","If","import","in","instanceOf","interface","new","null","return","super","switch","this","throw","true","try","typeOf","var","void","while","with"];fs.existsSync(e.modelDirectory)||fs.mkdirSync(e.modelDirectory,{recursive:!0}),getRelations(e.db).then((async r=>{let a=[];if((e.skipCoreTables||e.justCoreTables)&&await e.db.exists(SmartDbCoreTableModel)){const t=await e.db.getAll(SmartDbCoreTableModel);if(!1===t)throw e.db.getLastError();t.forEach((e=>{a.push(e.name)}))}const n=[];for(const s of r){let r=!0;if(e.justCoreTables?r=a.includes(s):e.skipCoreTables&&(r=!a.includes(s)),r){const r=s[0].toUpperCase()+_.camelCase(s.substring(1))+"Model",a=[];console.log("working on",s),await e.db.getTableInfo(s).then((o=>{const i=o.fields;let l=!1,c="",m="",p="",d="",b="";const u=s.toLowerCase().replace(/[^[a-z0-9]/g,"-")+"-model";if(n.push({className:r,fileName:u}),c+="/* eslint-disable @typescript-eslint/member-ordering */\n",c+="// noinspection JSUnusedGlobalSymbols\n",i){e.abstractModelModule==e.smartDbInterfaces?e.separateApi?(p+=`import {GenericModelData} from "${e.abstractModelModule}";\n`,b+=`import {AbstractModel, ModelAttributeMap} from "${e.abstractModelModule}";\n`,b+=`import {${r}Data} from "./${u}-api";\n`):b+=`import {AbstractModel, GenericModelData, ModelAttributeMap} from "${e.abstractModelModule}";\n`:e.separateApi?(p+=`import {GenericModelData} from "${e.smartDbInterfaces}";\n`,b+=`import {ModelAttributeMap} from "${e.smartDbInterfaces}";\n`,b+=`import {AbstractModel} from "${e.abstractModelModule}";\n`,b+=`import {${r}Data} from "./${u}-api";\n`):(b+=`import {GenericModelData, ModelAttributeMap} from "${e.smartDbInterfaces}";\n`,b+=`import {AbstractModel} from "${e.abstractModelModule}";\n`),m+=`export interface ${r}Data extends GenericModelData {\n`;let n,o="",f="",h=!1;const g=[];i.forEach((e=>{const t=e.name.match(/([a-z0-9]{1,4})_/i);e.isPk&&(o=e.name,t&&(f=t[1])),t?g.includes(t[1])||g.push(t[1]):h=!0})),f||h||1!=g.length||(f=g[0]),f&&(n=new RegExp(`^${f}_(.*)$`));const y={};i.forEach((t=>{const r=getType(t.type);let o;l||"SqlValueType"!=r||(p+=`import {SqlValueType} from "${e.smartDbInterfaces}";\n`,b+=`import {SqlValueType} from "${e.smartDbInterfaces}";\n`,l=!0);const i=n&&t.name.match(n);o=i?_.camelCase(i[1]):_.camelCase(t.name);let c=!0;if(o!=t.name&&(a.push({name:o,attribute:o,type:r,typeScriptStyle:c,alias:t.name}),c=!1),o!=t.name.toLowerCase()&&(a.push({name:t.name.toLowerCase(),attribute:o,type:r,physical:void 0!==t.cid&&t.name==t.name.toLowerCase(),typeScriptStyle:c}),c=!1),o!=t.name.toUpperCase()&&a.push({name:t.name.toUpperCase(),attribute:o,type:r,physical:void 0!==t.cid&&t.name==t.name.toUpperCase(),typeScriptStyle:c}),t.cid){const e=a.find((e=>e.physical&&e.name.toLowerCase()==t.name.toLowerCase()));e||a.push({name:t.name,attribute:o,type:r,physical:!0,typeScriptStyle:c})}y[o]=r,"user"==s&&"name"==o&&(m+=" // @ts-ignore"),m+=` ${o}?: ${r};\n`})),m+="}\n",d+=`export class ${r} extends AbstractModel<${r}, ${r}Data> {\n`,_.forEach(y,((e,t)=>{d+=` private _${t}?: ${e};\n`})),"user"==s&&(d+=" private _hash?: string;\n",d+=" private _privileges?: string[];\n"),d+="\n",d+=" static readonly attributeMap: ModelAttributeMap = {\n",a.forEach(((e,t)=>{t>0&&(d+=",\n"),d+=` ${e.name}: {\n`,e.physical&&(d+=" physical: true,\n"),e.alias&&(d+=` alias: "${e.alias}",\n`),e.virtual&&(d+=" virtual: true,\n"),e.typeScriptStyle&&(d+=" typeScriptStyle: true,\n"),d+=` type: "${e.type}",\n`,d+=` attribute: "_${e.attribute}"\n`,d+=" }"})),d+="\n",d+=" };\n",d+="\n",d+=" static getClassName(): string {\n",d+=` return "${r}";\n`,d+=" }\n",d+="\n",d+=" static getTableName(): string {\n",d+=` return "${s}";\n`,d+=" }\n",d+="\n",d+=" static getPrimaryKey(): string {\n",d+=` return "${o}";\n`,d+=" }\n",d+="\n",d+=` static from(other: ${r} | ${r}Data): ${r} {\n`,d+=` let value: ${r} = null;\n`,d+=" if (other) {\n",d+=` value = new ${r}();\n`,d+=` if (other instanceof ${r}) {\n`,d+=" Object.assign(value, other);\n",d+=" } else {\n",d+=" value.assign(other);\n",d+=" }\n",d+=" }\n",d+=" return value;\n",d+=" }\n",d+="\n",d+=` constructor(data?: ${r} | ${r}Data) {\n`,d+=" super();\n",d+=" if (data) {\n",d+=" this.assign(data);\n",d+=" }\n",d+=" }\n",d+="\n",d+=` public clone(): ${r} {\n`,d+=` return ${r}.from(this);\n`,d+=" }\n",d+="\n",d+=" public getClassName(): string {\n",d+=` return "${r}";\n`,d+=" }\n",d+="\n",d+=" public getTableName(): string {\n",d+=` return "${s}";\n`,d+=" }\n",d+="\n",d+=" public getPrimaryKey(): string {\n",d+=` return "${o}";\n`,d+=" }\n",d+="\n",d+=" public getAttributeMap(): ModelAttributeMap {\n",d+=` return ${r}.attributeMap;\n`,d+=" }\n",a.forEach((e=>{let r;d+="\n",r=e.name.length<3||e.name.match(/_/)?"FunctionNamingConventionJS":"",""!==r&&(d+=` // noinspection ${r}\n`),d+=` get ${e.name}(): ${e.type} {\n`,d+=` return this._${e.attribute};\n`,d+=" }\n\n",""!==r&&(d+=` // noinspection ${r}\n`);let a=e.attribute;t.includes(a)&&(a="value"),d+=` set ${e.name}(${a}: ${e.type}) {\n`,d+=` this._${e.attribute} = ${a};\n`,d+=" }\n"})),"user"==s&&(d+="\n",d+=" get hash(): string {\n",d+=" return this._hash;\n",d+=" }\n\n",d+=" set hash(hash: string) {\n",d+=" this._hash = hash;\n",d+=" }\n",d+="\n",d+=" get privileges(): string[] {\n",d+=" return this._privileges;\n",d+=" }\n\n",d+=" set privileges(p: string[]) {\n",d+=" this._privileges = p;\n",d+=" }\n"),d+="}\n",e.separateApi?(m=c+"\n"+p+"\n"+m,fs.writeFileSync(`${e.modelDirectory}/${u+"-api.ts"}`,m),d=c+"\n"+b+"\n"+d):d=c+"\n"+b+"\n"+m+"\n"+d,fs.writeFileSync(`${e.modelDirectory}/${u+".ts"}`,d)}else console.log("error: table has no fields")})).catch((e=>{console.error(e),process.abort()}))}}let s=`import {AbstractModel} from "${e.abstractModelModule}";\n`;_.forEach(n,(e=>{s+=`import {${e.className}} from "./${e.fileName}";\n`})),s+="\n",s+="interface SmartDbDictionaryEntry {\n",s+=" cls: "+n.map((e=>"typeof "+e.className)).join(" |\n "),s+=";\n",s+="}\n\n",s+="export class SmartDbDictionary {\n",s+=" static models: { [relation: string]: SmartDbDictionaryEntry; } = {\n",_.forEach(n,(e=>{s+=` ${e.className}: {\n`,s+=` cls: ${e.className}\n`,s+=" },\n"})),s=s.substring(0,s.length-2)+"\n",s+=" };\n",s+="}\n",fs.writeFileSync(`${e.modelDirectory}/smart-db-dictionary.ts`,s)})).catch((e=>{console.error("extraction error",e)}))}(async()=>{let e=!1;const t=Array.from(process.argv);let r,a,n,s=!1;for(t.shift(),t.shift();t[0]&&"--"==t[0].substring(0,2);)"--separate-api"==t[0]?(e=!0,t.shift()):"--connector"==t[0]?(r=t[1],t.shift(),t.shift()):"--username"==t[0]?(a=t[1],t.shift(),t.shift()):"--password"==t[0]?(r=t[1],t.shift(),t.shift()):"--create"==t[0]?(s=!0,t.shift()):(console.error(`unknown option '${t[2]}'`),process.exit(-1));if(r||(r=process.env.ORACLE_SID),a||(a=process.env.ORA_USER),n||(n=process.env.ORA_PASS),r&&t.length<=1){let o;a&&n?o=new SmartDbOracle(r,{user:a,password:n,noDbLogging:!0}):s||fs.existsSync(r)?o=new SmartDbBetterSqlite3(r,{}):(console.error(`ERROR: missing sqlite3 database file ${r}`),process.exit(-1)),1==t.length?o.onReady().subscribe((async r=>{if(r){o.getLogger().setDbLogging(!1);const r={skipCoreTables:!0,modelDirectory:t[0],smartDbInterfaces:"@egi/smart-db",abstractModelModule:"@egi/smart-db",separateApi:e,db:o};await extractDbApi(r)}})):fs.existsSync("src/helpers/extract-db-api.ts")?o.onReady().subscribe((t=>{if(t){const t={justCoreTables:!0,modelDirectory:"src/models/generated",smartDbInterfaces:"../smart-db-interfaces",abstractModelModule:"./abstract-model",separateApi:e,db:o};t.db.initDb({module:"smart-db-core",sqlFilesDirectory:"assets/sqlite3"}).then((async()=>{await extractDbApi(t)}))}else console.error("unable to connect to database")})):console.log("command must be run at the root directory of the smart-db project")}else console.log("USAGE: extract-db-api --connector {db-connector|path-to-db} [{options}] {target-models-directory}\n"),console.log("Options are: [--username {username}]"),console.log(" [--password {password}]"),console.log(" [--create"),console.log(" [--separate-api]")})();
|
|
1
|
+
import fs from"fs";import _ from"lodash";import process from"process";import{SmartDbBetterSqlite3}from"../drivers/smart-db-better-sqlite3";import{SmartDbOracle}from"../drivers/smart-db-oracle";import{OracleCatModel}from"../models/oracle-cat-model";import{SmartDbCoreTableModel}from"../models/smart-db-core-table-model";import{SqliteMasterModel}from"../models/sqlite-master-model";import{IN,NE,NOT_LIKE}from"../smart-db-globals";function getType(e){let t;return t=e?e.match(/varchar/i)||e.match(/text/i)?"string":e.match(/integer\(1\)/i)?"boolean":e.match(/date/i)?"Date":e.match(/integer/i)||e.match(/number/i)?"number":e.match(/long/i)||e.match(/raw/i)?"any":"SqlValueType":"SqlValueType",t}function getRelations(e){return new Promise((async(t,r)=>{e instanceof SmartDbOracle?e.getAll(OracleCatModel,{type:IN(["TABLE","VIEW"]),name:NOT_LIKE("BIN$%")}).then((a=>{a?t(a.map((e=>e.name.toLowerCase()))):r(e.getLastError())})).catch((e=>{r(e)})):e instanceof SmartDbBetterSqlite3?e.getAll(SqliteMasterModel,{type:IN(["table","view"]),name:NE("sqlite_sequence")}).then((a=>{a?t(a.map((e=>e.name))):r(e.getLastError())})).catch((e=>{r(e)})):r("unimplemented database type")}))}async function extractDbApi(e){console.log(`extract interface from '${e.db.getDbConnector()}' to '${e.modelDirectory}'`);const t=["break","case","catch","class","const","continue","debugger","default","delete","do","else","enum","export","extends","false","finally","for","function","If","import","in","instanceOf","interface","new","null","return","super","switch","this","throw","true","try","typeOf","var","void","while","with"];fs.existsSync(e.modelDirectory)||fs.mkdirSync(e.modelDirectory,{recursive:!0}),getRelations(e.db).then((async r=>{let a=[];if((e.skipCoreTables||e.justCoreTables)&&await e.db.exists(SmartDbCoreTableModel)){const t=await e.db.getAll(SmartDbCoreTableModel);if(!1===t)throw e.db.getLastError();t.forEach((e=>{a.push(e.name)}))}const n=[];for(const s of r){let r=!0;if(e.justCoreTables?r=a.includes(s):e.skipCoreTables&&(r=!a.includes(s)),r){const r=s[0].toUpperCase()+_.camelCase(s.substring(1))+"Model",a=[];console.log("working on",s),await e.db.getTableInfo(s).then((o=>{const i=o.fields;let l=!1,c="",m="",p="",d="",b="";const u=s.toLowerCase().replace(/[^[a-z0-9]/g,"-")+"-model";if(n.push({className:r,fileName:u}),c+="/* eslint-disable @typescript-eslint/member-ordering */\n",c+="// noinspection JSUnusedGlobalSymbols\n",i){e.abstractModelModule==e.smartDbInterfaces?e.separateApi?(p+=`import {GenericModelData} from "${e.abstractModelModule}";\n`,b+=`import {AbstractModel, ModelAttributeMap} from "${e.abstractModelModule}";\n`,b+=`import {${r}Data} from "./${u}-api";\n`):b+=`import {AbstractModel, GenericModelData, ModelAttributeMap} from "${e.abstractModelModule}";\n`:e.separateApi?(p+=`import {GenericModelData} from "${e.smartDbInterfaces}";\n`,b+=`import {ModelAttributeMap} from "${e.smartDbInterfaces}";\n`,b+=`import {AbstractModel} from "${e.abstractModelModule}";\n`,b+=`import {${r}Data} from "./${u}-api";\n`):(b+=`import {GenericModelData, ModelAttributeMap} from "${e.smartDbInterfaces}";\n`,b+=`import {AbstractModel} from "${e.abstractModelModule}";\n`),m+=`export interface ${r}Data extends GenericModelData {\n`;let n,o="",f="",h=!1;const g=[];i.forEach((e=>{const t=e.name.match(/([a-z0-9]{1,4})_/i);e.isPk&&(o=e.name,t&&(f=t[1])),t?g.includes(t[1])||g.push(t[1]):h=!0})),f||h||1!=g.length||(f=g[0]),f&&(n=new RegExp(`^${f}_(.*)$`));const y={};i.forEach((t=>{const r=getType(t.type);let o;l||"SqlValueType"!=r||(p+=`import {SqlValueType} from "${e.smartDbInterfaces}";\n`,b+=`import {SqlValueType} from "${e.smartDbInterfaces}";\n`,l=!0);const i=n&&t.name.match(n);o=i?_.camelCase(i[1]):_.camelCase(t.name);let c=!0;if(o!=t.name&&(a.push({name:o,attribute:o,type:r,typeScriptStyle:c,alias:t.name}),c=!1),o!=t.name.toLowerCase()&&(a.push({name:t.name.toLowerCase(),attribute:o,type:r,physical:void 0!==t.cid&&t.name==t.name.toLowerCase(),typeScriptStyle:c}),c=!1),o!=t.name.toUpperCase()&&a.push({name:t.name.toUpperCase(),attribute:o,type:r,physical:void 0!==t.cid&&t.name==t.name.toUpperCase(),typeScriptStyle:c}),t.cid){const e=a.find((e=>e.physical&&e.name.toLowerCase()==t.name.toLowerCase()));e||a.push({name:t.name,attribute:o,type:r,physical:!0,typeScriptStyle:c})}y[o]=r,"user"==s&&"name"==o&&(m+=" // @ts-ignore"),m+=` ${o}?: ${r};\n`})),m+="}\n",d+=`export class ${r} extends AbstractModel<${r}, ${r}Data> {\n`,_.forEach(y,((e,t)=>{d+=` private _${t}?: ${e};\n`})),"user"==s&&(d+=" private _hash?: string;\n",d+=" private _privileges?: string[];\n"),d+="\n",d+=" static readonly attributeMap: ModelAttributeMap = {\n",a.forEach(((e,t)=>{t>0&&(d+=",\n"),d+=` ${e.name}: {\n`,e.physical&&(d+=" physical: true,\n"),e.alias&&(d+=` alias: "${e.alias}",\n`),e.virtual&&(d+=" virtual: true,\n"),e.typeScriptStyle&&(d+=" typeScriptStyle: true,\n"),d+=` type: "${e.type}",\n`,d+=` attribute: "_${e.attribute}"\n`,d+=" }"})),d+="\n",d+=" };\n",d+="\n",d+=" static getClassName(): string {\n",d+=` return "${r}";\n`,d+=" }\n",d+="\n",d+=" static getTableName(): string {\n",d+=` return "${s}";\n`,d+=" }\n",d+="\n",d+=" static getPrimaryKey(): string {\n",d+=` return "${o}";\n`,d+=" }\n",d+="\n",d+=` static from(other: ${r} | ${r}Data): ${r} {\n`,d+=` let value: ${r} = null;\n`,d+=" if (other) {\n",d+=` value = new ${r}();\n`,d+=` if (other instanceof ${r}) {\n`,d+=" Object.assign(value, other);\n",d+=" } else {\n",d+=" value.assign(other);\n",d+=" }\n",d+=" }\n",d+=" return value;\n",d+=" }\n",d+="\n",d+=` constructor(data?: ${r} | ${r}Data) {\n`,d+=" super();\n",d+=" if (data) {\n",d+=" this.assign(data);\n",d+=" }\n",d+=" }\n",d+="\n",d+=` public clone(): ${r} {\n`,d+=` return ${r}.from(this);\n`,d+=" }\n",d+="\n",d+=" public getClassName(): string {\n",d+=` return "${r}";\n`,d+=" }\n",d+="\n",d+=" public getTableName(): string {\n",d+=` return "${s}";\n`,d+=" }\n",d+="\n",d+=" public getPrimaryKey(): string {\n",d+=` return "${o}";\n`,d+=" }\n",d+="\n",d+=" public getAttributeMap(): ModelAttributeMap {\n",d+=` return ${r}.attributeMap;\n`,d+=" }\n",a.forEach((e=>{let r;d+="\n",r=e.name.length<3||e.name.match(/_/)?"FunctionNamingConventionJS":"",""!==r&&(d+=` // noinspection ${r}\n`),d+=` get ${e.name}(): ${e.type} {\n`,d+=` return this._${e.attribute};\n`,d+=" }\n\n",""!==r&&(d+=` // noinspection ${r}\n`);let a=e.attribute;t.includes(a)&&(a="value"),d+=` set ${e.name}(${a}: ${e.type}) {\n`,d+=` this._${e.attribute} = ${a};\n`,d+=" }\n"})),"user"==s&&(d+="\n",d+=" get hash(): string {\n",d+=" return this._hash;\n",d+=" }\n\n",d+=" set hash(hash: string) {\n",d+=" this._hash = hash;\n",d+=" }\n",d+="\n",d+=" get privileges(): string[] {\n",d+=" return this._privileges;\n",d+=" }\n\n",d+=" set privileges(p: string[]) {\n",d+=" this._privileges = p;\n",d+=" }\n"),d+="}\n",e.separateApi?(m=c+"\n"+p+"\n"+m,fs.writeFileSync(`${e.modelDirectory}/${u+"-api.ts"}`,m),d=c+"\n"+b+"\n"+d):d=c+"\n"+b+"\n"+m+"\n"+d,fs.writeFileSync(`${e.modelDirectory}/${u+".ts"}`,d)}else console.log("error: table has no fields")})).catch((e=>{console.error(e),process.abort()}))}}let s=`import {AbstractModel} from "${e.abstractModelModule}";\n`;_.forEach(n,(e=>{s+=`import {${e.className}} from "./${e.fileName}";\n`})),s+="\n",s+="interface SmartDbDictionaryEntry {\n",s+=" cls: "+n.map((e=>"typeof "+e.className)).join(" |\n "),s+=";\n",s+="}\n\n",s+="export class SmartDbDictionary {\n",s+=" static models: { [relation: string]: SmartDbDictionaryEntry; } = {\n",_.forEach(n,(e=>{s+=` ${e.className}: {\n`,s+=` cls: ${e.className}\n`,s+=" },\n"})),s=s.substring(0,s.length-2)+"\n",s+=" };\n",s+="}\n",fs.writeFileSync(`${e.modelDirectory}/smart-db-dictionary.ts`,s)})).catch((e=>{console.error("extraction error",e)}))}(async()=>{let e=!1;const t=Array.from(process.argv);let r,a,n,s=!1;for(t.shift(),t.shift();t[0]&&"--"==t[0].substring(0,2);)"--separate-api"==t[0]?(e=!0,t.shift()):"--database"==t[0]?(r=t[1],t.shift(),t.shift()):"--username"==t[0]?(a=t[1],t.shift(),t.shift()):"--password"==t[0]?(n=t[1],t.shift(),t.shift()):"--create"==t[0]?(s=!0,t.shift()):(console.error(`unknown option '${t[2]}'`),process.exit(-1));if(r||(r=process.env.ORACLE_SID),fs.existsSync(r)||(a||(a=process.env.ORA_USER),n||(n=process.env.ORA_PASS)),r&&t.length<=1){let o;a&&n?o=new SmartDbOracle(r,{user:a,password:n,noDbLogging:!0}):s||fs.existsSync(r)?o=new SmartDbBetterSqlite3(r,{}):(console.error(`ERROR: missing sqlite3 database file ${r}`),process.exit(-1)),1==t.length?o.onReady().subscribe((async r=>{if(r){o.getLogger().setDbLogging(!1);const r={skipCoreTables:!0,modelDirectory:t[0],smartDbInterfaces:"@egi/smart-db",abstractModelModule:"@egi/smart-db",separateApi:e,db:o};await extractDbApi(r)}})):fs.existsSync("src/helpers/extract-db-api.ts")?o.onReady().subscribe((t=>{if(t){const t={justCoreTables:!0,modelDirectory:"src/models/generated",smartDbInterfaces:"../smart-db-interfaces",abstractModelModule:"./abstract-model",separateApi:e,db:o};t.db.initDb({module:"smart-db-core",sqlFilesDirectory:"assets/sqlite3"}).then((async()=>{await extractDbApi(t)}))}else console.error("unable to connect to database")})):console.log("command must be run at the root directory of the smart-db project")}else console.log("USAGE: extract-db-api --database {db-connector|path-to-db} [{options}] {target-models-directory}\n"),console.log("Options are: [--username {username}]"),console.log(" [--password {password}]"),console.log(" [--create"),console.log(" [--separate-api]")})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@egi/smart-db",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.2",
|
|
4
4
|
"description": "Unified Smart DB Access",
|
|
5
5
|
"author": "Marcel Egloff",
|
|
6
6
|
"type": "module",
|
|
@@ -24,9 +24,7 @@
|
|
|
24
24
|
"dev:watch": "npm-run-all clean copy:assets dev:tsc:watch",
|
|
25
25
|
"extract:db:api": "bin/extract-db-api && tsc --build tsconfig.test-model.json",
|
|
26
26
|
"publish": "npm-run-all pro:build npm:publish",
|
|
27
|
-
"unpublish": "npm-run-all npm:unpublish",
|
|
28
27
|
"npm:publish": "cd dist; npm publish",
|
|
29
|
-
"npm:unpublish": "cd dist; npm unpublish",
|
|
30
28
|
"pro:build": "npm-run-all clean pro:tsc terser copy:assets",
|
|
31
29
|
"pro:tsc": "tsc --build tsconfig.pro.json",
|
|
32
30
|
"pro:tsc:watch": "tsc --build tsconfig.pro.json --watch",
|
package/smart-db-api.d.ts
CHANGED
package/smart-db-api.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./smart-db";export*from"./models/abstract-model";export*from"./models/smart-db-core-table-model";export*from"./models/smart-db-dictionary";export*from"./models/smart-db-log-model";export*from"./models/smart-db-version-model";export*from"./models/smart-db-version-view-model";export*from"./models/sqlite-master-model";export*from"./models/sqlite-sequence-model";export*from"./smart-db-log";export*from"./smart-db-globals";export*from"./smart-db-interfaces";
|
|
1
|
+
export*from"./smart-db";export*from"./smart-error";export*from"./models/abstract-model";export*from"./models/smart-db-core-table-model";export*from"./models/smart-db-dictionary";export*from"./models/smart-db-log-model";export*from"./models/smart-db-version-model";export*from"./models/smart-db-version-view-model";export*from"./models/sqlite-master-model";export*from"./models/sqlite-sequence-model";export*from"./smart-db-log";export*from"./smart-db-globals";export*from"./smart-db-interfaces";
|
package/smart-db-log.d.ts
CHANGED
|
@@ -1,25 +1,5 @@
|
|
|
1
1
|
import { SmartDb } from "./smart-db";
|
|
2
|
-
|
|
3
|
-
Frontend: string;
|
|
4
|
-
Backend: string;
|
|
5
|
-
Database: string;
|
|
6
|
-
UpgradeManager: string;
|
|
7
|
-
Other: string;
|
|
8
|
-
};
|
|
9
|
-
export declare type SmartDbLogLocationType = typeof SmartDbLogLocation;
|
|
10
|
-
export declare type SmartDbLogLocationKey = keyof SmartDbLogLocationType;
|
|
11
|
-
export declare type SmartDbLogLocationValue = SmartDbLogLocationType[keyof SmartDbLogLocationType];
|
|
12
|
-
export declare const SeverityCode: {
|
|
13
|
-
readonly Fatal: "F";
|
|
14
|
-
readonly Error: "E";
|
|
15
|
-
readonly Warning: "W";
|
|
16
|
-
readonly Info: "I";
|
|
17
|
-
readonly Debug: "D";
|
|
18
|
-
readonly Local: "L";
|
|
19
|
-
};
|
|
20
|
-
export declare type SeverityCodeType = typeof SeverityCode;
|
|
21
|
-
export declare type SeverityCodeKey = keyof SeverityCodeType;
|
|
22
|
-
export declare type SeverityCodeValue = SeverityCodeType[keyof SeverityCodeType];
|
|
2
|
+
import { SmartErrorSeverityValue, SmartErrorLocationValue } from "./smart-error";
|
|
23
3
|
export declare const SeverityLevel: {
|
|
24
4
|
readonly None: 0;
|
|
25
5
|
readonly Fatal: 1;
|
|
@@ -44,17 +24,17 @@ export declare class SmartDbLog {
|
|
|
44
24
|
getConsoleLogLevel(): SeverityLevelValue;
|
|
45
25
|
getDbLogLevel(): SeverityLevelValue;
|
|
46
26
|
getDbLogging(): boolean;
|
|
47
|
-
logDebug(type:
|
|
48
|
-
logError(type:
|
|
49
|
-
logFatal(type:
|
|
50
|
-
logInfo(type:
|
|
51
|
-
logWarning(type:
|
|
27
|
+
logDebug(type: SmartErrorLocationValue, location: string, message: string | Error, data?: any): void;
|
|
28
|
+
logError(type: SmartErrorLocationValue, location: string, message: string | Error, data?: any): void;
|
|
29
|
+
logFatal(type: SmartErrorLocationValue, location: string, message: string | Error, data?: any): void;
|
|
30
|
+
logInfo(type: SmartErrorLocationValue, location: string, message: string | Error, data?: any): void;
|
|
31
|
+
logWarning(type: SmartErrorLocationValue, location: string, message: string | Error, data?: any): void;
|
|
52
32
|
setConsoleLogLevel(consoleLogLevel: SeverityLevelValue): void;
|
|
53
33
|
setDb(db: SmartDb): void;
|
|
54
34
|
setDbLogLevel(dbLogLevel: SeverityLevelValue): void;
|
|
55
35
|
setDbLogging(dbLogging: boolean): void;
|
|
56
36
|
setUserId(userId: string | number): void;
|
|
57
|
-
writeLog(type:
|
|
37
|
+
writeLog(type: SmartErrorLocationValue, location: string, severity: SmartErrorSeverityValue, message: string | Error, data: unknown, timestamp?: Date | string | number): void;
|
|
58
38
|
private nextStackEntry;
|
|
59
39
|
}
|
|
60
40
|
export declare const smartDbLog: SmartDbLog;
|
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
|
|
1
|
+
import _ from"lodash";import{SmartDbLogModel}from"./models/smart-db-log-model";import{SmartErrorSeverity,SmartErrorLocation}from"./smart-error";import{SmartDbDateRegexp,SmartDbTimestampRegexp,toSmartDbTimestamp}from"./smart-db-globals";export const SeverityLevel={None:0,Fatal:1,Error:2,Warning:3,Info:4,Debug:5,All:9};export class SmartDbLog{constructor(t){this.userId=null,this.dbLogging=!0,this.isLogging=!1,this.logFifo=[],this.db=t,this.dbLogging=!1,this.dbLogLevel=SeverityLevel.Info,this.consoleLogLevel=SeverityLevel.Info}getConsoleLogLevel(){return this.consoleLogLevel}getDbLogLevel(){return this.dbLogLevel}getDbLogging(){return this.dbLogging}logDebug(t,e,r,o){this.writeLog(t,e,SmartErrorSeverity.Debug,r,o)}logError(t,e,r,o){this.writeLog(t,e,SmartErrorSeverity.Error,r,o)}logFatal(t,e,r,o){this.writeLog(t,e,SmartErrorSeverity.Fatal,r,o)}logInfo(t,e,r,o){this.writeLog(t,e,SmartErrorSeverity.Info,r,o)}logWarning(t,e,r,o){this.writeLog(t,e,SmartErrorSeverity.Warning,r,o)}setConsoleLogLevel(t){this.consoleLogLevel=t}setDb(t){this.db=t,this.db?this.db.exists(SmartDbLogModel).then((t=>{this.dbLogging=t})).catch((t=>{throw t})):this.dbLogging=!1}setDbLogLevel(t){this.dbLogLevel=t}setDbLogging(t){this.dbLogging=t}setUserId(t){this.userId=t}writeLog(t,e,r,o,i,s){try{if(this.isLogging)this.logFifo.push({type:t,location:e,severity:r,message:o,data:i,timestamp:s??new Date});else{this.isLogging=!0;let a,g,n=SeverityLevel.None;switch(r){case SmartErrorSeverity.Fatal:a=console.error,n=SeverityLevel.Fatal;break;case SmartErrorSeverity.Error:a=console.error,n=SeverityLevel.Error;break;case SmartErrorSeverity.Warning:a=console.warn,n=SeverityLevel.Warning;break;case SmartErrorSeverity.Info:a=console.info,n=SeverityLevel.Info;break;case SmartErrorSeverity.Debug:a=console.debug,n=SeverityLevel.Debug}if(_.isString(s)){const t=s.match(SmartDbTimestampRegexp),e=t&&s.match(SmartDbDateRegexp);g=t?t[1]:e?e[1]+".000":toSmartDbTimestamp(new Date)}else g=_.isDate(s)?toSmartDbTimestamp(s):_.isNumber(s)?toSmartDbTimestamp(new Date(s)):toSmartDbTimestamp(new Date);if(_.isObjectLike(o))if(o instanceof Error)i||(i=o),o=o.message;else try{o=JSON.stringify(o)}catch(t){o=o.toString()}else"boolean"==typeof o&&(o=o?"<true>":"<false>");if(i){if(i instanceof Error)i=i.stack;else if(_.isObject(i))try{i=JSON.stringify(i)}catch(t){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&&(o+=` (${i})`)}if(this.consoleLogLevel>=n){const s=t.substring(0,1).toUpperCase();if(t==SmartErrorLocation.Database&&this.db&&a(`${r}-${s}-${g}: last statement:`,this.db.getLastBuildData()),a(`${r}-${s}-${g}: ${o}`),this.dbLogging)try{t==SmartErrorLocation.Database&&(i||(i=JSON.stringify(this.db.getLastBuildData()))),this.db.supportSyncCalls?(this.db.insertSync(SmartDbLogModel,{severity:r,type:t,location:e,info:o||"<empty>",data:i,user:this.userId,timestamp:new Date(g)}),this.isLogging=!1,this.nextStackEntry()):this.db.insert(SmartDbLogModel,{severity:r,type:t,location:e,info:o||"<empty>",data:i,user:this.userId,timestamp:new Date(g)}).then((()=>{this.db.commit().then((()=>{this.isLogging=!1,this.nextStackEntry()})).catch((t=>{console.error(`F-B-${g}: unable to commit log transaction`,t,t.code,t.name,t.message),this.isLogging=!1,this.nextStackEntry()}))})).catch((t=>{console.error(`F-B-${g}: unable to write the log statement below to database`,t,t.code,t.name,t.message),this.isLogging=!1,this.nextStackEntry()}))}catch(t){console.error(`F-B-${g}: unable to write the log statement below to database`,t,t.code,t.name,t.message);try{a(`F-B-${g}: last statement:`,this.db.getLastBuildData())}catch{a(`F-B-${g}: last statement not available`)}this.isLogging=!1,this.nextStackEntry()}else this.isLogging=!1,this.nextStackEntry()}else this.isLogging=!1,this.nextStackEntry()}}catch(t){this.isLogging=!1,console.error("fatal logging error",t)}}nextStackEntry(){if(this.logFifo.length>0){const t=this.logFifo.shift();this.writeLog(t.type,t.location,t.severity,t.message,t.data,t.timestamp)}}}export const smartDbLog=new SmartDbLog;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as fs from"fs";import _ from"lodash";import{SmartDbVersionModel}from"./models/smart-db-version-model";import{SmartDbVersionViewModel}from"./models/smart-db-version-view-model";import{
|
|
1
|
+
import*as fs from"fs";import _ from"lodash";import{SmartDbVersionModel}from"./models/smart-db-version-model";import{SmartDbVersionViewModel}from"./models/smart-db-version-view-model";import{SmartErrorLocation}from"./smart-error";export class SmartDbUpgradeManager{constructor(e){this.db=e,this.log=e.getLogger()}hasDatabaseModule(e){return new Promise(((t,r)=>{this.db.exists(SmartDbVersionModel).then((a=>{a?this.db.getFirst(SmartDbVersionModel,{module:e}).then((e=>{t(!!e)})).catch((e=>{r(e)})):t(!1)})).catch((e=>{r(e)}))}))}prepareDatabase(e){return new Promise(((t,r)=>{try{const a=fs.existsSync(e.sqlFilesDirectory)&&fs.statSync(e.sqlFilesDirectory);if(a&&a.isDirectory()){const a=e.sqlFilesDirectory+`/${e.module}-init.sql`;fs.existsSync(a)?this.hasDatabaseModule(e.module).then((o=>{o?(this.log.logInfo(SmartErrorLocation.UpgradeManager,"prepareDatabase",`database module '${e.module}' exists`),this.upgradeDatabase(e).then((r=>{this.log.logInfo(SmartErrorLocation.UpgradeManager,"prepareDatabase",`connected to module '${e.module}' version ${r.versionString}`),t(r)})).catch((e=>{r(e)}))):(this.log.setDbLogging(!1),this.log.logInfo(SmartErrorLocation.UpgradeManager,"prepareDatabase",`database module '${e.module}' doesn't exists - begin creation`),this.db.execScript(a,!0).then((()=>{this.log.setDbLogging(this.db.dbLogging),this.log.logInfo(SmartErrorLocation.UpgradeManager,"prepareDatabase","database module creation complete"),this.hasDatabaseModule(e.module).then((a=>{a?(this.log.logInfo(SmartErrorLocation.UpgradeManager,"prepareDatabase",`successfully initialized database for new module ${e.module}`),this.upgradeDatabase(e).then((r=>{this.log.logInfo(SmartErrorLocation.UpgradeManager,"prepareDatabase",`connected to module '${e.module}' version ${r.versionString}`),t(r)})).catch((e=>{r(e)}))):r("error running database initialization script")})).catch((e=>{r(e)}))})).catch((e=>{r(e)})))})).catch((e=>{r(e)})):r(`missing mandatory '${e.module}-init.sql' file in ${a}`)}else r(`option 'sqlFilesDirectory' (${e.sqlFilesDirectory}) must point to an existing directory (absolute or relative to ${fs.realpathSync(".")})`)}catch(e){r(e)}}))}upgradeDatabase(e){return new Promise(((t,r)=>{this.db.getFirst(SmartDbVersionViewModel,{module:e.module}).then((a=>{a?fs.readdir(e.sqlFilesDirectory,((o,s)=>{if(o)r(`unable to read database files from ${e.sqlFilesDirectory}`);else{let o=[];s.forEach((t=>{const r=new RegExp(`^${e.module}-update.([0-9]{3})\\..*\\.sql$`),s=t.match(r);if(s){parseInt(s[1],10)>a.sequence&&o.push(t)}})),o=_.sortBy(o),this.executeScriptsSequentially(o,e).then((()=>{this.db.getFirst(SmartDbVersionViewModel,{module:e.module},"*","sequence DESC").then((e=>{e?t(SmartDbVersionViewModel.from(e)):r("unable to determine final smart db version")})).catch((e=>{r(e)}))})).catch((e=>{r(e)}))}})):r(`missing version entry for module ${e.module} - add the mandatory insert into smart_db_version statement to your database creation script!`)})).catch((e=>{r(e)}))}))}executeScriptsSequentially(e,t){return new Promise((async(r,a)=>{e&&e.length>0?(this.log.logInfo(SmartErrorLocation.UpgradeManager,"upgradeDatabase",`execute update script '${e[0]}' for module ${t.module}`),await this.db.execScript(`${t.sqlFilesDirectory}/${e[0]}`).then((()=>{this.log.logInfo(SmartErrorLocation.UpgradeManager,"upgradeDatabase",`successfully executed update script '${e[0]}' for module ${t.module}`),1==e.length&&r(!0)})).catch((e=>{a(e)})),e.length>1&&this.executeScriptsSequentially(e.splice(1),t).then((e=>{r(e)})).catch((e=>{a(e)}))):r(!0)}))}}
|
package/smart-db.d.ts
CHANGED
|
@@ -4,17 +4,18 @@ import { SmartDbVersionViewModel } from "./models/smart-db-version-view-model";
|
|
|
4
4
|
import { GenericModelData, IndexedGenericModelData, SmartDbConnector, SmartDbDatabase, SmartDbOptions, SmartDbRunResult, SmartDbSqlOptions, SmartDbTableInfo, SqlFieldDescriptor, SqlLimit, SqlOrderBy, SqlUpdateValues, SqlValueType, SqlWhere } from "./smart-db-interfaces";
|
|
5
5
|
import { SmartDbLog } from "./smart-db-log";
|
|
6
6
|
import { SmartDbSqlBuildData } from "./smart-db-sql-build-data";
|
|
7
|
+
import { SmartError } from "./smart-error";
|
|
7
8
|
export declare abstract class SmartDb {
|
|
8
9
|
abstract getDatabaseType(): string;
|
|
9
10
|
abstract getTableInfo(table: string): Promise<SmartDbTableInfo>;
|
|
10
11
|
protected: any;
|
|
11
12
|
readonly dbLogging: boolean;
|
|
12
13
|
protected dbConnector: SmartDbConnector;
|
|
13
|
-
protected lastError: Error;
|
|
14
14
|
protected lastBuildData: SmartDbSqlBuildData;
|
|
15
15
|
protected smartDbLog: SmartDbLog;
|
|
16
16
|
protected _onReady: BehaviorSubject<boolean>;
|
|
17
17
|
protected db: SmartDbDatabase;
|
|
18
|
+
private _lastError;
|
|
18
19
|
private dictionaries;
|
|
19
20
|
private _isReady;
|
|
20
21
|
protected constructor(dbConnector: SmartDbConnector, noDbLogging?: boolean);
|
|
@@ -40,7 +41,7 @@ export declare abstract class SmartDb {
|
|
|
40
41
|
getFirst<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy): Promise<T | false>;
|
|
41
42
|
getFirstSync<T extends AbstractModel<T, D>, D extends GenericModelData>(modelClass: string | (new () => T), where?: SqlWhere, fields?: string | string[] | null, orderBy?: SqlOrderBy): T | false;
|
|
42
43
|
getLastBuildData(): SmartDbSqlBuildData;
|
|
43
|
-
getLastError():
|
|
44
|
+
getLastError(): SmartError;
|
|
44
45
|
getLogger(): SmartDbLog;
|
|
45
46
|
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;
|
|
46
47
|
hasConcurrentTransactions(): boolean;
|
|
@@ -80,5 +81,7 @@ export declare abstract class SmartDb {
|
|
|
80
81
|
private getTableName;
|
|
81
82
|
get isReady(): boolean;
|
|
82
83
|
set isReady(ready: boolean);
|
|
84
|
+
get lastError(): SmartError;
|
|
85
|
+
set lastError(value: any);
|
|
83
86
|
get supportSyncCalls(): boolean;
|
|
84
87
|
}
|
package/smart-db.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import fs from"fs";import _ from"lodash";import{BehaviorSubject}from"rxjs";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(t,e){this.dictionaries=[],this.dbConnector=t,this.smartDbLog=new SmartDbLog(e?null:this),this.dbLogging=!e,this.db=null,this._isReady=null,this._onReady=new BehaviorSubject(!1)}buildSelectStatement(t,e){e||(e={});const r=this.buildSelectSectionStatement(t,e);if(_.forEach(["union","minus","intersect"],(t=>{let s=_.get(e,t);s&&(_.isArray(s)||(s=[s]),_.forEach(s,(e=>{const s=this.buildSelectSectionStatement(e.model,e);r.sql+=" "+t.toUpperCase()+" ",r.append(s)})))})),e.orderBy){r.sql+=" ORDER BY ";const s=_.isString(e.orderBy)?e.orderBy.split(/ *, */):e.orderBy;r.sql+=s.map((e=>{let r="";const s=e.match(/^(\w*) (asc|desc)$/i);return s&&(e=s[1],r=s[2].toUpperCase()),e=this.translateFieldName(t,e),r&&(e+=" "+r),e})).join(", ")}return e.limit&&(e.limit.limit&&(r.sql+=" LIMIT "+e.limit.limit.toString()),e.limit.offset&&(r.sql+=" OFFSET "+e.limit.offset.toString())),this.lastBuildData=r,r}close(){return new Promise(((t,e)=>{try{t(this.closeSync())}catch(t){e(t)}}))}closeSync(){throw new Error("Method not implemented (close)")}commit(){return new Promise(((t,e)=>{try{t(this.commitSync())}catch(t){e(t)}}))}commitSync(){throw new Error("Method not implemented (commit)")}delete(t,e){return new Promise(((r,s)=>{const a=this.buildDeleteStatement(t,e);this.statementRun(a).then((t=>{t?r(t.changes):s(this.getLastError())})).catch((t=>{this.lastError=t,s(t)}))}))}deleteSync(t,e){if(this.supportSyncCalls)return this.saveExecute((()=>{const r=this.buildDeleteStatement(t,e);return this.statementRunSync(r).changes}));throw"This database driver doesn't support sync calls (deleteSync)"}exec(t){return new Promise(((e,r)=>{try{this.execSync(t)?e():r(this.getLastError())}catch(t){r(t)}}))}execScript(t,e){return new Promise((async(r,s)=>{const a=this.scriptParser(t);let i=!1;for(const t of a)try{await this.exec(t)}catch(r){if(!e||"drop "!=t.trim().substring(0,5).toLowerCase()){i=!0,this.lastBuildData=new SmartDbSqlBuildData(t),this.lastError=r;break}}i?(await this.rollback(),s(this.lastError)):(await this.commit(),r())}))}execScriptSync(t){if(!this.supportSyncCalls)throw"This database driver doesn't support sync calls (execScriptSync)";{const e=this.scriptParser(t);for(const t of e)try{this.execSync(t)}catch(e){if("drop "!=t.substring(0,5).toLowerCase())throw this.lastBuildData=new SmartDbSqlBuildData(t),this.lastError=e,e}this.commitSync()}}execSync(t){throw new Error("Method not implemented (exec)")}exists(t,e,r){return new Promise(((s,a)=>{try{s(this.existsSync(t,e,r))}catch(t){a(t)}}))}existsSync(t,e,r){throw new Error("Method not implemented (exists)")}get(t,e){return new Promise(((r,s)=>{e||(e={});const a=this.buildSelectStatement(t,e);e.firstOnly||e.count?this.statementGet(a).then((s=>{r(this.prepareResultRow(t,s,e))})).catch((t=>{s(t)})):this.statementGetAll(a).then((s=>{r(this.prepareResultRows(t,s,e))})).catch((t=>{s(t)}))}))}getAll(t,e,r,s,a){return this.get(t,{where:e,fields:r,orderBy:s,limit:a})}getAllSync(t,e,r,s,a){return this.getSync(t,{where:e,fields:r,orderBy:s,limit:a})}getDb(){return this.db}getDbConnector(){return this.dbConnector}getDbQuote(){return'"'}getFirst(t,e,r,s){return this.get(t,{firstOnly:!0,where:e,fields:r,orderBy:s})}getFirstSync(t,e,r,s){return this.getSync(t,{firstOnly:!0,where:e,fields:r,orderBy:s})}getLastBuildData(){return this.lastBuildData}getLastError(){return this.lastError}getLogger(){return this.smartDbLog}getSync(t,e){if(this.supportSyncCalls)return this.saveExecute((()=>{e||(e={});const r=this.buildSelectStatement(t,e);let s;if(e.firstOnly||e.count){const a=this.statementGetSync(r);s=this.prepareResultRow(t,a,e)}else{const a=this.statementGetAllSync(r);s=this.prepareResultRows(t,a,e)}return s}));throw"This database driver doesn't support sync calls (getSync)"}hasConcurrentTransactions(){return!1}hasTransaction(){throw new Error("Method not implemented (hasTransaction)")}initDb(t){return new Promise(((e,r)=>{this.dictionaries.push(SmartDbDictionary);const s=new SmartDbUpgradeManager(this);let a;a=import.meta&&import.meta.url?import.meta.url.replace(/file:\/\//,"").replace(/\/[^/]*$/,""):__dirname;const i={module:"smart-db-core",sqlFilesDirectory:a+"/assets/"+this.getDatabaseType()};s.prepareDatabase(i).then((a=>{this.exists(SmartDbLogModel).then((i=>{this.smartDbLog.setDbLogging(this.dbLogging&&i),s.prepareDatabase(t).then((t=>{e([a,t])}),(t=>{r(t)}))}))})).catch((t=>{r(t)}))}))}insert(t,e){return new Promise(((r,s)=>{const a=this.buildInsertStatement(t,e);this.statementRun(a).then((t=>{t?r(t.lastId):s(this.getLastError())})).catch((t=>{s(t)}))}))}insertSync(t,e){if(this.supportSyncCalls)return this.saveExecute((()=>{const r=this.buildInsertStatement(t,e);return this.statementRunSync(r).lastId}));throw"This database driver doesn't support sync calls (insertSync)"}onReady(){return this._onReady}rollback(){return new Promise(((t,e)=>{try{t(this.rollbackSync())}catch(t){e(t)}}))}rollbackSync(){throw new Error("Method not implemented (rollback)")}toDate(t){return smartDbToDate(t)}toDbDate(t){return toSmartDbDate(t)}toDbTimestamp(t){return toSmartDbTimestamp(t)}update(t,e,r){return new Promise(((s,a)=>{const i=this.buildUpdateStatement(t,e,r);this.statementRun(i).then((t=>{t?s(t.changes):a(this.getLastError())})).catch((t=>{a(t)}))}))}updateSync(t,e,r){if(this.supportSyncCalls)return this.saveExecute((()=>{const s=this.buildUpdateStatement(t,e,r);return this.statementRunSync(s).changes}));throw"This database driver doesn't support sync calls (updateSync)"}statementRun(t){return new Promise(((e,r)=>{try{e(this.statementRun(t))}catch(t){r(t)}}))}statementRunSync(t){throw new Error("Method not implemented (statementRun)")}statementGet(t){return new Promise(((e,r)=>{try{e(this.statementGetSync(t))}catch(t){r(t)}}))}statementGetSync(t){throw new Error("Method not implemented (statementGet)")}statementGetAll(t){return new Promise(((e,r)=>{try{e(this.statementGetAllSync(t))}catch(t){r(t)}}))}statementGetAllSync(t){throw new Error("Method not implemented (statementGetAll)")}buildWhere(t,e,r){const s=new SmartDbSqlBuildData;return e&&_.keys(e).length>0&&(r||(r="AND",s.sql+=" WHERE "),s.sql+=_.map(e,((e,a)=>{const i=a.toUpperCase();if("AND"==i||"OR"==i){let r="";return(_.isArray(e)?e:[e]).forEach(((e,a)=>{const n=this.buildWhere(t,e,i);a>0&&(r+=" "+i+" "),r+=n.sql,s.values=_.concat(s.values,n.values)})),r="("+r+")",r}if("EXPRESSION"==i){let a=[];return _.forEach(e,(e=>{const r=this.prepareField(t,e.compare,s.values),i=this.prepareField(t,e.with,s.values);let n;n=_.isString(e.operation)&&SqlOperationType[e.operation]?SqlOperationType[e.operation]:e.operation||SqlOperationType.EQ,a.push(`${r} ${n} ${i}`)})),a.join(" "+r+" ")}{let r,i,n=!0;if(_.isArray(e)&&(e=IN(e)),_.isObject(e)){const t=e;switch(_.isString(t.operation)&&SqlOperationType[t.operation]&&(t.operation=SqlOperationType[t.operation]),t.operation){case SqlOperationType.IN:case SqlOperationType.NOT_IN:const e=new Array(t.value.length);e.fill("?"),r=t.operation+" ("+e.join(", ")+")",s.values=_.concat(s.values,t.value);break;case SqlOperationType.IS_NULL:case SqlOperationType.IS_NOT_NULL:r=t.operation;break;case SqlOperationType.LITERAL:a=t.key;const i=t.literalOperation||SqlOperationType.EQ;if(i==SqlOperationType.IN||i==SqlOperationType.NOT_IN){const e=new Array(t.value.length);e.fill("?"),r=i+" ("+e.join(", ")+")",s.values=_.concat(s.values,t.value)}else _.isUndefined(t.value)?r=i:(r=i+" ?",s.values.push(this.makeDbValue(t.value)));n=!1;break;default:r=t.operation+" ?",s.values.push(this.makeDbValue(t.value))}}else null===e?r=SqlOperationType.IS_NULL:void 0===e?(a="1",r="= 1",n=!1):(r=_.isString(e)&&e.match(/[%_]/)?SqlOperationType.LIKE+" ?":SqlOperationType.EQ+" ?",s.values.push(this.makeDbValue(e)));return i=n?this.translateFieldName(t,a)+" "+r:a+" "+r,i}})).join(" "+r+" ")),s}buildDeleteStatement(t,e){const r=this.getTableName(t),s=new SmartDbSqlBuildData("DELETE FROM");return s.sql+=" "+r,e&&s.append(this.buildWhere(t,e)),this.lastBuildData=s,s}buildUpdateStatement(t,e,r){const s=this.getTableName(t),a=new SmartDbSqlBuildData("UPDATE");a.sql+=" "+s+" SET ";const i=[],n=e instanceof AbstractModel?e.getPlainObject(FieldNamingStyle.Database):e;return _.forOwn(n,((e,r)=>{i.push(this.translateFieldName(t,r)+" = ?"),a.values.push(this.makeDbValue(e))})),a.sql+=i.join(", "),r&&a.append(this.buildWhere(t,r)),this.lastBuildData=a,a}buildInsertStatement(t,e){const r=this.getTableName(t),s=new SmartDbSqlBuildData("INSERT");s.sql+=" INTO "+r;const a=[];e instanceof AbstractModel&&(e=e.getPlainObject(FieldNamingStyle.Database)),_.forOwn(e,((e,r)=>{r=this.translateFieldName(t,r),a.push(r),s.values.push(this.makeDbValue(e))}));const i=new Array(a.length);return i.fill("?"),s.sql+=" ("+a.join(", ")+") VALUES ("+i.join(", ")+")",this.lastBuildData=s,s}prepareFieldValue(t,e){let r="<undefined>";switch(e.operation){case SqlFieldOperationType.FIELD:r=this.translateFieldName(t,e.value);break;case SqlFieldOperationType.VALUE:null===e.value?r="NULL":e.literal?r=e.value:_.isString(e.value)?!isNaN(parseFloat(e.value))&&isFinite(e.value)||(r="'"+e.value+"'"):_.isNumber(e.value)?r=e.value.toString():_.isBoolean(e.value)?r=e.value?"1":"0":_.isDate(e.value)?r="'"+e.value.toISOString().substr(0,23).replace("T"," ")+"'":console.error("unhandled field data type",typeof e.value,e.value);break;case SqlFieldOperationType.COUNT:r=_.isArray(e.value)?"COUNT("+e.value.join(",")+")":"COUNT("+(e.value||"")+")";break;case SqlFieldOperationType.COALESCE:const s=_.isArray(e.value)?e.value:[e.value];r="COALESCE("+this.buildFieldList(t,s).join(",")+")"}if(e.alias){const t=this.getDbQuote();r+=` as ${t}${e.alias}${t}`}return r}prepareField(t,e,r){let s;if(null===e)s="NULL";else if(_.isString(e)){const a=e.match(/^'(.*)'$/);a?r?(s="?",r.push(a[1])):s=e:s=this.translateFieldName(t,e)}else e.operation?s=this.prepareFieldValue(t,e):r?(s="?",r.push(e)):s=this.makeArgumentDbValue(e).toString();return s}buildFieldList(t,e){const r=[];return _.forEach(e,(e=>{r.push(this.prepareField(t,e))})),r}buildSelectSectionStatement(t,e){const r=this.getTableName(t);let s,a;if(_.isArray(e.fields))s=e.fields;else if(_.isString(e.fields)){const t=e.fields.trim();s=""===t||"*"==t?[]:t.split(/,/)}else s=e.fields&&e.fields.operation?[e.fields]:[];if(s.length>0){a=this.buildFieldList(t,s).join(", ")}else a="*";e.distinct&&(a="DISTINCT "+a),e.count&&(a=`COUNT(${a})`);const i=new SmartDbSqlBuildData(`SELECT ${a} FROM ${r}`);if(e.where&&i.append(this.buildWhere(t,e.where)),e.groupBy){i.sql+=" GROUP BY ";const r=_.isArray(e.groupBy)?e.groupBy:[e.groupBy];i.sql+=r.map((e=>this.translateFieldName(t,e))).join(", ")}return i}translateFieldName(t,e){if(_.isString(t)){const e=t;let r=!1;_.forEach(this.dictionaries,(s=>(s.models&&s.models[e]&&(t=s.models[e].cls,r=!0),!r)))}if(!_.isString(t)){const r=t.attributeMap[e];if(r)r.alias&&(e=r.alias);else{const r=t.getTableName();this.lastError=new Error(`unknown field '${e}' in table '${r}'`),this.smartDbLog.logError(SmartDbLogLocation.Database,"translateFieldName",this.lastError)}}return e}makeDbValue(t){return _.isBoolean(t)?t=t?1:0:_.isDate(t)&&(t=toSmartDbDate(t)),t}makeArgumentDbValue(t){return _.isBoolean(t)?t=t?1:0:_.isDate(t)?t=`'${toSmartDbDate(t)}'`:_.isString(t)&&(t=`'${t.replace(/'/,"''").replace(/\\/,"\\\\")}'`),t}saveExecute(t){let e;try{e=t()}catch(t){this.lastError=t instanceof Error?t:new Error(t||"Unknown error"),this.smartDbLog.logFatal(SmartDbLogLocation.Database,"saveExecute-catch",this.lastError),e=!1}return e}scriptParser(t){const e=fs.readFileSync(t,"utf8"),r=[];let s=0,a=0,i=!1,n=0,l=!1,o="";for(;a<e.length;){if(l){if("\n"==e[a])for(l=!1,s=a+1;" "==e[s]||"\n"==e[s]||"\n"==e[s];)s+=1}else"'"==e[a]?i=!i:!i&&e.substring(a,a+6).match(/^begin(\s|\n)/)?(n+=1,a+=6):n>0&&!i&&e.substring(a,a+4).match(/^end;/)?(n-=1,a+=4):0!==n||i||"/"!=e[a]?i||"-"!=e[a]||"-"!=e[a+1]?0!==n||i||";"!=e[a]||(r.push((o+e.substring(s,a)).trim()),o="",s=a+2):(o+=e.substring(s,a),l=!0):(r.push((o+e.substring(s,a)).trim()),o="",s=a+2);a+=1}if(s<e.length){const t=e.substring(s,e.length).trim().replace(/;$/,"");console.log(t),""!==t&&r.push(t)}return r}prepareResultRow(t,e,r){let s;if(r.indexedBy&&this.smartDbLog.logWarning(SmartDbLogLocation.Database,"AbstractModel.get","option 'indexedBy' not supported without 'all'"),e)if(r.count)s=parseInt(_.values(e)[0],10);else if(r.collapseRow)s=_.values(e).join(",");else{const a=t.from(e);s=r.style==FieldNamingStyle.TypeScript?a.getPlainObject():a}return s}prepareResultRows(t,e,r){let s;if(!e||!r.indexedBy&&!r.collapseRow&&_.isString(t))s=e;else{const a=t;s=r.indexedBy?{}:new Array(e.length),_.forEach(e,((t,e)=>{let i=a.from?a.from(t):null,n=null;if(r.indexedBy&&(n=i?i.getValue(r.indexedBy):t[r.indexedBy]),r.collapseRow){const r=_.values(t).join(",");n?s[n]=r:s[e]=r}else i&&r.style==FieldNamingStyle.TypeScript&&(i=i.getPlainObject()),n?s[n]=i||t:s[e]=i||t}))}return s}getTableName(t){let e;if(_.isString(t)){let r=t;_.forEach(this.dictionaries,(t=>(t.models&&t.models[r]&&(e=t.models[r].cls.getTableName()),!e))),e||(e=r)}else{if(!t||!t.getTableName)throw new Error(`unknown model: ${t}`);e=t.getTableName()}return e}get isReady(){return this._isReady}set isReady(t){this._isReady=t,this._onReady.next(t)}get supportSyncCalls(){return!1}}
|
|
1
|
+
import fs from"fs";import _ from"lodash";import{BehaviorSubject}from"rxjs";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}from"./smart-db-log";import{SmartDbSqlBuildData}from"./smart-db-sql-build-data";import{SmartDbUpgradeManager}from"./smart-db-upgrade-manager";import{SmartError,SmartErrorLocation}from"./smart-error";export class SmartDb{constructor(t,e){this.dictionaries=[],this.dbConnector=t,this.smartDbLog=new SmartDbLog(e?null:this),this.dbLogging=!e,this.db=null,this._isReady=null,this._onReady=new BehaviorSubject(!1)}buildSelectStatement(t,e){e||(e={});const r=this.buildSelectSectionStatement(t,e);if(_.forEach(["union","minus","intersect"],(t=>{let s=_.get(e,t);s&&(_.isArray(s)||(s=[s]),_.forEach(s,(e=>{const s=this.buildSelectSectionStatement(e.model,e);r.sql+=" "+t.toUpperCase()+" ",r.append(s)})))})),e.orderBy){r.sql+=" ORDER BY ";const s=_.isString(e.orderBy)?e.orderBy.split(/ *, */):e.orderBy;r.sql+=s.map((e=>{let r="";const s=e.match(/^(\w*) (asc|desc)$/i);return s&&(e=s[1],r=s[2].toUpperCase()),e=this.translateFieldName(t,e),r&&(e+=" "+r),e})).join(", ")}return e.limit&&(e.limit.limit&&(r.sql+=" LIMIT "+e.limit.limit.toString()),e.limit.offset&&(r.sql+=" OFFSET "+e.limit.offset.toString())),this.lastBuildData=r,r}close(){return new Promise(((t,e)=>{try{t(this.closeSync())}catch(t){e(t)}}))}closeSync(){throw new Error("Method not implemented (close)")}commit(){return new Promise(((t,e)=>{try{this.commitSync(),t()}catch(t){e(t)}}))}commitSync(){throw new Error("Method not implemented (commit)")}delete(t,e){return new Promise(((r,s)=>{const a=this.buildDeleteStatement(t,e);this.statementRun(a).then((t=>{t?r(t.changes):s(this.getLastError())})).catch((t=>{this.lastError=t,s(t)}))}))}deleteSync(t,e){if(this.supportSyncCalls)return this.saveExecute((()=>{const r=this.buildDeleteStatement(t,e);return this.statementRunSync(r).changes}));throw"This database driver doesn't support sync calls (deleteSync)"}exec(t){return new Promise(((e,r)=>{try{this.execSync(t)?e():r(this.getLastError())}catch(t){r(t)}}))}execScript(t,e){return new Promise((async(r,s)=>{const a=this.scriptParser(t);let i=!1;for(const t of a)try{await this.exec(t)}catch(r){if(!e||"drop "!=t.trim().substring(0,5).toLowerCase()){i=!0,this.lastBuildData=new SmartDbSqlBuildData(t),this.lastError=r;break}}i?(await this.rollback(),s(this.lastError)):(await this.commit(),r())}))}execScriptSync(t){if(!this.supportSyncCalls)throw"This database driver doesn't support sync calls (execScriptSync)";{const e=this.scriptParser(t);for(const t of e)try{this.execSync(t)}catch(e){if("drop "!=t.substring(0,5).toLowerCase())throw this.lastBuildData=new SmartDbSqlBuildData(t),this.lastError=e,e}this.commitSync()}}execSync(t){throw new Error("Method not implemented (exec)")}exists(t,e,r){return new Promise(((s,a)=>{try{s(this.existsSync(t,e,r))}catch(t){a(t)}}))}existsSync(t,e,r){throw new Error("Method not implemented (exists)")}get(t,e){return new Promise(((r,s)=>{e||(e={});const a=this.buildSelectStatement(t,e);e.firstOnly||e.count?this.statementGet(a).then((s=>{r(this.prepareResultRow(t,s,e))})).catch((t=>{s(t)})):this.statementGetAll(a).then((s=>{r(this.prepareResultRows(t,s,e))})).catch((t=>{s(t)}))}))}getAll(t,e,r,s,a){return this.get(t,{where:e,fields:r,orderBy:s,limit:a})}getAllSync(t,e,r,s,a){return this.getSync(t,{where:e,fields:r,orderBy:s,limit:a})}getDb(){return this.db}getDbConnector(){return this.dbConnector}getDbQuote(){return'"'}getFirst(t,e,r,s){return this.get(t,{firstOnly:!0,where:e,fields:r,orderBy:s})}getFirstSync(t,e,r,s){return this.getSync(t,{firstOnly:!0,where:e,fields:r,orderBy:s})}getLastBuildData(){return this.lastBuildData}getLastError(){return this.lastError}getLogger(){return this.smartDbLog}getSync(t,e){if(this.supportSyncCalls)return this.saveExecute((()=>{e||(e={});const r=this.buildSelectStatement(t,e);let s;if(e.firstOnly||e.count){const a=this.statementGetSync(r);s=this.prepareResultRow(t,a,e)}else{const a=this.statementGetAllSync(r);s=this.prepareResultRows(t,a,e)}return s}));throw"This database driver doesn't support sync calls (getSync)"}hasConcurrentTransactions(){return!1}hasTransaction(){throw new Error("Method not implemented (hasTransaction)")}initDb(t){return new Promise(((e,r)=>{this.dictionaries.push(SmartDbDictionary);const s=new SmartDbUpgradeManager(this);let a;a=import.meta&&import.meta.url?import.meta.url.replace(/file:\/\//,"").replace(/\/[^/]*$/,""):__dirname;const i={module:"smart-db-core",sqlFilesDirectory:a+"/assets/"+this.getDatabaseType()};s.prepareDatabase(i).then((a=>{this.exists(SmartDbLogModel).then((i=>{this.smartDbLog.setDbLogging(this.dbLogging&&i),s.prepareDatabase(t).then((t=>{e([a,t])}),(t=>{r(t)}))}))})).catch((t=>{r(t)}))}))}insert(t,e){return new Promise(((r,s)=>{const a=this.buildInsertStatement(t,e);this.statementRun(a).then((t=>{t?r(t.lastId):s(this.getLastError())})).catch((t=>{s(t)}))}))}insertSync(t,e){if(this.supportSyncCalls)return this.saveExecute((()=>{const r=this.buildInsertStatement(t,e);return this.statementRunSync(r).lastId}));throw"This database driver doesn't support sync calls (insertSync)"}onReady(){return this._onReady}rollback(){return new Promise(((t,e)=>{try{this.rollbackSync(),t()}catch(t){e(t)}}))}rollbackSync(){throw new Error("Method not implemented (rollback)")}toDate(t){return smartDbToDate(t)}toDbDate(t){return toSmartDbDate(t)}toDbTimestamp(t){return toSmartDbTimestamp(t)}update(t,e,r){return new Promise(((s,a)=>{const i=this.buildUpdateStatement(t,e,r);this.statementRun(i).then((t=>{t?s(t.changes):a(this.getLastError())})).catch((t=>{a(t)}))}))}updateSync(t,e,r){if(this.supportSyncCalls)return this.saveExecute((()=>{const s=this.buildUpdateStatement(t,e,r);return this.statementRunSync(s).changes}));throw"This database driver doesn't support sync calls (updateSync)"}statementRun(t){return new Promise(((e,r)=>{try{e(this.statementRun(t))}catch(t){r(t)}}))}statementRunSync(t){throw new Error("Method not implemented (statementRun)")}statementGet(t){return new Promise(((e,r)=>{try{e(this.statementGetSync(t))}catch(t){r(t)}}))}statementGetSync(t){throw new Error("Method not implemented (statementGet)")}statementGetAll(t){return new Promise(((e,r)=>{try{e(this.statementGetAllSync(t))}catch(t){r(t)}}))}statementGetAllSync(t){throw new Error("Method not implemented (statementGetAll)")}buildWhere(t,e,r){const s=new SmartDbSqlBuildData;return e&&_.keys(e).length>0&&(r||(r="AND",s.sql+=" WHERE "),s.sql+=_.map(e,((e,a)=>{const i=a.toUpperCase();if("AND"==i||"OR"==i){let r="";return(_.isArray(e)?e:[e]).forEach(((e,a)=>{const n=this.buildWhere(t,e,i);a>0&&(r+=" "+i+" "),r+=n.sql,s.values=_.concat(s.values,n.values)})),r="("+r+")",r}if("EXPRESSION"==i){let a=[];return _.forEach(e,(e=>{const r=this.prepareField(t,e.compare,s.values),i=this.prepareField(t,e.with,s.values);let n;n=_.isString(e.operation)&&SqlOperationType[e.operation]?SqlOperationType[e.operation]:e.operation||SqlOperationType.EQ,a.push(`${r} ${n} ${i}`)})),a.join(" "+r+" ")}{let r,i,n=!0;if(_.isArray(e)&&(e=IN(e)),_.isObject(e)){const t=e;switch(_.isString(t.operation)&&SqlOperationType[t.operation]&&(t.operation=SqlOperationType[t.operation]),t.operation){case SqlOperationType.IN:case SqlOperationType.NOT_IN:const e=new Array(t.value.length);e.fill("?"),r=t.operation+" ("+e.join(", ")+")",s.values=_.concat(s.values,t.value);break;case SqlOperationType.IS_NULL:case SqlOperationType.IS_NOT_NULL:r=t.operation;break;case SqlOperationType.LITERAL:a=t.key;const i=t.literalOperation||SqlOperationType.EQ;if(i==SqlOperationType.IN||i==SqlOperationType.NOT_IN){const e=new Array(t.value.length);e.fill("?"),r=i+" ("+e.join(", ")+")",s.values=_.concat(s.values,t.value)}else _.isUndefined(t.value)?r=i:(r=i+" ?",s.values.push(this.makeDbValue(t.value)));n=!1;break;default:r=t.operation+" ?",s.values.push(this.makeDbValue(t.value))}}else null===e?r=SqlOperationType.IS_NULL:void 0===e?(a="1",r="= 1",n=!1):(r=_.isString(e)&&e.match(/[%_]/)?SqlOperationType.LIKE+" ?":SqlOperationType.EQ+" ?",s.values.push(this.makeDbValue(e)));return i=n?this.translateFieldName(t,a)+" "+r:a+" "+r,i}})).join(" "+r+" ")),s}buildDeleteStatement(t,e){const r=this.getTableName(t),s=new SmartDbSqlBuildData("DELETE FROM");return s.sql+=" "+r,e&&s.append(this.buildWhere(t,e)),this.lastBuildData=s,s}buildUpdateStatement(t,e,r){const s=this.getTableName(t),a=new SmartDbSqlBuildData("UPDATE");a.sql+=" "+s+" SET ";const i=[],n=e instanceof AbstractModel?e.getPlainObject(FieldNamingStyle.Database):e;return _.forOwn(n,((e,r)=>{i.push(this.translateFieldName(t,r)+" = ?"),a.values.push(this.makeDbValue(e))})),a.sql+=i.join(", "),r&&a.append(this.buildWhere(t,r)),this.lastBuildData=a,a}buildInsertStatement(t,e){const r=this.getTableName(t),s=new SmartDbSqlBuildData("INSERT");s.sql+=" INTO "+r;const a=[];e instanceof AbstractModel&&(e=e.getPlainObject(FieldNamingStyle.Database)),_.forOwn(e,((e,r)=>{r=this.translateFieldName(t,r),a.push(r),s.values.push(this.makeDbValue(e))}));const i=new Array(a.length);return i.fill("?"),s.sql+=" ("+a.join(", ")+") VALUES ("+i.join(", ")+")",this.lastBuildData=s,s}prepareFieldValue(t,e){let r="<undefined>";switch(e.operation){case SqlFieldOperationType.FIELD:r=this.translateFieldName(t,e.value);break;case SqlFieldOperationType.VALUE:null===e.value?r="NULL":e.literal?r=e.value:_.isString(e.value)?!isNaN(parseFloat(e.value))&&isFinite(e.value)||(r="'"+e.value+"'"):_.isNumber(e.value)?r=e.value.toString():_.isBoolean(e.value)?r=e.value?"1":"0":_.isDate(e.value)?r="'"+e.value.toISOString().substring(0,23).replace("T"," ")+"'":console.error("unhandled field data type",typeof e.value,e.value);break;case SqlFieldOperationType.COUNT:r=_.isArray(e.value)?"COUNT("+e.value.join(",")+")":"COUNT("+(e.value||"")+")";break;case SqlFieldOperationType.COALESCE:const s=_.isArray(e.value)?e.value:[e.value];r="COALESCE("+this.buildFieldList(t,s).join(",")+")"}if(e.alias){const t=this.getDbQuote();r+=` as ${t}${e.alias}${t}`}return r}prepareField(t,e,r){let s;if(null===e)s="NULL";else if(_.isString(e)){const a=e.match(/^'(.*)'$/);a?r?(s="?",r.push(a[1])):s=e:s=this.translateFieldName(t,e)}else e.operation?s=this.prepareFieldValue(t,e):r?(s="?",r.push(e)):s=this.makeArgumentDbValue(e).toString();return s}buildFieldList(t,e){const r=[];return _.forEach(e,(e=>{r.push(this.prepareField(t,e))})),r}buildSelectSectionStatement(t,e){const r=this.getTableName(t);let s,a;if(_.isArray(e.fields))s=e.fields;else if(_.isString(e.fields)){const t=e.fields.trim();s=""===t||"*"==t?[]:t.split(/,/)}else s=e.fields&&e.fields.operation?[e.fields]:[];if(s.length>0){a=this.buildFieldList(t,s).join(", ")}else a="*";e.distinct&&(a="DISTINCT "+a),e.count&&(a=`COUNT(${a})`);const i=new SmartDbSqlBuildData(`SELECT ${a} FROM ${r}`);if(e.where&&i.append(this.buildWhere(t,e.where)),e.groupBy){i.sql+=" GROUP BY ";const r=_.isArray(e.groupBy)?e.groupBy:[e.groupBy];i.sql+=r.map((e=>this.translateFieldName(t,e))).join(", ")}return i}translateFieldName(t,e){if(_.isString(t)){const e=t;let r=!1;_.forEach(this.dictionaries,(s=>(s.models&&s.models[e]&&(t=s.models[e].cls,r=!0),!r)))}if(!_.isString(t)){const r=t.attributeMap[e];if(r)r.alias&&(e=r.alias);else{const r=t.getTableName();this.lastError=new Error(`unknown field '${e}' in table '${r}'`),this.smartDbLog.logError(SmartErrorLocation.Database,"translateFieldName",this.lastError)}}return e}makeDbValue(t){return _.isBoolean(t)?t=t?1:0:_.isDate(t)&&(t=toSmartDbDate(t)),t}makeArgumentDbValue(t){return _.isBoolean(t)?t=t?1:0:_.isDate(t)?t=`'${toSmartDbDate(t)}'`:_.isString(t)&&(t=`'${t.replace(/'/,"''").replace(/\\/,"\\\\")}'`),t}saveExecute(t){let e;try{e=t()}catch(t){this.lastError=t instanceof Error?t:new Error(t||"Unknown error"),this.smartDbLog.logFatal(SmartErrorLocation.Database,"saveExecute-catch",this.lastError),e=!1}return e}scriptParser(t){const e=fs.readFileSync(t,"utf8"),r=[];let s=0,a=0,i=!1,n=0,l=!1,o="";for(;a<e.length;){if(l){if("\n"==e[a])for(l=!1,s=a+1;" "==e[s]||"\n"==e[s]||"\n"==e[s];)s+=1}else"'"==e[a]?i=!i:!i&&e.substring(a,a+6).match(/^begin(\s|\n)/)?(n+=1,a+=6):n>0&&!i&&e.substring(a,a+4).match(/^end;/)?(n-=1,a+=4):0!==n||i||"/"!=e[a]?i||"-"!=e[a]||"-"!=e[a+1]?0!==n||i||";"!=e[a]||(r.push((o+e.substring(s,a)).trim()),o="",s=a+2):(o+=e.substring(s,a),l=!0):(r.push((o+e.substring(s,a)).trim()),o="",s=a+2);a+=1}if(s<e.length){const t=e.substring(s,e.length).trim().replace(/;$/,"");console.log(t),""!==t&&r.push(t)}return r}prepareResultRow(t,e,r){let s;if(r.indexedBy&&this.smartDbLog.logWarning(SmartErrorLocation.Database,"AbstractModel.get","option 'indexedBy' not supported without 'all'"),e)if(r.count)s=parseInt(_.values(e)[0],10);else if(r.collapseRow)s=_.values(e).join(",");else{const a=t.from(e);s=r.style==FieldNamingStyle.TypeScript?a.getPlainObject():a}return s}prepareResultRows(t,e,r){let s;if(!e||!r.indexedBy&&!r.collapseRow&&_.isString(t))s=e;else{const a=t;s=r.indexedBy?{}:new Array(e.length),_.forEach(e,((t,e)=>{let i=a.from?a.from(t):null,n=null;if(r.indexedBy&&(n=i?i.getValue(r.indexedBy):t[r.indexedBy]),r.collapseRow){const r=_.values(t).join(",");n?s[n]=r:s[e]=r}else i&&r.style==FieldNamingStyle.TypeScript&&(i=i.getPlainObject()),n?s[n]=i||t:s[e]=i||t}))}return s}getTableName(t){let e;if(_.isString(t)){let r=t;_.forEach(this.dictionaries,(t=>(t.models&&t.models[r]&&(e=t.models[r].cls.getTableName()),!e))),e||(e=r)}else{if(!t||!t.getTableName)throw new Error(`unknown model: ${t}`);e=t.getTableName()}return e}get isReady(){return this._isReady}set isReady(t){this._isReady=t,this._onReady.next(t)}get lastError(){return this._lastError}set lastError(t){this._lastError=new SmartError(t),this._lastError.location=SmartErrorLocation.Database}get supportSyncCalls(){return!1}}
|
package/smart-error.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare const SmartErrorLocation: {
|
|
2
|
+
App: SmartErrorLocationValue;
|
|
3
|
+
Frontend: SmartErrorLocationValue;
|
|
4
|
+
Backend: SmartErrorLocationValue;
|
|
5
|
+
Database: SmartErrorLocationValue;
|
|
6
|
+
UpgradeManager: SmartErrorLocationValue;
|
|
7
|
+
};
|
|
8
|
+
export declare type SmartErrorLocationType = typeof SmartErrorLocation;
|
|
9
|
+
export declare type SmartErrorLocationKey = keyof SmartErrorLocationType;
|
|
10
|
+
export declare type SmartErrorLocationValue = "APP" | "FRONTEND" | "BACKEND" | "DATABASE" | "UPGRADE-MANAGER";
|
|
11
|
+
export declare const SmartErrorSeverity: {
|
|
12
|
+
readonly Fatal: SmartErrorSeverityValue;
|
|
13
|
+
readonly Error: SmartErrorSeverityValue;
|
|
14
|
+
readonly Warning: SmartErrorSeverityValue;
|
|
15
|
+
readonly Info: SmartErrorSeverityValue;
|
|
16
|
+
readonly Debug: SmartErrorSeverityValue;
|
|
17
|
+
readonly Local: SmartErrorSeverityValue;
|
|
18
|
+
};
|
|
19
|
+
export declare type SmartErrorSeverityType = typeof SmartErrorSeverity;
|
|
20
|
+
export declare type SmartErrorSeverityKey = keyof SmartErrorSeverityType;
|
|
21
|
+
export declare type SmartErrorSeverityValue = "F" | "E" | "W" | "I" | "D" | "L";
|
|
22
|
+
export interface SmartErrorData {
|
|
23
|
+
message: string;
|
|
24
|
+
name: string;
|
|
25
|
+
code?: number | string;
|
|
26
|
+
type?: SmartErrorSeverityValue;
|
|
27
|
+
location?: SmartErrorLocationValue;
|
|
28
|
+
timestamp?: Date | string | number;
|
|
29
|
+
info?: Record<string, any>;
|
|
30
|
+
}
|
|
31
|
+
export declare class SmartError extends Error implements SmartErrorData {
|
|
32
|
+
code: number | string;
|
|
33
|
+
type: SmartErrorSeverityValue;
|
|
34
|
+
location: SmartErrorLocationValue;
|
|
35
|
+
timestamp: Date | string | number;
|
|
36
|
+
info: Record<string, any>;
|
|
37
|
+
private smartErrorKeys;
|
|
38
|
+
constructor(message: any);
|
|
39
|
+
toObject(): SmartErrorData;
|
|
40
|
+
toString(): string;
|
|
41
|
+
}
|
package/smart-error.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const SmartErrorLocation={App:"APP",Frontend:"FRONTEND",Backend:"BACKEND",Database:"DATABASE",UpgradeManager:"UPGRADE-MANAGER"};export const SmartErrorSeverity={Fatal:"F",Error:"E",Warning:"W",Info:"I",Debug:"D",Local:"L"};export class SmartError extends Error{constructor(t){let e,r,s,o,i,n,a;if(void 0===t||"string"==typeof t)e=t;else if("object"==typeof t){if(e="string"==typeof t.message?t.message:"string"==typeof t.text?t.text:"string"==typeof t.error?t.error:"Error",i=t.name,r=t.code,s=t.type,o=t.location,n=t.timestamp,!t.constructor){const e=Object.keys(t).filter((t=>!this.smartErrorKeys.includes(t)));e.length>0&&(a={},e.forEach((e=>{a[e]=t[e]})))}}else e="function"==typeof t.toString?t.toString():t;super(e),this.name=i??"",this.code=r??-1,this.type&&(this.type=s??"E"),o&&(this.location=o),n&&(this.timestamp=n),a&&(this.info=a),this.smartErrorKeys=["message","name","code","type","location","timestamp","info"]}toObject(){const t={name:this.name,message:this.message};return this.smartErrorKeys.forEach((e=>{"name"!=e&&"message"!=e&&this[e]&&(t[e]=this[e])})),t}toString(){let t=super.toString(),e="";return this.type&&(e+=this.type),this.location&&(""!==e&&(e+="-"),e+=this.location),this.code&&(""!==e&&(e+=" #"),e+=this.code),t+" ("+e+")"}}
|