3 const fs
= require('fs');
4 const path
= require('path');
7 * Utility functions for wrangling schema migrations.
8 * This mostly just deals with sorting and comparing 'x.y.z' version
9 * strings, with some presumptions about directory layouts and whatnot.
13 * @typedef {Object} SchemaVersionObject
14 * @property {Number} major
15 * @property {Number} minor
16 * @property {Number} patch
21 * Split a dotted version string into parts.
23 * @returns {SchemaVersionObject}
25 function schemaVersionStringToObject(v
) {
26 const [ major
, minor
, patch
] = v
.split('.', 3).map((x
) => parseInt(x
, 10));
27 return { major
, minor
, patch
};
32 * Render a version object numerically.
33 * @param {SchemaVersionObject} v
36 function schemaVersionObjectToNumber(v
) {
38 return parseInt(v
.major
) * vScale
* vScale
+ parseInt(v
.minor
) * vScale
+ parseInt(v
.patch
);
43 * Convert dotted version string into number.
47 function schemaVersionStringToNumber(v
) {
48 return schemaVersionObjectToNumber(schemaVersionStringToObject(v
));
53 * Version string comparison, for sorting.
58 function schemaVersionStringCmp(a
, b
) {
59 return schemaVersionStringToNumber(a
) - schemaVersionStringToNumber(b
);
64 * Check if an entry in a directory is a directory containing a migration file.
65 * @param {String} schemaDir
66 * @param {String} name
69 function isSchemaMigrationDirectory(schemaDir
, name
, migrationFile
= 'apply.sql') {
70 // eslint-disable-next-line security/detect-non-literal-fs-filename
71 const nameStat
= fs
.statSync(path
.join(schemaDir
, name
));
72 if (nameStat
.isDirectory()) {
75 // eslint-disable-next-line security/detect-non-literal-fs-filename
76 applyStat
= fs
.statSync(path
.join(schemaDir
, name
, migrationFile
));
77 return applyStat
.isFile();
87 * Return an array of schema migration directory names within engineDir,
88 * sorted in increasing order.
89 * @param {String} engineDir
92 function allSchemaVersions(engineDir
) {
93 const schemaDir
= path
.join(engineDir
, 'sql', 'schema');
94 // eslint-disable-next-line security/detect-non-literal-fs-filename
95 const availableVersions
= fs
.readdirSync(schemaDir
).filter((d
) => isSchemaMigrationDirectory(schemaDir
, d
));
96 availableVersions
.sort(schemaVersionStringCmp
);
97 return availableVersions
;
102 * Return an array of schema migration directory names within engineDir,
103 * which are within supported range, and are greater than the current
104 * @param {String} engineDir
105 * @param {SchemaVersionObject} current
106 * @param {Object} supported
107 * @param {SchemaVersionObject} supported.min
108 * @param {SchemaVersionObject} supported.max
109 * @returns {String[]}
111 function unappliedSchemaVersions(engineDir
, current
, supported
) {
112 const min
= schemaVersionObjectToNumber(supported
.min
);
113 const max
= schemaVersionObjectToNumber(supported
.max
);
114 const cur
= schemaVersionObjectToNumber(current
);
115 const available
= allSchemaVersions(engineDir
);
116 return available
.filter((a
) => {
117 a
= schemaVersionStringToNumber(a
);
118 return a
>= min
&& a
<= max
&& a
> cur
;
124 schemaVersionStringToObject
,
125 schemaVersionObjectToNumber
,
126 schemaVersionStringToNumber
,
127 schemaVersionStringCmp
,
128 isSchemaMigrationDirectory
,
130 unappliedSchemaVersions
,