@brandtg/flapjack 0.2.0 → 1.0.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.
- package/dist/migrate.d.ts +2 -20
- package/dist/migrate.d.ts.map +1 -1
- package/dist/migrate.js +6 -19
- package/dist/model.js +3 -3
- package/migrations/1759720355601_create-feature-flag.js +35 -28
- package/migrations/1760502793520_add-feature-flag-expires.js +7 -4
- package/migrations/1764560643657_add-feature-flag-groups.js +57 -37
- package/package.json +1 -1
package/dist/migrate.d.ts
CHANGED
|
@@ -4,21 +4,16 @@
|
|
|
4
4
|
export interface MigrationOptions {
|
|
5
5
|
/** PostgreSQL connection URL (e.g., "postgresql://user:pass@localhost/dbname") */
|
|
6
6
|
databaseUrl: string;
|
|
7
|
-
/** Name of the migrations tracking table (default: 'pgmigrations') */
|
|
8
|
-
migrationsTable?: string;
|
|
9
|
-
/** Schema name to create tables in (optional) */
|
|
10
|
-
schema?: string;
|
|
11
7
|
}
|
|
12
8
|
/**
|
|
13
9
|
* Run Flapjack database migrations.
|
|
14
10
|
*
|
|
15
11
|
* This function applies all pending migrations to create or update the
|
|
16
|
-
*
|
|
12
|
+
* flapjack.feature_flag table in your PostgreSQL database. All tables,
|
|
13
|
+
* including the migrations tracking table, are created in the flapjack schema.
|
|
17
14
|
*
|
|
18
15
|
* @param options - Migration configuration options
|
|
19
16
|
* @param options.databaseUrl - PostgreSQL connection URL
|
|
20
|
-
* @param options.migrationsTable - Name of the migrations tracking table (default: 'pgmigrations')
|
|
21
|
-
* @param options.schema - Schema name to create tables in (optional)
|
|
22
17
|
* @returns Promise that resolves when migrations are complete
|
|
23
18
|
*
|
|
24
19
|
* @throws Will throw an error if the database connection fails or migrations cannot be applied
|
|
@@ -27,22 +22,9 @@ export interface MigrationOptions {
|
|
|
27
22
|
* ```typescript
|
|
28
23
|
* import { runMigrations } from "@brandtg/flapjack";
|
|
29
24
|
*
|
|
30
|
-
* // Basic usage
|
|
31
25
|
* await runMigrations({
|
|
32
26
|
* databaseUrl: process.env.DATABASE_URL,
|
|
33
27
|
* });
|
|
34
|
-
*
|
|
35
|
-
* // With custom migrations table
|
|
36
|
-
* await runMigrations({
|
|
37
|
-
* databaseUrl: process.env.DATABASE_URL,
|
|
38
|
-
* migrationsTable: "my_migrations",
|
|
39
|
-
* });
|
|
40
|
-
*
|
|
41
|
-
* // With custom schema
|
|
42
|
-
* await runMigrations({
|
|
43
|
-
* databaseUrl: process.env.DATABASE_URL,
|
|
44
|
-
* schema: "feature_flags",
|
|
45
|
-
* });
|
|
46
28
|
* ```
|
|
47
29
|
*/
|
|
48
30
|
export declare function runMigrations(options: MigrationOptions): Promise<void>;
|
package/dist/migrate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kFAAkF;IAClF,WAAW,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kFAAkF;IAClF,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB5E"}
|
package/dist/migrate.js
CHANGED
|
@@ -7,12 +7,11 @@ const __dirname = path.dirname(__filename);
|
|
|
7
7
|
* Run Flapjack database migrations.
|
|
8
8
|
*
|
|
9
9
|
* This function applies all pending migrations to create or update the
|
|
10
|
-
*
|
|
10
|
+
* flapjack.feature_flag table in your PostgreSQL database. All tables,
|
|
11
|
+
* including the migrations tracking table, are created in the flapjack schema.
|
|
11
12
|
*
|
|
12
13
|
* @param options - Migration configuration options
|
|
13
14
|
* @param options.databaseUrl - PostgreSQL connection URL
|
|
14
|
-
* @param options.migrationsTable - Name of the migrations tracking table (default: 'pgmigrations')
|
|
15
|
-
* @param options.schema - Schema name to create tables in (optional)
|
|
16
15
|
* @returns Promise that resolves when migrations are complete
|
|
17
16
|
*
|
|
18
17
|
* @throws Will throw an error if the database connection fails or migrations cannot be applied
|
|
@@ -21,34 +20,22 @@ const __dirname = path.dirname(__filename);
|
|
|
21
20
|
* ```typescript
|
|
22
21
|
* import { runMigrations } from "@brandtg/flapjack";
|
|
23
22
|
*
|
|
24
|
-
* // Basic usage
|
|
25
23
|
* await runMigrations({
|
|
26
24
|
* databaseUrl: process.env.DATABASE_URL,
|
|
27
25
|
* });
|
|
28
|
-
*
|
|
29
|
-
* // With custom migrations table
|
|
30
|
-
* await runMigrations({
|
|
31
|
-
* databaseUrl: process.env.DATABASE_URL,
|
|
32
|
-
* migrationsTable: "my_migrations",
|
|
33
|
-
* });
|
|
34
|
-
*
|
|
35
|
-
* // With custom schema
|
|
36
|
-
* await runMigrations({
|
|
37
|
-
* databaseUrl: process.env.DATABASE_URL,
|
|
38
|
-
* schema: "feature_flags",
|
|
39
|
-
* });
|
|
40
26
|
* ```
|
|
41
27
|
*/
|
|
42
28
|
export async function runMigrations(options) {
|
|
43
|
-
const { databaseUrl
|
|
29
|
+
const { databaseUrl } = options;
|
|
44
30
|
// Path to migrations directory (relative to dist in production)
|
|
45
31
|
const migrationsDir = path.resolve(__dirname, "../migrations");
|
|
46
32
|
const migrationConfig = {
|
|
47
33
|
databaseUrl,
|
|
48
34
|
dir: migrationsDir,
|
|
49
35
|
direction: "up",
|
|
50
|
-
|
|
51
|
-
|
|
36
|
+
schema: "flapjack",
|
|
37
|
+
migrationsTable: "pgmigrations",
|
|
38
|
+
createSchema: true,
|
|
52
39
|
verbose: false,
|
|
53
40
|
};
|
|
54
41
|
await runner(migrationConfig);
|
package/dist/model.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import MurmurHash3 from "imurmurhash";
|
|
2
|
-
const TABLE = "
|
|
2
|
+
const TABLE = "flapjack.feature_flag";
|
|
3
3
|
const COLUMNS = [
|
|
4
4
|
"id",
|
|
5
5
|
"name",
|
|
@@ -406,8 +406,8 @@ export class FeatureFlagModel {
|
|
|
406
406
|
return false;
|
|
407
407
|
}
|
|
408
408
|
}
|
|
409
|
-
const GROUP_TABLE = "
|
|
410
|
-
const GROUP_MEMBER_TABLE = "
|
|
409
|
+
const GROUP_TABLE = "flapjack.feature_flag_group";
|
|
410
|
+
const GROUP_MEMBER_TABLE = "flapjack.feature_flag_group_member";
|
|
411
411
|
const GROUP_COLUMNS = ["id", "name", "note", "created", "modified"];
|
|
412
412
|
function mapGroupRow(row) {
|
|
413
413
|
return {
|
|
@@ -9,30 +9,37 @@ export const shorthands = undefined;
|
|
|
9
9
|
* @returns {Promise<void> | void}
|
|
10
10
|
*/
|
|
11
11
|
export const up = (pgm) => {
|
|
12
|
-
// Create the
|
|
13
|
-
pgm.createTable(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
type: "
|
|
19
|
-
|
|
12
|
+
// Create the feature_flag table (schema created by node-pg-migrate)
|
|
13
|
+
pgm.createTable(
|
|
14
|
+
{ schema: "flapjack", name: "feature_flag" },
|
|
15
|
+
{
|
|
16
|
+
id: "id",
|
|
17
|
+
name: { type: "text", notNull: true, unique: true },
|
|
18
|
+
everyone: { type: "boolean" },
|
|
19
|
+
percent: {
|
|
20
|
+
type: "numeric(3,1)",
|
|
21
|
+
check: "percent >= 0 AND percent <= 99.9",
|
|
22
|
+
},
|
|
23
|
+
roles: { type: "text[]", default: pgm.func("'{}'::text[]") },
|
|
24
|
+
groups: { type: "text[]", default: pgm.func("'{}'::text[]") },
|
|
25
|
+
users: { type: "text[]", default: pgm.func("'{}'::text[]") },
|
|
26
|
+
note: { type: "text" },
|
|
27
|
+
created: {
|
|
28
|
+
type: "timestamptz",
|
|
29
|
+
notNull: true,
|
|
30
|
+
default: pgm.func("now()"),
|
|
31
|
+
},
|
|
32
|
+
modified: {
|
|
33
|
+
type: "timestamptz",
|
|
34
|
+
notNull: true,
|
|
35
|
+
default: pgm.func("now()"),
|
|
36
|
+
},
|
|
20
37
|
},
|
|
21
|
-
|
|
22
|
-
groups: { type: "text[]", default: pgm.func("'{}'::text[]") },
|
|
23
|
-
users: { type: "text[]", default: pgm.func("'{}'::text[]") },
|
|
24
|
-
note: { type: "text" },
|
|
25
|
-
created: { type: "timestamptz", notNull: true, default: pgm.func("now()") },
|
|
26
|
-
modified: {
|
|
27
|
-
type: "timestamptz",
|
|
28
|
-
notNull: true,
|
|
29
|
-
default: pgm.func("now()"),
|
|
30
|
-
},
|
|
31
|
-
});
|
|
38
|
+
);
|
|
32
39
|
|
|
33
40
|
// Create a trigger to update the modified timestamp on row update
|
|
34
41
|
pgm.sql(`
|
|
35
|
-
CREATE OR REPLACE FUNCTION
|
|
42
|
+
CREATE OR REPLACE FUNCTION flapjack.set_modified_timestamp()
|
|
36
43
|
RETURNS trigger AS $$
|
|
37
44
|
BEGIN
|
|
38
45
|
NEW.modified = now();
|
|
@@ -41,12 +48,12 @@ export const up = (pgm) => {
|
|
|
41
48
|
$$ LANGUAGE plpgsql;
|
|
42
49
|
`);
|
|
43
50
|
|
|
44
|
-
// Attach the trigger to the
|
|
51
|
+
// Attach the trigger to the feature_flag table
|
|
45
52
|
pgm.sql(`
|
|
46
|
-
CREATE TRIGGER
|
|
47
|
-
BEFORE UPDATE ON
|
|
53
|
+
CREATE TRIGGER feature_flag_set_modified
|
|
54
|
+
BEFORE UPDATE ON flapjack.feature_flag
|
|
48
55
|
FOR EACH ROW
|
|
49
|
-
EXECUTE FUNCTION
|
|
56
|
+
EXECUTE FUNCTION flapjack.set_modified_timestamp();
|
|
50
57
|
`);
|
|
51
58
|
};
|
|
52
59
|
|
|
@@ -57,9 +64,9 @@ export const up = (pgm) => {
|
|
|
57
64
|
*/
|
|
58
65
|
export const down = (pgm) => {
|
|
59
66
|
pgm.sql(`
|
|
60
|
-
DROP TRIGGER IF EXISTS
|
|
61
|
-
ON
|
|
67
|
+
DROP TRIGGER IF EXISTS feature_flag_set_modified
|
|
68
|
+
ON flapjack.feature_flag;
|
|
62
69
|
`);
|
|
63
|
-
pgm.sql(`DROP FUNCTION IF EXISTS
|
|
64
|
-
pgm.dropTable("
|
|
70
|
+
pgm.sql(`DROP FUNCTION IF EXISTS flapjack.set_modified_timestamp;`);
|
|
71
|
+
pgm.dropTable({ schema: "flapjack", name: "feature_flag" });
|
|
65
72
|
};
|
|
@@ -9,9 +9,12 @@ export const shorthands = undefined;
|
|
|
9
9
|
* @returns {Promise<void> | void}
|
|
10
10
|
*/
|
|
11
11
|
export const up = (pgm) => {
|
|
12
|
-
pgm.addColumn(
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
pgm.addColumn(
|
|
13
|
+
{ schema: "flapjack", name: "feature_flag" },
|
|
14
|
+
{
|
|
15
|
+
expires: { type: "timestamptz" },
|
|
16
|
+
},
|
|
17
|
+
);
|
|
15
18
|
};
|
|
16
19
|
|
|
17
20
|
/**
|
|
@@ -20,5 +23,5 @@ export const up = (pgm) => {
|
|
|
20
23
|
* @returns {Promise<void> | void}
|
|
21
24
|
*/
|
|
22
25
|
export const down = (pgm) => {
|
|
23
|
-
pgm.dropColumn("
|
|
26
|
+
pgm.dropColumn({ schema: "flapjack", name: "feature_flag" }, "expires");
|
|
24
27
|
};
|
|
@@ -9,40 +9,54 @@ export const shorthands = undefined;
|
|
|
9
9
|
* @returns {Promise<void> | void}
|
|
10
10
|
*/
|
|
11
11
|
export const up = (pgm) => {
|
|
12
|
-
// Create the
|
|
13
|
-
pgm.createTable(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
// Create the feature_flag_group table
|
|
13
|
+
pgm.createTable(
|
|
14
|
+
{ schema: "flapjack", name: "feature_flag_group" },
|
|
15
|
+
{
|
|
16
|
+
id: "id",
|
|
17
|
+
name: { type: "text", notNull: true, unique: true },
|
|
18
|
+
note: { type: "text" },
|
|
19
|
+
created: {
|
|
20
|
+
type: "timestamptz",
|
|
21
|
+
notNull: true,
|
|
22
|
+
default: pgm.func("now()"),
|
|
23
|
+
},
|
|
24
|
+
modified: {
|
|
25
|
+
type: "timestamptz",
|
|
26
|
+
notNull: true,
|
|
27
|
+
default: pgm.func("now()"),
|
|
28
|
+
},
|
|
22
29
|
},
|
|
23
|
-
|
|
30
|
+
);
|
|
24
31
|
|
|
25
|
-
// Create the
|
|
26
|
-
pgm.createTable(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
// Create the feature_flag_group_member relation table
|
|
33
|
+
pgm.createTable(
|
|
34
|
+
{ schema: "flapjack", name: "feature_flag_group_member" },
|
|
35
|
+
{
|
|
36
|
+
id: "id",
|
|
37
|
+
group_id: {
|
|
38
|
+
type: "integer",
|
|
39
|
+
notNull: true,
|
|
40
|
+
references: { schema: "flapjack", name: "feature_flag_group" },
|
|
41
|
+
onDelete: "CASCADE",
|
|
42
|
+
},
|
|
43
|
+
feature_flag_id: {
|
|
44
|
+
type: "integer",
|
|
45
|
+
notNull: true,
|
|
46
|
+
references: { schema: "flapjack", name: "feature_flag" },
|
|
47
|
+
onDelete: "CASCADE",
|
|
48
|
+
},
|
|
49
|
+
created: {
|
|
50
|
+
type: "timestamptz",
|
|
51
|
+
notNull: true,
|
|
52
|
+
default: pgm.func("now()"),
|
|
53
|
+
},
|
|
39
54
|
},
|
|
40
|
-
|
|
41
|
-
});
|
|
55
|
+
);
|
|
42
56
|
|
|
43
57
|
// Add unique constraint on group_id and feature_flag_id
|
|
44
58
|
pgm.addConstraint(
|
|
45
|
-
"
|
|
59
|
+
{ schema: "flapjack", name: "feature_flag_group_member" },
|
|
46
60
|
"unique_group_feature_flag",
|
|
47
61
|
{
|
|
48
62
|
unique: ["group_id", "feature_flag_id"],
|
|
@@ -50,15 +64,21 @@ export const up = (pgm) => {
|
|
|
50
64
|
);
|
|
51
65
|
|
|
52
66
|
// Create indexes for efficient lookups
|
|
53
|
-
pgm.createIndex(
|
|
54
|
-
|
|
67
|
+
pgm.createIndex(
|
|
68
|
+
{ schema: "flapjack", name: "feature_flag_group_member" },
|
|
69
|
+
"group_id",
|
|
70
|
+
);
|
|
71
|
+
pgm.createIndex(
|
|
72
|
+
{ schema: "flapjack", name: "feature_flag_group_member" },
|
|
73
|
+
"feature_flag_id",
|
|
74
|
+
);
|
|
55
75
|
|
|
56
76
|
// Attach the modified timestamp trigger to the group table
|
|
57
77
|
pgm.sql(`
|
|
58
|
-
CREATE TRIGGER
|
|
59
|
-
BEFORE UPDATE ON
|
|
78
|
+
CREATE TRIGGER feature_flag_group_set_modified
|
|
79
|
+
BEFORE UPDATE ON flapjack.feature_flag_group
|
|
60
80
|
FOR EACH ROW
|
|
61
|
-
EXECUTE FUNCTION
|
|
81
|
+
EXECUTE FUNCTION flapjack.set_modified_timestamp();
|
|
62
82
|
`);
|
|
63
83
|
};
|
|
64
84
|
|
|
@@ -69,9 +89,9 @@ export const up = (pgm) => {
|
|
|
69
89
|
*/
|
|
70
90
|
export const down = (pgm) => {
|
|
71
91
|
pgm.sql(`
|
|
72
|
-
DROP TRIGGER IF EXISTS
|
|
73
|
-
ON
|
|
92
|
+
DROP TRIGGER IF EXISTS feature_flag_group_set_modified
|
|
93
|
+
ON flapjack.feature_flag_group;
|
|
74
94
|
`);
|
|
75
|
-
pgm.dropTable("
|
|
76
|
-
pgm.dropTable("
|
|
95
|
+
pgm.dropTable({ schema: "flapjack", name: "feature_flag_group_member" });
|
|
96
|
+
pgm.dropTable({ schema: "flapjack", name: "feature_flag_group" });
|
|
77
97
|
};
|