@loomcore/api 0.1.22 → 0.1.25
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/__tests__/common-test.utils.js +13 -23
- package/dist/__tests__/models/test-item.model.d.ts +1 -1
- package/dist/__tests__/postgres-test-migrations/004-create-test-users-table.migration.js +0 -1
- package/dist/__tests__/postgres.test-database.js +6 -2
- package/dist/__tests__/test-objects.d.ts +9 -41
- package/dist/__tests__/test-objects.js +98 -63
- package/dist/controllers/auth.controller.js +2 -2
- package/dist/databases/postgres/migrations/001-create-migrations-table.migration.js +18 -20
- package/dist/databases/postgres/migrations/002-create-organizations-table.migration.d.ts +1 -3
- package/dist/databases/postgres/migrations/002-create-organizations-table.migration.js +41 -48
- package/dist/databases/postgres/migrations/003-create-users-table.migration.js +42 -47
- package/dist/databases/postgres/migrations/004-create-refresh-tokens-table.migration.js +34 -37
- package/dist/databases/postgres/migrations/005-create-meta-org.migration.js +24 -23
- package/dist/databases/postgres/migrations/006-create-admin-user.migration.d.ts +4 -9
- package/dist/databases/postgres/migrations/006-create-admin-user.migration.js +14 -17
- package/dist/databases/postgres/migrations/007-create-roles-table.migration.d.ts +21 -0
- package/dist/databases/postgres/migrations/007-create-roles-table.migration.js +62 -0
- package/dist/databases/postgres/migrations/008-create-user-roles-table.migration.d.ts +21 -0
- package/dist/databases/postgres/migrations/008-create-user-roles-table.migration.js +65 -0
- package/dist/databases/postgres/migrations/009-create-features-table.migration.d.ts +21 -0
- package/dist/databases/postgres/migrations/009-create-features-table.migration.js +62 -0
- package/dist/databases/postgres/migrations/010-create-authorizations-table.migration.d.ts +21 -0
- package/dist/databases/postgres/migrations/010-create-authorizations-table.migration.js +74 -0
- package/dist/databases/postgres/migrations/011-create-admin-authorization.migration.d.ts +23 -0
- package/dist/databases/postgres/migrations/011-create-admin-authorization.migration.js +117 -0
- package/dist/databases/postgres/migrations/setup-for-auth.migration.d.ts +1 -1
- package/dist/databases/postgres/migrations/setup-for-auth.migration.js +43 -12
- package/dist/databases/postgres/migrations/setup-for-multitenant.migration.d.ts +1 -1
- package/dist/databases/postgres/migrations/setup-for-multitenant.migration.js +16 -6
- package/dist/databases/postgres/postgres.database.d.ts +1 -0
- package/dist/databases/postgres/postgres.database.js +61 -0
- package/dist/models/feature.model.d.ts +7 -0
- package/dist/models/feature.model.js +6 -0
- package/dist/models/refresh-token.model.d.ts +1 -1
- package/dist/models/role.model.d.ts +7 -0
- package/dist/models/role.model.js +6 -0
- package/dist/models/user-role.model.d.ts +8 -0
- package/dist/models/user-role.model.js +7 -0
- package/dist/services/auth.service.js +0 -3
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/user-service/user.service.d.ts +12 -0
- package/dist/services/user-service/user.service.js +65 -0
- package/package.json +6 -6
- package/dist/services/user.service.d.ts +0 -8
- package/dist/services/user.service.js +0 -22
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
|
+
import { doesTableExist } from "../utils/does-table-exist.util.js";
|
|
2
3
|
export class CreateUsersTableMigration {
|
|
3
4
|
client;
|
|
4
5
|
constructor(client) {
|
|
@@ -8,72 +9,66 @@ export class CreateUsersTableMigration {
|
|
|
8
9
|
async execute(_orgId) {
|
|
9
10
|
const _id = randomUUID().toString();
|
|
10
11
|
try {
|
|
11
|
-
await this.client.query(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
return { success: false, error: new Error(`Error creating users table: ${error.message}`) };
|
|
12
|
+
await this.client.query('BEGIN');
|
|
13
|
+
const tableExists = await doesTableExist(this.client, 'users');
|
|
14
|
+
if (!tableExists) {
|
|
15
|
+
await this.client.query(`
|
|
16
|
+
CREATE TABLE "users" (
|
|
17
|
+
"_id" VARCHAR(255) PRIMARY KEY,
|
|
18
|
+
"_orgId" VARCHAR(255),
|
|
19
|
+
"email" VARCHAR(255) NOT NULL,
|
|
20
|
+
"firstName" VARCHAR(255),
|
|
21
|
+
"lastName" VARCHAR(255),
|
|
22
|
+
"displayName" VARCHAR(255),
|
|
23
|
+
"password" VARCHAR(255) NOT NULL,
|
|
24
|
+
"_lastLoggedIn" TIMESTAMP,
|
|
25
|
+
"_lastPasswordChange" TIMESTAMP,
|
|
26
|
+
"_created" TIMESTAMP NOT NULL,
|
|
27
|
+
"_createdBy" VARCHAR(255) NOT NULL,
|
|
28
|
+
"_updated" TIMESTAMP NOT NULL,
|
|
29
|
+
"_updatedBy" VARCHAR(255) NOT NULL,
|
|
30
|
+
"_deleted" TIMESTAMP,
|
|
31
|
+
"_deletedBy" VARCHAR(255),
|
|
32
|
+
CONSTRAINT "fk_users_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE,
|
|
33
|
+
CONSTRAINT "uk_users_email" UNIQUE ("_orgId", "email")
|
|
34
|
+
)
|
|
35
|
+
`);
|
|
38
36
|
}
|
|
39
|
-
}
|
|
40
|
-
try {
|
|
41
37
|
const result = await this.client.query(`
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
|
|
39
|
+
VALUES ('${_id}', ${this.index}, TRUE, FALSE);
|
|
40
|
+
`);
|
|
45
41
|
if (result.rowCount === 0) {
|
|
42
|
+
await this.client.query('ROLLBACK');
|
|
46
43
|
return { success: false, error: new Error(`Error inserting migration ${this.index} to migrations table: No row returned`) };
|
|
47
44
|
}
|
|
45
|
+
await this.client.query('COMMIT');
|
|
46
|
+
return { success: true, error: null };
|
|
48
47
|
}
|
|
49
48
|
catch (error) {
|
|
50
|
-
|
|
49
|
+
await this.client.query('ROLLBACK');
|
|
50
|
+
return { success: false, error: new Error(`Error executing migration ${this.index}: ${error.message}`) };
|
|
51
51
|
}
|
|
52
|
-
return { success: true, error: null };
|
|
53
52
|
}
|
|
54
53
|
async revert() {
|
|
55
54
|
try {
|
|
56
|
-
|
|
55
|
+
await this.client.query('BEGIN');
|
|
56
|
+
await this.client.query(`
|
|
57
57
|
DROP TABLE "users";
|
|
58
58
|
`);
|
|
59
|
-
|
|
60
|
-
return { success: false, error: new Error(`Error dropping users table: No row returned`) };
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
return { success: false, error: new Error(`Error dropping users table: ${error.message}`) };
|
|
65
|
-
}
|
|
66
|
-
try {
|
|
67
|
-
const result = await this.client.query(`
|
|
59
|
+
const updateResult = await this.client.query(`
|
|
68
60
|
UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
|
|
69
61
|
`);
|
|
70
|
-
if (
|
|
62
|
+
if (updateResult.rowCount === 0) {
|
|
63
|
+
await this.client.query('ROLLBACK');
|
|
71
64
|
return { success: false, error: new Error(`Error updating migration record for index ${this.index}: No row returned`) };
|
|
72
65
|
}
|
|
66
|
+
await this.client.query('COMMIT');
|
|
67
|
+
return { success: true, error: null };
|
|
73
68
|
}
|
|
74
69
|
catch (error) {
|
|
75
|
-
|
|
70
|
+
await this.client.query('ROLLBACK');
|
|
71
|
+
return { success: false, error: new Error(`Error reverting migration ${this.index}: ${error.message}`) };
|
|
76
72
|
}
|
|
77
|
-
return { success: true, error: null };
|
|
78
73
|
}
|
|
79
74
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
|
+
import { doesTableExist } from "../utils/does-table-exist.util.js";
|
|
2
3
|
export class CreateRefreshTokenTableMigration {
|
|
3
4
|
client;
|
|
4
5
|
constructor(client) {
|
|
@@ -8,64 +9,60 @@ export class CreateRefreshTokenTableMigration {
|
|
|
8
9
|
async execute(_orgId) {
|
|
9
10
|
const _id = randomUUID().toString();
|
|
10
11
|
try {
|
|
11
|
-
await this.client.query(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
console.log(`Refresh token table already exists`);
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
return { success: false, error: new Error(`Error creating refresh token table: ${error.message}`) };
|
|
12
|
+
await this.client.query('BEGIN');
|
|
13
|
+
const tableExists = await doesTableExist(this.client, 'refreshTokens');
|
|
14
|
+
if (!tableExists) {
|
|
15
|
+
await this.client.query(`
|
|
16
|
+
CREATE TABLE "refreshTokens" (
|
|
17
|
+
"_id" VARCHAR(255) PRIMARY KEY,
|
|
18
|
+
"_orgId" VARCHAR(255),
|
|
19
|
+
"token" VARCHAR(255) NOT NULL,
|
|
20
|
+
"deviceId" VARCHAR(255) NOT NULL,
|
|
21
|
+
"userId" VARCHAR(255) NOT NULL,
|
|
22
|
+
"expiresOn" BIGINT NOT NULL,
|
|
23
|
+
"created" TIMESTAMP NOT NULL,
|
|
24
|
+
"createdBy" VARCHAR(255) NOT NULL
|
|
25
|
+
)
|
|
26
|
+
`);
|
|
30
27
|
}
|
|
31
|
-
}
|
|
32
|
-
try {
|
|
33
28
|
const result = await this.client.query(`
|
|
34
29
|
INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
|
|
35
30
|
VALUES ('${_id}', ${this.index}, TRUE, FALSE);
|
|
36
31
|
`);
|
|
37
32
|
if (result.rowCount === 0) {
|
|
33
|
+
await this.client.query('ROLLBACK');
|
|
38
34
|
return { success: false, error: new Error(`Error inserting migration ${this.index} to migrations table: No row returned`) };
|
|
39
35
|
}
|
|
36
|
+
await this.client.query('COMMIT');
|
|
37
|
+
return { success: true, error: null };
|
|
40
38
|
}
|
|
41
39
|
catch (error) {
|
|
42
|
-
|
|
40
|
+
await this.client.query('ROLLBACK');
|
|
41
|
+
return { success: false, error: new Error(`Error executing migration ${this.index}: ${error.message}`) };
|
|
43
42
|
}
|
|
44
|
-
return { success: true, error: null };
|
|
45
43
|
}
|
|
46
44
|
async revert() {
|
|
47
45
|
try {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
await this.client.query('BEGIN');
|
|
47
|
+
const tableExists = await doesTableExist(this.client, 'refreshTokens');
|
|
48
|
+
if (tableExists) {
|
|
49
|
+
await this.client.query(`
|
|
50
|
+
DROP TABLE "refreshTokens";
|
|
51
|
+
`);
|
|
53
52
|
}
|
|
54
|
-
|
|
55
|
-
catch (error) {
|
|
56
|
-
return { success: false, error: new Error(`Error dropping refresh token table: ${error.message}`) };
|
|
57
|
-
}
|
|
58
|
-
try {
|
|
59
|
-
const result = await this.client.query(`
|
|
53
|
+
const updateResult = await this.client.query(`
|
|
60
54
|
UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
|
|
61
55
|
`);
|
|
62
|
-
if (
|
|
56
|
+
if (updateResult.rowCount === 0) {
|
|
57
|
+
await this.client.query('ROLLBACK');
|
|
63
58
|
return { success: false, error: new Error(`Error updating migration record for index ${this.index}: No row returned`) };
|
|
64
59
|
}
|
|
60
|
+
await this.client.query('COMMIT');
|
|
61
|
+
return { success: true, error: null };
|
|
65
62
|
}
|
|
66
63
|
catch (error) {
|
|
67
|
-
|
|
64
|
+
await this.client.query('ROLLBACK');
|
|
65
|
+
return { success: false, error: new Error(`Error reverting migration ${this.index}: ${error.message}`) };
|
|
68
66
|
}
|
|
69
|
-
return { success: true, error: null };
|
|
70
67
|
}
|
|
71
68
|
}
|
|
@@ -12,52 +12,53 @@ export class CreateMetaOrgMigration {
|
|
|
12
12
|
async execute() {
|
|
13
13
|
const _id = randomUUID().toString();
|
|
14
14
|
try {
|
|
15
|
-
|
|
15
|
+
await this.client.query('BEGIN');
|
|
16
|
+
const orgResult = await this.client.query(`
|
|
16
17
|
INSERT INTO "organizations" ("_id", "name", "code", "status", "isMetaOrg", "_created", "_createdBy", "_updated", "_updatedBy")
|
|
17
|
-
VALUES ('${_id}', '${this.orgName}', '${this.orgCode}', 1, true, NOW(), 'system', NOW(), 'system')
|
|
18
|
-
|
|
18
|
+
VALUES ('${_id}', '${this.orgName}', '${this.orgCode}', 1, true, NOW(), 'system', NOW(), 'system');
|
|
19
|
+
`);
|
|
20
|
+
if (orgResult.rowCount === 0) {
|
|
21
|
+
await this.client.query('ROLLBACK');
|
|
19
22
|
return { success: false, error: new Error(`Error creating meta org: No row returned`) };
|
|
20
23
|
}
|
|
21
|
-
|
|
22
|
-
catch (error) {
|
|
23
|
-
return { success: false, error: new Error(`Error creating meta org: ${error.message}`) };
|
|
24
|
-
}
|
|
25
|
-
try {
|
|
26
|
-
const result = await this.client.query(`
|
|
24
|
+
const migrationResult = await this.client.query(`
|
|
27
25
|
INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
|
|
28
26
|
VALUES ('${_id}', ${this.index}, TRUE, FALSE);
|
|
29
27
|
`);
|
|
30
|
-
if (
|
|
28
|
+
if (migrationResult.rowCount === 0) {
|
|
29
|
+
await this.client.query('ROLLBACK');
|
|
31
30
|
return { success: false, error: new Error(`Error inserting migration ${this.index} to migrations table: No row returned`) };
|
|
32
31
|
}
|
|
32
|
+
await this.client.query('COMMIT');
|
|
33
|
+
return { success: true, metaOrgId: _id, error: null };
|
|
33
34
|
}
|
|
34
35
|
catch (error) {
|
|
35
|
-
|
|
36
|
+
await this.client.query('ROLLBACK');
|
|
37
|
+
return { success: false, error: new Error(`Error executing migration ${this.index}: ${error.message}`) };
|
|
36
38
|
}
|
|
37
|
-
return { success: true, metaOrgId: _id, error: null };
|
|
38
39
|
}
|
|
39
40
|
async revert() {
|
|
40
41
|
try {
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
await this.client.query('BEGIN');
|
|
43
|
+
const deleteResult = await this.client.query(`DELETE FROM "organizations" WHERE "isMetaOrg" = TRUE;`);
|
|
44
|
+
if (deleteResult.rowCount === 0) {
|
|
45
|
+
await this.client.query('ROLLBACK');
|
|
43
46
|
return { success: false, error: new Error(`Error reverting meta org: No row returned`) };
|
|
44
47
|
}
|
|
45
|
-
|
|
46
|
-
catch (error) {
|
|
47
|
-
return { success: false, error: new Error(`Error reverting meta org: ${error.message}`) };
|
|
48
|
-
}
|
|
49
|
-
try {
|
|
50
|
-
const result = await this.client.query(`
|
|
48
|
+
const updateResult = await this.client.query(`
|
|
51
49
|
UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
|
|
52
50
|
`);
|
|
53
|
-
if (
|
|
51
|
+
if (updateResult.rowCount === 0) {
|
|
52
|
+
await this.client.query('ROLLBACK');
|
|
54
53
|
return { success: false, error: new Error(`Error updating migration record for index ${this.index}: No row returned`) };
|
|
55
54
|
}
|
|
55
|
+
await this.client.query('COMMIT');
|
|
56
|
+
return { success: true, error: null };
|
|
56
57
|
}
|
|
57
58
|
catch (error) {
|
|
58
|
-
|
|
59
|
+
await this.client.query('ROLLBACK');
|
|
60
|
+
return { success: false, error: new Error(`Error reverting migration ${this.index}: ${error.message}`) };
|
|
59
61
|
}
|
|
60
|
-
return { success: true, error: null };
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
export default CreateMetaOrgMigration;
|
|
@@ -2,17 +2,12 @@ import { Client } from "pg";
|
|
|
2
2
|
import { IMigration } from "../index.js";
|
|
3
3
|
export declare class CreateAdminUserMigration implements IMigration {
|
|
4
4
|
private readonly client;
|
|
5
|
-
|
|
6
|
-
private readonly adminPassword;
|
|
7
|
-
private readonly _orgId?;
|
|
8
|
-
constructor(client: Client, adminEmail: string, adminPassword: string, _orgId?: string | undefined);
|
|
5
|
+
constructor(client: Client);
|
|
9
6
|
index: number;
|
|
10
|
-
execute(): Promise<{
|
|
7
|
+
execute(adminEmail?: string, adminPassword?: string): Promise<{
|
|
11
8
|
success: boolean;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
success: boolean;
|
|
15
|
-
error: null;
|
|
9
|
+
adminUserId: string | undefined;
|
|
10
|
+
error: Error | null;
|
|
16
11
|
}>;
|
|
17
12
|
revert(): Promise<{
|
|
18
13
|
success: boolean;
|
|
@@ -4,34 +4,31 @@ import { getSystemUserContext } from "@loomcore/common/models";
|
|
|
4
4
|
import { AuthService } from "../../../services/auth.service.js";
|
|
5
5
|
export class CreateAdminUserMigration {
|
|
6
6
|
client;
|
|
7
|
-
|
|
8
|
-
adminPassword;
|
|
9
|
-
_orgId;
|
|
10
|
-
constructor(client, adminEmail, adminPassword, _orgId) {
|
|
7
|
+
constructor(client) {
|
|
11
8
|
this.client = client;
|
|
12
|
-
this.adminEmail = adminEmail;
|
|
13
|
-
this.adminPassword = adminPassword;
|
|
14
|
-
this._orgId = _orgId;
|
|
15
9
|
}
|
|
16
10
|
index = 6;
|
|
17
|
-
async execute() {
|
|
11
|
+
async execute(adminEmail, adminPassword) {
|
|
18
12
|
const _id = randomUUID().toString();
|
|
13
|
+
const systemUserContext = getSystemUserContext();
|
|
14
|
+
let createdUser;
|
|
19
15
|
try {
|
|
20
16
|
const database = new PostgresDatabase(this.client);
|
|
21
17
|
const authService = new AuthService(database);
|
|
22
|
-
|
|
18
|
+
createdUser = await authService.createUser(systemUserContext, {
|
|
23
19
|
_id: _id,
|
|
24
|
-
_orgId:
|
|
25
|
-
email:
|
|
26
|
-
password:
|
|
20
|
+
_orgId: systemUserContext._orgId,
|
|
21
|
+
email: adminEmail,
|
|
22
|
+
password: adminPassword,
|
|
27
23
|
firstName: 'Admin',
|
|
28
24
|
lastName: 'User',
|
|
29
25
|
displayName: 'Admin User',
|
|
30
|
-
roles: ['admin'],
|
|
31
26
|
});
|
|
32
27
|
}
|
|
33
28
|
catch (error) {
|
|
34
|
-
return {
|
|
29
|
+
return {
|
|
30
|
+
success: false, adminUserId: undefined, error: new Error(`Error creating admin user: ${error.message}`)
|
|
31
|
+
};
|
|
35
32
|
}
|
|
36
33
|
try {
|
|
37
34
|
const result = await this.client.query(`
|
|
@@ -39,13 +36,13 @@ export class CreateAdminUserMigration {
|
|
|
39
36
|
VALUES ('${_id}', ${this.index}, TRUE, FALSE);
|
|
40
37
|
`);
|
|
41
38
|
if (result.rowCount === 0) {
|
|
42
|
-
return { success: false, error: new Error(`Error inserting migration ${this.index} to migrations table: No row returned`) };
|
|
39
|
+
return { success: false, adminUserId: undefined, error: new Error(`Error inserting migration ${this.index} to migrations table: No row returned`) };
|
|
43
40
|
}
|
|
44
41
|
}
|
|
45
42
|
catch (error) {
|
|
46
|
-
return { success: false, error: new Error(`Error inserting migration ${this.index} to migrations table: ${error.message}`) };
|
|
43
|
+
return { success: false, adminUserId: undefined, error: new Error(`Error inserting migration ${this.index} to migrations table: ${error.message}`) };
|
|
47
44
|
}
|
|
48
|
-
return { success: true, error: null };
|
|
45
|
+
return { success: true, adminUserId: createdUser?._id, error: null };
|
|
49
46
|
}
|
|
50
47
|
async revert() {
|
|
51
48
|
throw new Error('Not implemented');
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Client } from "pg";
|
|
2
|
+
import { IMigration } from "./migration.interface.js";
|
|
3
|
+
export declare class CreateRoleTableMigration implements IMigration {
|
|
4
|
+
private readonly client;
|
|
5
|
+
constructor(client: Client);
|
|
6
|
+
index: number;
|
|
7
|
+
execute(_orgId?: string): Promise<{
|
|
8
|
+
success: boolean;
|
|
9
|
+
error: Error;
|
|
10
|
+
} | {
|
|
11
|
+
success: boolean;
|
|
12
|
+
error: null;
|
|
13
|
+
}>;
|
|
14
|
+
revert(): Promise<{
|
|
15
|
+
success: boolean;
|
|
16
|
+
error: Error;
|
|
17
|
+
} | {
|
|
18
|
+
success: boolean;
|
|
19
|
+
error: null;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
import { doesTableExist } from "../utils/does-table-exist.util.js";
|
|
3
|
+
export class CreateRoleTableMigration {
|
|
4
|
+
client;
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
}
|
|
8
|
+
index = 7;
|
|
9
|
+
async execute(_orgId) {
|
|
10
|
+
const _id = randomUUID().toString();
|
|
11
|
+
try {
|
|
12
|
+
await this.client.query('BEGIN');
|
|
13
|
+
const tableExists = await doesTableExist(this.client, 'roles');
|
|
14
|
+
if (!tableExists) {
|
|
15
|
+
await this.client.query(`
|
|
16
|
+
CREATE TABLE "roles" (
|
|
17
|
+
"_id" VARCHAR(255) PRIMARY KEY,
|
|
18
|
+
"_orgId" VARCHAR(255),
|
|
19
|
+
"name" VARCHAR(255) NOT NULL,
|
|
20
|
+
CONSTRAINT "fk_roles_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE,
|
|
21
|
+
CONSTRAINT "uk_roles_name" UNIQUE ("_orgId", "name")
|
|
22
|
+
)
|
|
23
|
+
`);
|
|
24
|
+
}
|
|
25
|
+
const result = await this.client.query(`
|
|
26
|
+
INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
|
|
27
|
+
VALUES ('${_id}', ${this.index}, TRUE, FALSE);
|
|
28
|
+
`);
|
|
29
|
+
if (result.rowCount === 0) {
|
|
30
|
+
await this.client.query('ROLLBACK');
|
|
31
|
+
return { success: false, error: new Error(`Error inserting migration ${this.index} to migrations table: No row returned`) };
|
|
32
|
+
}
|
|
33
|
+
await this.client.query('COMMIT');
|
|
34
|
+
return { success: true, error: null };
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
await this.client.query('ROLLBACK');
|
|
38
|
+
return { success: false, error: new Error(`Error executing migration ${this.index}: ${error.message}`) };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async revert() {
|
|
42
|
+
try {
|
|
43
|
+
await this.client.query('BEGIN');
|
|
44
|
+
await this.client.query(`
|
|
45
|
+
DROP TABLE "roles";
|
|
46
|
+
`);
|
|
47
|
+
const updateResult = await this.client.query(`
|
|
48
|
+
UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
|
|
49
|
+
`);
|
|
50
|
+
if (updateResult.rowCount === 0) {
|
|
51
|
+
await this.client.query('ROLLBACK');
|
|
52
|
+
return { success: false, error: new Error(`Error updating migration record for index ${this.index}: No row returned`) };
|
|
53
|
+
}
|
|
54
|
+
await this.client.query('COMMIT');
|
|
55
|
+
return { success: true, error: null };
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
await this.client.query('ROLLBACK');
|
|
59
|
+
return { success: false, error: new Error(`Error reverting migration ${this.index}: ${error.message}`) };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Client } from "pg";
|
|
2
|
+
import { IMigration } from "./migration.interface.js";
|
|
3
|
+
export declare class CreateUserRolesTableMigration implements IMigration {
|
|
4
|
+
private readonly client;
|
|
5
|
+
constructor(client: Client);
|
|
6
|
+
index: number;
|
|
7
|
+
execute(_orgId?: string): Promise<{
|
|
8
|
+
success: boolean;
|
|
9
|
+
error: Error;
|
|
10
|
+
} | {
|
|
11
|
+
success: boolean;
|
|
12
|
+
error: null;
|
|
13
|
+
}>;
|
|
14
|
+
revert(): Promise<{
|
|
15
|
+
success: boolean;
|
|
16
|
+
error: Error;
|
|
17
|
+
} | {
|
|
18
|
+
success: boolean;
|
|
19
|
+
error: null;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
import { doesTableExist } from "../utils/does-table-exist.util.js";
|
|
3
|
+
export class CreateUserRolesTableMigration {
|
|
4
|
+
client;
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
}
|
|
8
|
+
index = 8;
|
|
9
|
+
async execute(_orgId) {
|
|
10
|
+
const _id = randomUUID().toString();
|
|
11
|
+
try {
|
|
12
|
+
await this.client.query('BEGIN');
|
|
13
|
+
const tableExists = await doesTableExist(this.client, 'user_roles');
|
|
14
|
+
if (!tableExists) {
|
|
15
|
+
await this.client.query(`
|
|
16
|
+
CREATE TABLE "user_roles" (
|
|
17
|
+
"_id" VARCHAR(255) PRIMARY KEY,
|
|
18
|
+
"_orgId" VARCHAR(255),
|
|
19
|
+
"_userId" VARCHAR(255) NOT NULL,
|
|
20
|
+
"_roleId" VARCHAR(255) NOT NULL,
|
|
21
|
+
CONSTRAINT "fk_user_roles_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE
|
|
22
|
+
CONSTRAINT "fk_user_roles_user" FOREIGN KEY ("_userId") REFERENCES "users"("_id") ON DELETE CASCADE,
|
|
23
|
+
CONSTRAINT "fk_user_roles_role" FOREIGN KEY ("_roleId") REFERENCES "roles"("_id") ON DELETE CASCADE,
|
|
24
|
+
CONSTRAINT "uk_user_roles" UNIQUE ("_orgId", "_userId", "_roleId")
|
|
25
|
+
)
|
|
26
|
+
`);
|
|
27
|
+
}
|
|
28
|
+
const result = await this.client.query(`
|
|
29
|
+
INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
|
|
30
|
+
VALUES ('${_id}', ${this.index}, TRUE, FALSE);
|
|
31
|
+
`);
|
|
32
|
+
if (result.rowCount === 0) {
|
|
33
|
+
await this.client.query('ROLLBACK');
|
|
34
|
+
return { success: false, error: new Error(`Error inserting migration ${this.index} to migrations table: No row returned`) };
|
|
35
|
+
}
|
|
36
|
+
await this.client.query('COMMIT');
|
|
37
|
+
return { success: true, error: null };
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
await this.client.query('ROLLBACK');
|
|
41
|
+
return { success: false, error: new Error(`Error executing migration ${this.index}: ${error.message}`) };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async revert() {
|
|
45
|
+
try {
|
|
46
|
+
await this.client.query('BEGIN');
|
|
47
|
+
await this.client.query(`
|
|
48
|
+
DROP TABLE "user_roles";
|
|
49
|
+
`);
|
|
50
|
+
const updateResult = await this.client.query(`
|
|
51
|
+
UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
|
|
52
|
+
`);
|
|
53
|
+
if (updateResult.rowCount === 0) {
|
|
54
|
+
await this.client.query('ROLLBACK');
|
|
55
|
+
return { success: false, error: new Error(`Error updating migration record for index ${this.index}: No row returned`) };
|
|
56
|
+
}
|
|
57
|
+
await this.client.query('COMMIT');
|
|
58
|
+
return { success: true, error: null };
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
await this.client.query('ROLLBACK');
|
|
62
|
+
return { success: false, error: new Error(`Error reverting migration ${this.index}: ${error.message}`) };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Client } from "pg";
|
|
2
|
+
import { IMigration } from "./migration.interface.js";
|
|
3
|
+
export declare class CreateFeaturesTableMigration implements IMigration {
|
|
4
|
+
private readonly client;
|
|
5
|
+
constructor(client: Client);
|
|
6
|
+
index: number;
|
|
7
|
+
execute(_orgId?: string): Promise<{
|
|
8
|
+
success: boolean;
|
|
9
|
+
error: Error;
|
|
10
|
+
} | {
|
|
11
|
+
success: boolean;
|
|
12
|
+
error: null;
|
|
13
|
+
}>;
|
|
14
|
+
revert(): Promise<{
|
|
15
|
+
success: boolean;
|
|
16
|
+
error: Error;
|
|
17
|
+
} | {
|
|
18
|
+
success: boolean;
|
|
19
|
+
error: null;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
import { doesTableExist } from "../utils/does-table-exist.util.js";
|
|
3
|
+
export class CreateFeaturesTableMigration {
|
|
4
|
+
client;
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
}
|
|
8
|
+
index = 9;
|
|
9
|
+
async execute(_orgId) {
|
|
10
|
+
const _id = randomUUID().toString();
|
|
11
|
+
try {
|
|
12
|
+
await this.client.query('BEGIN');
|
|
13
|
+
const tableExists = await doesTableExist(this.client, 'features');
|
|
14
|
+
if (!tableExists) {
|
|
15
|
+
await this.client.query(`
|
|
16
|
+
CREATE TABLE "features" (
|
|
17
|
+
"_id" VARCHAR(255) PRIMARY KEY,
|
|
18
|
+
"_orgId" VARCHAR(255),
|
|
19
|
+
"name" VARCHAR(255) NOT NULL,
|
|
20
|
+
CONSTRAINT "fk_features_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE,
|
|
21
|
+
CONSTRAINT "uk_features" UNIQUE ("_orgId", "name")
|
|
22
|
+
)
|
|
23
|
+
`);
|
|
24
|
+
}
|
|
25
|
+
const result = await this.client.query(`
|
|
26
|
+
INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
|
|
27
|
+
VALUES ('${_id}', ${this.index}, TRUE, FALSE);
|
|
28
|
+
`);
|
|
29
|
+
if (result.rowCount === 0) {
|
|
30
|
+
await this.client.query('ROLLBACK');
|
|
31
|
+
return { success: false, error: new Error(`Error inserting migration ${this.index} to migrations table: No row returned`) };
|
|
32
|
+
}
|
|
33
|
+
await this.client.query('COMMIT');
|
|
34
|
+
return { success: true, error: null };
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
await this.client.query('ROLLBACK');
|
|
38
|
+
return { success: false, error: new Error(`Error executing migration ${this.index}: ${error.message}`) };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async revert() {
|
|
42
|
+
try {
|
|
43
|
+
await this.client.query('BEGIN');
|
|
44
|
+
await this.client.query(`
|
|
45
|
+
DROP TABLE "features";
|
|
46
|
+
`);
|
|
47
|
+
const updateResult = await this.client.query(`
|
|
48
|
+
UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
|
|
49
|
+
`);
|
|
50
|
+
if (updateResult.rowCount === 0) {
|
|
51
|
+
await this.client.query('ROLLBACK');
|
|
52
|
+
return { success: false, error: new Error(`Error updating migration record for index ${this.index}: No row returned`) };
|
|
53
|
+
}
|
|
54
|
+
await this.client.query('COMMIT');
|
|
55
|
+
return { success: true, error: null };
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
await this.client.query('ROLLBACK');
|
|
59
|
+
return { success: false, error: new Error(`Error reverting migration ${this.index}: ${error.message}`) };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|