@ad-sdk/bgd 0.0.9 → 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 +57 -45
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ad-sdk/bgd",
3
- "version": "0.0.9",
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,77 +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
44
  try {
43
- for (let i = 0; i < contentsList.length; ++i) {
44
- if (!_core.SQL_MIGRATION_FILE_PATTERN.test(contentsList[i].name)) continue;
45
- const currPath = _nodePath.default.join(contentsList[i].parentPath, contentsList[i].name // eslint-disable-line comma-dangle
46
- );
47
- if (contentsList[i].isDirectory() && options?.recursive) {
48
- const res = await migrate(driver, currPath, options);
49
- if (res.isLeft()) {
50
- throw res.value;
51
- }
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);
52
48
  continue;
53
49
  }
54
- if (!contentsList[i].isFile()) continue;
55
- if (executed.some(item => {
56
- return item.filename === contentsList[i].name;
57
- })) {
58
- options?.logger?.log("[@@migrate] Migration \"%s\" has already executed. Skipping...", contentsList[i].name);
59
- continue;
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;
60
56
  }
61
- const fc = await fs.promises.readFile(currPath, "utf8");
62
- const res = await tx.execBatch([{
63
- query: fc.trim()
64
- }, {
65
- query: `INSERT INTO bgd_migrations (
66
- migration_id, filename, order
67
- ) VALUES ($1::TEXT, $2::TEXT, $3::VARCHAR)`,
68
- values: [(0, _uidlib.uuidv7)(), contentsList[0].name, contentsList[i].name.split("_")[0]]
69
- }]);
70
- for (let j = 0; j < res.length; ++j) {
71
- if (res[j].isLeft()) {
72
- throw res[j].value;
73
- }
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;
74
62
  }
75
63
  }
76
64
  await tx.commit();
77
- } catch (e) {
65
+ return (0, _either.right)(void 0);
66
+ } catch (err) {
78
67
  await tx.rollback();
79
- throw e;
68
+ throw err;
80
69
  }
81
- return (0, _either.right)(void 0);
82
70
  } catch (err) {
83
71
  let e = err;
84
72
  if (!(err instanceof _errors.BGDException)) {
85
73
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
86
- 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"}`);
87
75
  }
88
76
  return (0, _either.left)(e);
89
77
  }
90
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
+ }
91
102
  const PGCT_QUERY = `CREATE TABLE IF NOT EXISTS bgd_migrations (
92
103
  migration_id VARCHAR(100) NOT NULL UNIQUE PRIMARY KEY,
93
104
  sequence SERIAL NOT NULL,
94
105
  filename VARCHAR(255) NOT NULL UNIQUE,
95
- order VARCHAR(4) NOT NULL,
96
- executed_at TIMESTAMP WITH TIME ZONE NOT NULL
106
+ sort_index VARCHAR(4) NOT NULL,
107
+
108
+ executed_at TIMESTAMPTZ NOT NULL
97
109
  DEFAULT (NOW() AT TIME ZONE 'UTC')
98
- )`;
110
+ );`;
99
111
  async function ensureTable_(driver) {
100
112
  let text = "";
101
113
  switch (driver.dialect) {
@@ -105,13 +117,13 @@ async function ensureTable_(driver) {
105
117
  }
106
118
  break;
107
119
  default:
108
- throw new _errors.BGDException(`[@@ensureTable_] Unknown or unsupported database dialect "${driver.dialect}"`);
120
+ throw new _errors.BGDException("[@@ensureTable_] Unknown or unsupported database dialect");
109
121
  }
110
122
  await driver.exec(text);
111
123
  }
112
124
  async function listExecuted_(driver) {
113
125
  await ensureTable_(driver);
114
- const res = await driver.exec("SELECT * FROM bgd_migrations");
126
+ const res = await driver.exec("SELECT * FROM migrations");
115
127
  if (res.isLeft()) {
116
128
  throw res.value;
117
129
  }