You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
4.5 KiB

11 months ago
  1. const { getGitVersion } = require("../../endpoints/utils");
  2. const { Telemetry } = require("../../models/telemetry");
  3. function checkColumnTemplate(tablename = null, column = null) {
  4. if (!tablename || !column)
  5. throw new Error(`Migration Error`, { tablename, column });
  6. return `SELECT COUNT(*) AS _exists FROM pragma_table_info('${tablename}') WHERE name='${column}'`;
  7. }
  8. // Note (tcarambat): Since there is no good way to track migrations in Node/SQLite we use this simple system
  9. // Each model has a `migrations` method that will return an array like...
  10. // { colName: 'stringColName', execCmd: `SQL Command to run when`, doif: boolean },
  11. // colName = name of column
  12. // execCmd = Command to run when doif matches the state of the DB
  13. // doif = condition to match that determines if execCmd will run.
  14. // eg: Table workspace has slug column.
  15. // execCmd: ALTER TABLE DROP COLUMN slug;
  16. // doif: true
  17. // => Will drop the slug column if the workspace table has a column named 'slug' otherwise nothing happens.
  18. // If you are adding a new table column if needs to exist in the Models `colsInit` and as a migration.
  19. // So both new and existing DBs will get the column when code is pulled in.
  20. async function checkForMigrations(model, db) {
  21. if (model.migrations().length === 0) return;
  22. const toMigrate = [];
  23. for (const { colName, execCmd, doif } of model.migrations()) {
  24. const { _exists } = await db.get(
  25. checkColumnTemplate(model.tablename, colName)
  26. );
  27. const colExists = _exists !== 0;
  28. if (colExists !== doif) continue;
  29. toMigrate.push(execCmd);
  30. }
  31. if (toMigrate.length === 0) return;
  32. console.log(`Running ${toMigrate.length} migrations`, toMigrate);
  33. await db.exec(toMigrate.join(";\n"));
  34. return;
  35. }
  36. // Note(tcarambat): When building in production via Docker the SQLite file will not exist
  37. // and if this function tries to run on boot the file will not exist
  38. // and the server will abort and the container will exit.
  39. // This function will run each reload on dev but on production
  40. // it will be stubbed until the /api/migrate endpoint is GET.
  41. async function validateTablePragmas(force = false) {
  42. try {
  43. if (process.env.NODE_ENV !== "development" && force === false) {
  44. console.log(
  45. `\x1b[34m[MIGRATIONS STUBBED]\x1b[0m Please ping /migrate once server starts to run migrations`
  46. );
  47. return;
  48. }
  49. const { SystemSettings } = require("../../models/systemSettings");
  50. const { User } = require("../../models/user");
  51. const { Workspace } = require("../../models/workspace");
  52. const { WorkspaceUser } = require("../../models/workspaceUsers");
  53. const { Document } = require("../../models/documents");
  54. const { DocumentVectors } = require("../../models/vectors");
  55. const { WorkspaceChats } = require("../../models/workspaceChats");
  56. const { Invite } = require("../../models/invite");
  57. const { WelcomeMessages } = require("../../models/welcomeMessages");
  58. const { ApiKey } = require("../../models/apiKeys");
  59. await SystemSettings.migrateTable();
  60. await User.migrateTable();
  61. await Workspace.migrateTable();
  62. await WorkspaceUser.migrateTable();
  63. await Document.migrateTable();
  64. await DocumentVectors.migrateTable();
  65. await WorkspaceChats.migrateTable();
  66. await Invite.migrateTable();
  67. await WelcomeMessages.migrateTable();
  68. await ApiKey.migrateTable();
  69. } catch (e) {
  70. console.error(`validateTablePragmas: Migrations failed`, e);
  71. }
  72. return;
  73. }
  74. // Telemetry is anonymized and your data is never read. This can be disabled by setting
  75. // DISABLE_TELEMETRY=true in the `.env` of however you setup. Telemetry helps us determine use
  76. // of how AnythingLLM is used and how to improve this product!
  77. // You can see all Telemetry events by ctrl+f `Telemetry.sendEvent` calls to verify this claim.
  78. async function setupTelemetry() {
  79. if (process.env.DISABLE_TELEMETRY === "true") {
  80. console.log(
  81. `\x1b[31m[TELEMETRY DISABLED]\x1b[0m Telemetry is marked as disabled - no events will send. Telemetry helps Mintplex Labs Inc improve AnythingLLM.`
  82. );
  83. return true;
  84. }
  85. if (Telemetry.isDev()) {
  86. console.log(
  87. `\x1b[33m[TELEMETRY STUBBED]\x1b[0m Anonymous Telemetry stubbed in development.`
  88. );
  89. return;
  90. }
  91. console.log(
  92. `\x1b[32m[TELEMETRY ENABLED]\x1b[0m Anonymous Telemetry enabled. Telemetry helps Mintplex Labs Inc improve AnythingLLM.`
  93. );
  94. await Telemetry.findOrCreateId();
  95. await Telemetry.sendTelemetry("server_boot", {
  96. commit: getGitVersion(),
  97. });
  98. return;
  99. }
  100. module.exports = {
  101. checkForMigrations,
  102. validateTablePragmas,
  103. setupTelemetry,
  104. };