applyDatabaseConfig.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. const fs = require("fs");
  2. const { resolve } = require("path");
  3. const { displayMessage } = require("./displayMessage.js");
  4. const { $sh } = require("./shell.js");
  5. async function applyDatabaseConfig() {
  6. const db_conf = {
  7. // location: "data/postgres",
  8. location: resolve(__dirname, "..", "..", "data", "postgres"),
  9. port: 5432,
  10. database: "webui",
  11. username: "postgres",
  12. password: "",
  13. ssl: false,
  14. };
  15. const initializeDatabase = async () => {
  16. if (fs.existsSync(db_conf.location)) {
  17. displayMessage("Database already initialized, skipping...");
  18. return;
  19. }
  20. displayMessage("Initializing database...");
  21. await $sh(`initdb -D ${db_conf.location} -U ${db_conf.username}`);
  22. displayMessage("Successfully initialized database");
  23. };
  24. await initializeDatabase();
  25. const withDatabase = async (func) => {
  26. const startDatabase = async () => {
  27. displayMessage("Starting database...");
  28. await $sh(`pg_ctl start -D ${db_conf.location}`);
  29. displayMessage("Successfully started database");
  30. };
  31. const stopDatabase = async () => {
  32. displayMessage("Stopping database...");
  33. await $sh(`pg_ctl stop -D ${db_conf.location} -m fast`);
  34. displayMessage("Successfully stopped database");
  35. };
  36. const awaitDatabase = async (counter = 0) => {
  37. try {
  38. await $sh(`pg_isready -U ${db_conf.username}`);
  39. } catch (error) {
  40. displayMessage(`Database is not ready, retrying... ${counter}/10`);
  41. if (counter < 10) {
  42. await awaitDatabase(counter + 1);
  43. } else {
  44. displayMessage("Database is not ready, aborting...");
  45. throw error;
  46. }
  47. }
  48. };
  49. await startDatabase();
  50. await awaitDatabase();
  51. try {
  52. await func();
  53. } catch (error) {
  54. throw error;
  55. } finally {
  56. await stopDatabase();
  57. }
  58. };
  59. const db_version = "1";
  60. const db_version_file = resolve(__dirname, "..", ".db_version");
  61. const withDatabaseVersioning = async (func) => {
  62. if (fs.existsSync(db_version_file)) {
  63. const version = fs.readFileSync(db_version_file, "utf8");
  64. if (version === db_version) {
  65. displayMessage(
  66. `Database is already up to date with version=${version}, skipping...`
  67. );
  68. return;
  69. } else {
  70. displayMessage(
  71. `Database is not up to date, current version=${version}, version=${db_version}, upgrading...`
  72. );
  73. await func();
  74. fs.writeFileSync(db_version_file, db_version);
  75. }
  76. }
  77. };
  78. await withDatabaseVersioning(() =>
  79. withDatabase(async () => {
  80. const createDB = async () => {
  81. displayMessage(`Creating database ${db_conf.database}`);
  82. // create a database, error if it already exists
  83. try {
  84. await $sh(`createdb -U ${db_conf.username} ${db_conf.database}`);
  85. } catch (error) {
  86. displayMessage("Database already exists, skipping...");
  87. return;
  88. }
  89. displayMessage("Successfully created database");
  90. };
  91. const applyMigrations = async () => {
  92. const sql = async (strings) => {
  93. // Since we're assuming no interpolated values, we can directly use the string
  94. const query = strings[0];
  95. const psqlCommand = `psql -U ${db_conf.username} -d ${
  96. db_conf.database
  97. } -c "${query.replace(/"/g, '\\"').replace(/\n/g, " ")}"`;
  98. $sh(psqlCommand);
  99. };
  100. await sql`CREATE TABLE IF NOT EXISTS generations (
  101. id SERIAL PRIMARY KEY,
  102. metadata JSONB
  103. );`;
  104. };
  105. await createDB();
  106. await applyMigrations();
  107. })
  108. );
  109. }
  110. exports.applyDatabaseConfig = applyDatabaseConfig;