databaseHelper.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. const sqlite3 = require('sqlite3');
  2. const CONFIG = require('./config.js');
  3. const PasteContentModel = require('../models/pasteContent.js').PasteContent;
  4. const ApiKeyModel = require('../models/apiKey.js').ApiKeyModel;
  5. const AccessModel = require('../models/access.js').AccessModel;
  6. const OriginModel = require('../models/origin.js').OriginModel;
  7. function DatabaseHelper() {
  8. this.db = null;
  9. }
  10. DatabaseHelper.prototype.init = function() {
  11. return new Promise((ok, ko) => {
  12. this.db = new sqlite3.Database(CONFIG.database, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE | sqlite3.OPEN_FULLMUTEX, async (err) => {
  13. if (err) {
  14. ko(err);
  15. return;
  16. }
  17. let types = [ PasteContentModel, ApiKeyModel, AccessModel, OriginModel ];
  18. for (let i =0; i < types.length; ++i) {
  19. let instance = new types[i]();
  20. await instance.createOrUpdateBase(this);
  21. }
  22. await this.runSql("PRAGMA foreign_key=1");
  23. console.log("Database is ready");
  24. ok();
  25. });
  26. });
  27. }
  28. DatabaseHelper.prototype.runSql = function(sqlStatement, args) {
  29. console.log("DatabaseHelper::runSql ", sqlStatement, args);
  30. return new Promise((ok, ko) => {
  31. if (sqlStatement.indexOf('--') >= 0) {
  32. console.error("Rejecting SQL request containing comments");
  33. ko("SQL Comment Error");
  34. return;
  35. }
  36. try {
  37. this.db.all(sqlStatement, args, (err, data) => {
  38. if (err) {
  39. console.error(err);
  40. ko(err);
  41. } else {
  42. ok(data);
  43. }
  44. });
  45. } catch (err) {
  46. console.error(err);
  47. ko(err);
  48. }
  49. });
  50. }
  51. DatabaseHelper.prototype.insertOne = async function(object) {
  52. let columns = [];
  53. let args = [];
  54. for (let [key, val] of Object.entries(object.describe())) {
  55. columns.push("`"+key+"`");
  56. args.push(val);
  57. }
  58. let request = "insert into `" +object.getTableName()
  59. +"` (" +columns.join(", ")
  60. +") VALUES (" +columns.map(i => "?").join(",")+")";
  61. await this.runSql(request, args);
  62. }
  63. DatabaseHelper.prototype.count = async function(objectPrototype, where) {
  64. let whereArgs = this.buildWhere(where);
  65. let query = "select count(*) as c from `" +objectPrototype.prototype.getTableName.call(null) +"` where " +whereArgs.columns.join(" and ");
  66. let result = await this.runSql(query, whereArgs.args);
  67. let resultArr = [];
  68. for (let i of result)
  69. return i.c;
  70. return 0;
  71. }
  72. DatabaseHelper.prototype.upsertOne = async function(obj) {
  73. let columns = [];
  74. let columnsVal = [];
  75. let args = [];
  76. let i =0;
  77. for (let [key, val] of Object.entries(obj.describe())) {
  78. columns.push("`"+key+"`");
  79. columnsVal.push("`"+key+"`=:"+(i++));
  80. args.push(val);
  81. }
  82. let request = "insert into `" +obj.getTableName()
  83. +"` (" +columns.join(", ")
  84. +") VALUES (" +columns.map((_, i) => `:${i}`).join(",")+")"
  85. +" ON CONFLICT DO UPDATE SET " +columnsVal.join(", ");
  86. await this.runSql(request, args);
  87. }
  88. DatabaseHelper.prototype.buildWhere = function(whereObj, columns, args) {
  89. columns = columns || [];
  90. args = args || [];
  91. if (!whereObj) {
  92. columns.push("1=1");
  93. } else {
  94. for (let [key, val] of Object.entries(whereObj)) {
  95. if (val === null) {
  96. columns.push("`"+key+"` is null");
  97. } else {
  98. columns.push("`"+key+"`=?");
  99. args.push(val);
  100. }
  101. }
  102. }
  103. return {
  104. columns: columns,
  105. args: args
  106. };
  107. }
  108. DatabaseHelper.prototype.maxVersion = async function(instanceName) {
  109. let queryParts = [];
  110. for (let i of [ SessionModel, ArchiveModel, TaskModel ])
  111. queryParts.push("select max(" +i.prototype.versionColumn.call(null) +") as v from " +i.prototype.getTableName.call(null) +" where instance=:0");
  112. let version = await this.runSql("select max(v) as v from (" +queryParts.join(" union ") +")", [ instanceName ]);
  113. return (version?.[0]?.v) || 0;
  114. }
  115. DatabaseHelper.prototype.versionFetch = async function(objectPrototype, minVersion) {
  116. let query = "select * from `" +objectPrototype.prototype.getTableName.call(null) +"` where `" +objectPrototype.prototype.versionColumn.call(null)+"` > ? and instance=?";
  117. let result = [];
  118. for (let i of await this.runSql(query, [minVersion, CONFIG.instanceHostname]))
  119. {
  120. let resultObj = new objectPrototype();
  121. resultObj.fromDb(i);
  122. result.push(resultObj);
  123. }
  124. return result;
  125. }
  126. DatabaseHelper.prototype.fetch = async function(objectPrototype, where, orderBy) {
  127. let whereArgs = this.buildWhere(where);
  128. let query = "select * from `" +objectPrototype.prototype.getTableName.call(null) +"` where " +whereArgs.columns.join(" and ");
  129. if (orderBy)
  130. query += " ORDER BY " +Object.keys(orderBy || {}).map(i => "`"+i+"` " +(orderBy[i] === 'DESC' ? "DESC":"ASC")).join(",");
  131. let result = await this.runSql(query, whereArgs.args);
  132. let resultArr = [];
  133. for (let i of result)
  134. {
  135. let resultObj = new objectPrototype();
  136. resultObj.fromDb(i);
  137. resultArr.push(resultObj);
  138. }
  139. return resultArr;
  140. }
  141. DatabaseHelper.prototype.rawFetch = async function(objectPrototype, where) {
  142. let query = "select * from `" +objectPrototype.prototype.getTableName.call(null) +"` where " +where;
  143. let result = await this.runSql(query);
  144. let resultArr = [];
  145. for (let i of result)
  146. {
  147. let resultObj = new objectPrototype();
  148. resultObj.fromDb(i);
  149. resultArr.push(resultObj);
  150. }
  151. return resultArr;
  152. }
  153. DatabaseHelper.prototype.findOne = async function(objectPrototype, where, whereSeparator) {
  154. let whereArgs = this.buildWhere(where);
  155. whereSeparator = whereSeparator || " and ";
  156. let result = await this.runSql("select * from `" +objectPrototype.prototype.getTableName.call(null) +"` where " +whereArgs.columns.join(whereSeparator), whereArgs.args);
  157. if (result && result.length)
  158. {
  159. let resultObj = new objectPrototype();
  160. resultObj.fromDb(result[0]);
  161. return resultObj;
  162. }
  163. return null;
  164. }
  165. DatabaseHelper.prototype.update = async function(where, object) {
  166. if (object.lastUpdated)
  167. object.lastUpdated = new Date();
  168. await this.rawUpdate(object, where, object.describe());
  169. }
  170. DatabaseHelper.prototype.rawUpdate = async function(model, where, values) {
  171. let columns = [];
  172. let args = [];
  173. for (let [key, val] of Object.entries(values)) {
  174. columns.push("`"+key+"`=?");
  175. args.push(val);
  176. }
  177. let whereArgs = this.buildWhere(where, [], args);
  178. let query = "update `" +(model.prototype?.getTableName ? model.prototype.getTableName() : model.getTableName())
  179. +"` set " +columns.join(", ")
  180. +" WHERE " +whereArgs.columns.join(" and ");
  181. await this.runSql(query, args);
  182. }
  183. module.exports.DatabaseHelper = new DatabaseHelper();