db.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import { DatabaseSync } from "node:sqlite";
  2. function getDbPath(): string {
  3. return Deno.env.get("POSTDOWN_DB_PATH") || "data/postdown.db";
  4. }
  5. function prepareDB(tableName: string, dbPath?: string) {
  6. const db = new DatabaseSync(dbPath || getDbPath());
  7. switch (tableName) {
  8. case "User":
  9. db.exec(`
  10. CREATE TABLE IF NOT EXISTS user (
  11. id INTEGER PRIMARY KEY AUTOINCREMENT,
  12. name VARCHAR(128),
  13. email VARCHAR(128),
  14. password TEXT,
  15. created DATETIME DEFAULT CURRENT_TIMESTAMP,
  16. updated DATETIME,
  17. UNIQUE(name)
  18. )
  19. `);
  20. break;
  21. case "Token":
  22. db.exec(`
  23. CREATE TABLE IF NOT EXISTS token (
  24. id INTEGER PRIMARY KEY AUTOINCREMENT,
  25. user_id INTEGER,
  26. token VARCHAR(128),
  27. created DATETIME DEFAULT CURRENT_TIMESTAMP,
  28. updated DATETIME
  29. )
  30. `);
  31. break;
  32. case "Post":
  33. db.exec(`
  34. CREATE TABLE IF NOT EXISTS post (
  35. id VARCHAR(64) PRIMARY KEY,
  36. user_id INTEGER,
  37. title VARCHAR(256),
  38. content TEXT,
  39. shared BOOLEAN,
  40. created DATETIME DEFAULT CURRENT_TIMESTAMP,
  41. updated DATETIME
  42. )
  43. `);
  44. }
  45. return db;
  46. }
  47. export function find(
  48. tableName: string,
  49. queryObject: { [key: string]: string | number | boolean },
  50. targetKeys: string[] = [],
  51. limit?: number,
  52. dbPath?: string,
  53. ) {
  54. const db = prepareDB(tableName, dbPath);
  55. const findQuery = db.prepare(
  56. `SELECT ${
  57. targetKeys.length > 0 ? targetKeys.join(", ") : "*"
  58. } FROM ${tableName.toLowerCase()} WHERE ${
  59. Object.keys(queryObject)
  60. .map((queryKey) => `${queryKey} = ?`)
  61. .join(" AND ")
  62. } ORDER BY updated DESC ${limit ? ` LIMIT ${limit}` : ""}`,
  63. );
  64. try {
  65. return findQuery.all(
  66. ...Object.values(queryObject).map((v) => v.toString()),
  67. );
  68. } catch (e) {
  69. console.error("Find error:", e);
  70. return [];
  71. } finally {
  72. db.close();
  73. }
  74. }
  75. export function insert(
  76. tableName: string,
  77. userInsertObject: { [key: string]: string | number | boolean },
  78. dbPath?: string,
  79. ) {
  80. const db = prepareDB(tableName, dbPath);
  81. const insertObject = {
  82. ...userInsertObject,
  83. updated: new Date().toISOString().slice(0, 19).replace("T", " "),
  84. };
  85. const insertQuery = db.prepare(
  86. `INSERT INTO ${tableName.toLowerCase()} (${
  87. Object.keys(insertObject).join(
  88. ", ",
  89. )
  90. }) VALUES (${
  91. Object.keys(insertObject)
  92. .map(() => "?")
  93. .join(", ")
  94. })`,
  95. );
  96. try {
  97. insertQuery.run(...Object.values(insertObject).map((v) => v.toString()));
  98. return find(tableName, userInsertObject, ["id"], 1, dbPath);
  99. } catch (e) {
  100. console.error("Insert error:", e);
  101. return [];
  102. } finally {
  103. db.close();
  104. }
  105. }
  106. export function update(
  107. tableName: string,
  108. id: number | string,
  109. userUpdateObject: { [key: string]: string | number | boolean },
  110. dbPath?: string,
  111. ) {
  112. const db = prepareDB(tableName, dbPath);
  113. const updateObject = {
  114. ...userUpdateObject,
  115. updated: new Date().toISOString().slice(0, 19).replace("T", " "),
  116. };
  117. const updateQuery = db.prepare(
  118. `UPDATE ${tableName.toLowerCase()} SET ${
  119. Object.keys(updateObject)
  120. .map((updateKey) => `${updateKey} = ?`)
  121. .join(", ")
  122. } WHERE id = ?`,
  123. );
  124. try {
  125. updateQuery.run(
  126. ...Object.values(updateObject).map((v) => v.toString()),
  127. id,
  128. );
  129. return find(tableName, userUpdateObject, ["id"], 1, dbPath);
  130. } catch (e) {
  131. console.error("Update error:", e);
  132. return [];
  133. } finally {
  134. db.close();
  135. }
  136. }
  137. export function del(
  138. tableName: string,
  139. queryObject: { [key: string]: string | number | boolean },
  140. dbPath?: string,
  141. ) {
  142. const db = prepareDB(tableName, dbPath);
  143. const deleteQuery = db.prepare(
  144. `DELETE FROM ${tableName.toLowerCase()} WHERE ${
  145. Object.keys(queryObject)
  146. .map((queryKey) => `${queryKey} = ?`)
  147. .join(" AND ")
  148. }`,
  149. );
  150. try {
  151. deleteQuery.all(...Object.values(queryObject).map((v) => v.toString()));
  152. return true;
  153. } catch (e) {
  154. console.error("Delete error:", e);
  155. return false;
  156. } finally {
  157. db.close();
  158. }
  159. }