db.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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. share_password TEXT DEFAULT '',
  41. created DATETIME DEFAULT CURRENT_TIMESTAMP,
  42. updated DATETIME
  43. )
  44. `);
  45. try {
  46. db.exec(`ALTER TABLE post ADD COLUMN share_password TEXT DEFAULT ''`);
  47. } catch {
  48. // Column already exists
  49. }
  50. }
  51. return db;
  52. }
  53. export function find(
  54. tableName: string,
  55. queryObject: { [key: string]: string | number | boolean },
  56. targetKeys: string[] = [],
  57. limit?: number,
  58. dbPath?: string,
  59. ) {
  60. const db = prepareDB(tableName, dbPath);
  61. const findQuery = db.prepare(
  62. `SELECT ${
  63. targetKeys.length > 0 ? targetKeys.join(", ") : "*"
  64. } FROM ${tableName.toLowerCase()} WHERE ${
  65. Object.keys(queryObject)
  66. .map((queryKey) => `${queryKey} = ?`)
  67. .join(" AND ")
  68. } ORDER BY updated DESC ${limit ? ` LIMIT ${limit}` : ""}`,
  69. );
  70. try {
  71. return findQuery.all(
  72. ...Object.values(queryObject).map((v) => v.toString()),
  73. );
  74. } catch (e) {
  75. console.error("Find error:", e);
  76. return [];
  77. } finally {
  78. db.close();
  79. }
  80. }
  81. export function insert(
  82. tableName: string,
  83. userInsertObject: { [key: string]: string | number | boolean },
  84. dbPath?: string,
  85. ) {
  86. const db = prepareDB(tableName, dbPath);
  87. const insertObject = {
  88. ...userInsertObject,
  89. updated: new Date().toISOString().slice(0, 19).replace("T", " "),
  90. };
  91. const insertQuery = db.prepare(
  92. `INSERT INTO ${tableName.toLowerCase()} (${
  93. Object.keys(insertObject).join(
  94. ", ",
  95. )
  96. }) VALUES (${
  97. Object.keys(insertObject)
  98. .map(() => "?")
  99. .join(", ")
  100. })`,
  101. );
  102. try {
  103. insertQuery.run(...Object.values(insertObject).map((v) => v.toString()));
  104. return find(tableName, userInsertObject, ["id"], 1, dbPath);
  105. } catch (e) {
  106. console.error("Insert error:", e);
  107. return [];
  108. } finally {
  109. db.close();
  110. }
  111. }
  112. export function update(
  113. tableName: string,
  114. id: number | string,
  115. userUpdateObject: { [key: string]: string | number | boolean },
  116. dbPath?: string,
  117. ) {
  118. const db = prepareDB(tableName, dbPath);
  119. const updateObject = {
  120. ...userUpdateObject,
  121. updated: new Date().toISOString().slice(0, 19).replace("T", " "),
  122. };
  123. const updateQuery = db.prepare(
  124. `UPDATE ${tableName.toLowerCase()} SET ${
  125. Object.keys(updateObject)
  126. .map((updateKey) => `${updateKey} = ?`)
  127. .join(", ")
  128. } WHERE id = ?`,
  129. );
  130. try {
  131. updateQuery.run(
  132. ...Object.values(updateObject).map((v) => v.toString()),
  133. id,
  134. );
  135. return find(tableName, userUpdateObject, ["id"], 1, dbPath);
  136. } catch (e) {
  137. console.error("Update error:", e);
  138. return [];
  139. } finally {
  140. db.close();
  141. }
  142. }
  143. export function del(
  144. tableName: string,
  145. queryObject: { [key: string]: string | number | boolean },
  146. dbPath?: string,
  147. ) {
  148. const db = prepareDB(tableName, dbPath);
  149. const deleteQuery = db.prepare(
  150. `DELETE FROM ${tableName.toLowerCase()} WHERE ${
  151. Object.keys(queryObject)
  152. .map((queryKey) => `${queryKey} = ?`)
  153. .join(" AND ")
  154. }`,
  155. );
  156. try {
  157. deleteQuery.all(...Object.values(queryObject).map((v) => v.toString()));
  158. return true;
  159. } catch (e) {
  160. console.error("Delete error:", e);
  161. return false;
  162. } finally {
  163. db.close();
  164. }
  165. }