@ad-sdk/bgd 0.0.8 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/sqlx/migrations.js +62 -46
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ad-sdk/bgd",
3
- "version": "0.0.8",
3
+ "version": "0.1.0",
4
4
  "main": "index.js",
5
5
  "license": "BSD-3-Clause",
6
6
  "repository": {
@@ -6,10 +6,10 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.migrate = migrate;
7
7
  var _nodePath = _interopRequireDefault(require("node:path"));
8
8
  var fs = _interopRequireWildcard(require("node:fs"));
9
- var _uidlib = require("uidlib");
10
9
  var _errors = require("../errors");
11
10
  var _core = require("./core");
12
11
  var _either = require("../lifecycle/either");
12
+ var _uidlib = require("uidlib");
13
13
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
14
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
15
  /**
@@ -25,73 +25,89 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
25
25
 
26
26
  async function migrate(driver, directory, options) {
27
27
  try {
28
- if (!fs.existsSync(directory)) {
28
+ const dirPath = directory.toString();
29
+ if (!fs.existsSync(dirPath)) {
29
30
  if (options?.ensure) {
30
- throw new _errors.BGDException("[@@migrate] Migrations directory not found", "ER_IO_FAIL");
31
+ throw new _errors.BGDException("[@@migrate] Migrations directory not found", "ER_IO_FAIL" // eslint-disable-line comma-dangle
32
+ );
31
33
  }
32
- options?.logger?.log("Migrations directory not found at '%s'", directory.toString());
34
+ options?.logger?.log("Migrations directory not found at '%s'", dirPath);
33
35
  return (0, _either.right)(void 0);
34
36
  }
35
- const contentsList = await fs.promises.readdir(directory, {
36
- withFileTypes: true
37
- });
38
- const executed = await listExecuted_(driver);
37
+ const filesToProcess = (await collectMigrationFiles_(dirPath, options?.recursive ?? false)).toSorted((a, b) => a.filename.localeCompare(b.filename));
38
+ if (filesToProcess.length === 0) return (0, _either.right)(void 0);
39
+ const executedLogs = await listExecuted_(driver);
40
+ const executedFilenames = new Set(executedLogs.map(item => item.filename));
39
41
  const tx = await driver.createTransaction({
40
42
  allowQueryBatch: true
41
43
  });
42
- for (let i = 0; i < contentsList.length; ++i) {
43
- if (!_core.SQL_MIGRATION_FILE_PATTERN.test(contentsList[i].name)) continue;
44
- const currPath = _nodePath.default.join(contentsList[i].parentPath, contentsList[i].name // eslint-disable-line comma-dangle
45
- );
46
- if (contentsList[i].isDirectory() && options?.recursive) {
47
- const res = await migrate(driver, currPath, options);
48
- if (res.isLeft()) {
49
- throw res.value;
44
+ try {
45
+ for (const file of filesToProcess) {
46
+ if (executedFilenames.has(file.filename)) {
47
+ options?.logger?.log("[@@migrate] Migration \"%s\" has already executed. Skipping...", file.filename);
48
+ continue;
50
49
  }
51
- continue;
52
- }
53
- if (!contentsList[i].isFile()) continue;
54
- if (executed.some(item => {
55
- return item.filename === contentsList[i].name;
56
- })) {
57
- options?.logger?.log("[@@migrate] Migration \"%s\" has already executed. Skipping...", contentsList[i].name);
58
- continue;
59
- }
60
- const fc = await fs.promises.readFile(currPath, "utf8");
61
- const res = await tx.execBatch([{
62
- query: fc.trim()
63
- }, {
64
- query: `INSERT INTO bgd_migrations (
65
- migration_id, filename, order
66
- ) VALUES ($1::TEXT, $2::TEXT, $3::VARCHAR)`,
67
- values: [(0, _uidlib.uuidv7)(), contentsList[0].name, contentsList[i].name.split("_")[0]]
68
- }]);
69
- for (let j = 0; j < res.length; ++j) {
70
- if (res[j].isLeft()) {
71
- await tx.rollback();
72
- throw res[j].value;
50
+ options?.logger?.log("[@@migrate] Running \"%s\"...", file.filename);
51
+ const sqlContent = (await fs.promises.readFile(file.fullPath, "utf8")).trim();
52
+ const orderPrefix = file.filename.split("_")[0] || "000";
53
+ const r1 = await tx.exec(sqlContent);
54
+ if (r1.isLeft()) {
55
+ throw r1.value;
56
+ }
57
+ const r2 = await tx.exec(`INSERT INTO bgd_migrations (migration_id, filename, sort_index)
58
+ VALUES ($1::TEXT, $2::TEXT, $3::TEXT)`, [(0, _uidlib.uuidv7)(), file.filename, orderPrefix] // eslint-disable-line comma-dangle
59
+ );
60
+ if (r2.isLeft()) {
61
+ throw r2.value;
73
62
  }
74
63
  }
64
+ await tx.commit();
65
+ return (0, _either.right)(void 0);
66
+ } catch (err) {
67
+ await tx.rollback();
68
+ throw err;
75
69
  }
76
- await tx.commit();
77
- return (0, _either.right)(void 0);
78
70
  } catch (err) {
79
71
  let e = err;
80
72
  if (!(err instanceof _errors.BGDException)) {
81
73
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
82
- e = new _errors.BGDException(`[@@migrate] Failed to execute SQL migration due to: ${err?.message || String(err) || "Unknown error"}`);
74
+ e = new _errors.BGDException(`[@@migrate] ${err?.message || String(err) || "Unknown error"}`);
83
75
  }
84
76
  return (0, _either.left)(e);
85
77
  }
86
78
  }
79
+ async function collectMigrationFiles_(dirPath, recursive) {
80
+ const res = [];
81
+ const contents = await fs.promises.readdir(dirPath, {
82
+ withFileTypes: true
83
+ });
84
+ for (const entry of contents) {
85
+ const fullPath = _nodePath.default.join(dirPath, entry.name);
86
+ if (entry.isDirectory()) {
87
+ if (recursive) {
88
+ const children = await collectMigrationFiles_(fullPath, recursive);
89
+ res.push(...children);
90
+ }
91
+ continue;
92
+ }
93
+ if (entry.isFile() && _core.SQL_MIGRATION_FILE_PATTERN.test(entry.name)) {
94
+ res.push({
95
+ fullPath,
96
+ filename: entry.name
97
+ });
98
+ }
99
+ }
100
+ return res;
101
+ }
87
102
  const PGCT_QUERY = `CREATE TABLE IF NOT EXISTS bgd_migrations (
88
103
  migration_id VARCHAR(100) NOT NULL UNIQUE PRIMARY KEY,
89
104
  sequence SERIAL NOT NULL,
90
105
  filename VARCHAR(255) NOT NULL UNIQUE,
91
- order VARCHAR(4) NOT NULL,
92
- executed_at TIMESTAMP WITH TIME ZONE NOT NULL
106
+ sort_index VARCHAR(4) NOT NULL,
107
+
108
+ executed_at TIMESTAMPTZ NOT NULL
93
109
  DEFAULT (NOW() AT TIME ZONE 'UTC')
94
- )`;
110
+ );`;
95
111
  async function ensureTable_(driver) {
96
112
  let text = "";
97
113
  switch (driver.dialect) {
@@ -101,13 +117,13 @@ async function ensureTable_(driver) {
101
117
  }
102
118
  break;
103
119
  default:
104
- throw new _errors.BGDException(`[@@ensureTable_] Unknown or unsupported database dialect "${driver.dialect}"`);
120
+ throw new _errors.BGDException("[@@ensureTable_] Unknown or unsupported database dialect");
105
121
  }
106
122
  await driver.exec(text);
107
123
  }
108
124
  async function listExecuted_(driver) {
109
125
  await ensureTable_(driver);
110
- const res = await driver.exec("SELECT * FROM bgd_migrations");
126
+ const res = await driver.exec("SELECT * FROM migrations");
111
127
  if (res.isLeft()) {
112
128
  throw res.value;
113
129
  }