@loomcore/api 0.1.21 → 0.1.24
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 +96 -63
- package/dist/controllers/auth.controller.js +5 -6
- 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 +1 -2
- package/dist/databases/postgres/migrations/006-create-admin-user.migration.js +16 -7
- 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/setup-for-auth.migration.js +14 -5
- 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/models/refresh-token.model.d.ts +1 -1
- package/dist/services/auth.service.d.ts +3 -3
- package/dist/services/auth.service.js +13 -10
- package/dist/services/multi-tenant-api.service.js +1 -1
- package/package.json +6 -6
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
2
|
import jwt from 'jsonwebtoken';
|
|
3
|
-
import { getSystemUserContext } from '@loomcore/common/models';
|
|
4
3
|
import { Type } from '@sinclair/typebox';
|
|
5
4
|
import { JwtService } from '../services/jwt.service.js';
|
|
6
5
|
import { ApiController } from '../controllers/api.controller.js';
|
|
7
6
|
import { MultiTenantApiService } from '../services/multi-tenant-api.service.js';
|
|
8
7
|
import { Join } from '../databases/operations/join.operation.js';
|
|
9
8
|
import { OrganizationService } from '../services/organization.service.js';
|
|
10
|
-
import { IdNotFoundError } from '../errors/index.js';
|
|
11
9
|
import { AuthService, GenericApiService } from '../services/index.js';
|
|
12
10
|
import { ObjectId } from 'mongodb';
|
|
13
|
-
import {
|
|
11
|
+
import { getTestMetaOrg, getTestOrg, getTestMetaOrgUser, getTestMetaOrgUserContext } from './test-objects.js';
|
|
14
12
|
import { CategorySpec } from './models/category.model.js';
|
|
15
13
|
import { ProductSpec } from './models/product.model.js';
|
|
16
14
|
let deviceIdCookie;
|
|
@@ -33,9 +31,9 @@ async function createMetaOrg() {
|
|
|
33
31
|
throw new Error('OrganizationService not initialized. Call initialize() first.');
|
|
34
32
|
}
|
|
35
33
|
try {
|
|
36
|
-
const existingMetaOrg = await organizationService.
|
|
34
|
+
const existingMetaOrg = await organizationService.getMetaOrg(getTestMetaOrgUserContext());
|
|
37
35
|
if (!existingMetaOrg) {
|
|
38
|
-
const metaOrgInsertResult = await organizationService.create(
|
|
36
|
+
const metaOrgInsertResult = await organizationService.create(getTestMetaOrgUserContext(), getTestMetaOrg());
|
|
39
37
|
}
|
|
40
38
|
}
|
|
41
39
|
catch (error) {
|
|
@@ -48,7 +46,7 @@ async function deleteMetaOrg() {
|
|
|
48
46
|
return Promise.resolve();
|
|
49
47
|
}
|
|
50
48
|
try {
|
|
51
|
-
await organizationService.deleteMany(
|
|
49
|
+
await organizationService.deleteMany(getTestMetaOrgUserContext(), { filters: { isMetaOrg: { eq: true } } });
|
|
52
50
|
}
|
|
53
51
|
catch (error) {
|
|
54
52
|
console.log('Error deleting meta org:', error);
|
|
@@ -69,23 +67,15 @@ async function createTestUser() {
|
|
|
69
67
|
throw new Error('Database not initialized. Call initialize() first.');
|
|
70
68
|
}
|
|
71
69
|
try {
|
|
72
|
-
|
|
73
|
-
try {
|
|
74
|
-
existingMetaOrg = await organizationService.getMetaOrg(testMetaOrgUserContext);
|
|
75
|
-
}
|
|
76
|
-
catch (error) {
|
|
77
|
-
if (error instanceof IdNotFoundError) {
|
|
78
|
-
existingMetaOrg = null;
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
throw error;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
70
|
+
const existingMetaOrg = await organizationService.getMetaOrg(getTestMetaOrgUserContext());
|
|
84
71
|
if (!existingMetaOrg) {
|
|
85
|
-
await organizationService.create(
|
|
72
|
+
await organizationService.create(getTestMetaOrgUserContext(), getTestMetaOrg());
|
|
73
|
+
}
|
|
74
|
+
const existingTestOrg = await organizationService.findOne(getTestMetaOrgUserContext(), { filters: { _id: { eq: getTestOrg()._id } } });
|
|
75
|
+
if (!existingTestOrg) {
|
|
76
|
+
await organizationService.create(getTestMetaOrgUserContext(), getTestOrg());
|
|
86
77
|
}
|
|
87
|
-
const
|
|
88
|
-
const createdUser = await authService.createUser(systemUserContext, getTestMetaOrgUser());
|
|
78
|
+
const createdUser = await authService.createUser(getTestMetaOrgUserContext(), getTestMetaOrgUser());
|
|
89
79
|
if (!createdUser) {
|
|
90
80
|
throw new Error('Failed to create test user');
|
|
91
81
|
}
|
|
@@ -97,10 +87,10 @@ async function createTestUser() {
|
|
|
97
87
|
}
|
|
98
88
|
}
|
|
99
89
|
async function deleteTestUser() {
|
|
100
|
-
await authService.deleteById(
|
|
90
|
+
await authService.deleteById(getTestMetaOrgUserContext(), getTestMetaOrgUser()._id).catch((error) => {
|
|
101
91
|
return null;
|
|
102
92
|
});
|
|
103
|
-
await organizationService.deleteById(
|
|
93
|
+
await organizationService.deleteById(getTestMetaOrgUserContext(), getTestOrg()._id).catch((error) => {
|
|
104
94
|
return null;
|
|
105
95
|
});
|
|
106
96
|
}
|
|
@@ -7,6 +7,6 @@ export interface ITestItem extends IEntity, IAuditable {
|
|
|
7
7
|
export declare const TestItemSchema: import("@sinclair/typebox").TObject<{
|
|
8
8
|
name: import("@sinclair/typebox").TString;
|
|
9
9
|
value: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
10
|
-
eventDate: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").
|
|
10
|
+
eventDate: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TTransform<import("@sinclair/typebox").TString, Date>>;
|
|
11
11
|
}>;
|
|
12
12
|
export declare const TestItemSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
|
|
@@ -6,6 +6,7 @@ import { setupDatabaseForMultitenant } from '../databases/postgres/migrations/se
|
|
|
6
6
|
import { setupDatabaseForAuth } from '../databases/postgres/migrations/setup-for-auth.migration.js';
|
|
7
7
|
import { runTestMigrations } from './postgres-test-migrations/run-test-migrations.js';
|
|
8
8
|
import { PostgresDatabase } from '../databases/postgres/postgres.database.js';
|
|
9
|
+
import { getTestMetaOrg, setTestMetaOrgId } from './test-objects.js';
|
|
9
10
|
import { getSystemUserContext } from '@loomcore/common/models';
|
|
10
11
|
export class TestPostgresDatabase {
|
|
11
12
|
database = null;
|
|
@@ -29,10 +30,13 @@ export class TestPostgresDatabase {
|
|
|
29
30
|
const testDatabase = new PostgresDatabase(postgresClient);
|
|
30
31
|
this.database = testDatabase;
|
|
31
32
|
this.postgresClient = postgresClient;
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
const metaOrg = getTestMetaOrg();
|
|
34
|
+
const multitenantResult = await setupDatabaseForMultitenant(postgresClient, metaOrg.name, metaOrg.code);
|
|
35
|
+
let success = multitenantResult.success;
|
|
36
|
+
if (!success || !multitenantResult.metaOrgId) {
|
|
34
37
|
throw new Error('Failed to setup for multitenant');
|
|
35
38
|
}
|
|
39
|
+
setTestMetaOrgId(multitenantResult.metaOrgId);
|
|
36
40
|
await initSystemUserContext(this.database);
|
|
37
41
|
success = (await setupDatabaseForAuth(postgresClient, adminUsername || 'admin', adminPassword || 'password')).success;
|
|
38
42
|
if (!success) {
|
|
@@ -1,41 +1,9 @@
|
|
|
1
|
-
import { IOrganization, IUserContext } from "@loomcore/common/models";
|
|
2
|
-
export declare
|
|
3
|
-
export declare function
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
_lastLoggedIn?: Date;
|
|
11
|
-
_lastPasswordChange?: Date;
|
|
12
|
-
_created: Date;
|
|
13
|
-
_createdBy: string;
|
|
14
|
-
_updated: Date;
|
|
15
|
-
_updatedBy: string;
|
|
16
|
-
_deleted?: Date;
|
|
17
|
-
_deletedBy?: string;
|
|
18
|
-
_id: string;
|
|
19
|
-
_orgId?: string;
|
|
20
|
-
};
|
|
21
|
-
export declare const testMetaOrgUserContext: IUserContext;
|
|
22
|
-
export declare const testOrg: IOrganization;
|
|
23
|
-
export declare function getTestOrgUser(): {
|
|
24
|
-
email: string;
|
|
25
|
-
firstName?: string;
|
|
26
|
-
lastName?: string;
|
|
27
|
-
displayName?: string;
|
|
28
|
-
password: string;
|
|
29
|
-
roles?: string[];
|
|
30
|
-
_lastLoggedIn?: Date;
|
|
31
|
-
_lastPasswordChange?: Date;
|
|
32
|
-
_created: Date;
|
|
33
|
-
_createdBy: string;
|
|
34
|
-
_updated: Date;
|
|
35
|
-
_updatedBy: string;
|
|
36
|
-
_deleted?: Date;
|
|
37
|
-
_deletedBy?: string;
|
|
38
|
-
_id: string;
|
|
39
|
-
_orgId?: string;
|
|
40
|
-
};
|
|
41
|
-
export declare const testOrgUserContext: IUserContext;
|
|
1
|
+
import { IOrganization, IUser, IUserContext } from "@loomcore/common/models";
|
|
2
|
+
export declare let TEST_META_ORG_ID: string;
|
|
3
|
+
export declare function setTestMetaOrgId(metaOrgId: string): void;
|
|
4
|
+
export declare function getTestMetaOrg(): IOrganization;
|
|
5
|
+
export declare function getTestMetaOrgUser(): IUser;
|
|
6
|
+
export declare function getTestMetaOrgUserContext(): IUserContext;
|
|
7
|
+
export declare function getTestOrg(): IOrganization;
|
|
8
|
+
export declare function getTestOrgUser(): IUser;
|
|
9
|
+
export declare function getTestOrgUserContext(): IUserContext;
|
|
@@ -1,67 +1,100 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
roles: ['user'],
|
|
20
|
-
_orgId: testMetaOrg._id,
|
|
21
|
-
_created: new Date(),
|
|
22
|
-
_createdBy: 'system',
|
|
23
|
-
_lastLoggedIn: new Date(),
|
|
24
|
-
_lastPasswordChange: new Date(),
|
|
25
|
-
_updated: new Date(),
|
|
26
|
-
_updatedBy: 'system',
|
|
27
|
-
};
|
|
1
|
+
export let TEST_META_ORG_ID = '69261691f936c45f85da24d0';
|
|
2
|
+
export function setTestMetaOrgId(metaOrgId) {
|
|
3
|
+
TEST_META_ORG_ID = metaOrgId;
|
|
4
|
+
}
|
|
5
|
+
export function getTestMetaOrg() {
|
|
6
|
+
return {
|
|
7
|
+
_id: TEST_META_ORG_ID,
|
|
8
|
+
name: 'Test Meta Organization',
|
|
9
|
+
code: 'test-meta-org',
|
|
10
|
+
status: 1,
|
|
11
|
+
isMetaOrg: true,
|
|
12
|
+
_created: new Date(),
|
|
13
|
+
_createdBy: 'system',
|
|
14
|
+
_updated: new Date(),
|
|
15
|
+
_updatedBy: 'system',
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
;
|
|
28
19
|
export function getTestMetaOrgUser() {
|
|
29
|
-
return {
|
|
20
|
+
return {
|
|
21
|
+
_id: '69261672f48fb7bf76e54dfb',
|
|
22
|
+
_orgId: getTestMetaOrg()._id,
|
|
23
|
+
email: 'test@example.com',
|
|
24
|
+
password: 'testpassword',
|
|
25
|
+
firstName: 'Test',
|
|
26
|
+
lastName: 'User',
|
|
27
|
+
displayName: 'Test User',
|
|
28
|
+
authorizations: [{
|
|
29
|
+
_id: '6939c54e57a1c6576a40c590',
|
|
30
|
+
_orgId: getTestMetaOrg()._id,
|
|
31
|
+
feature: 'metaorgUser',
|
|
32
|
+
config: {},
|
|
33
|
+
_created: new Date(),
|
|
34
|
+
_createdBy: 'system',
|
|
35
|
+
_updated: new Date(),
|
|
36
|
+
_updatedBy: 'system',
|
|
37
|
+
}],
|
|
38
|
+
_created: new Date(),
|
|
39
|
+
_createdBy: 'system',
|
|
40
|
+
_lastLoggedIn: new Date(),
|
|
41
|
+
_updated: new Date(),
|
|
42
|
+
_updatedBy: 'system',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
;
|
|
46
|
+
export function getTestMetaOrgUserContext() {
|
|
47
|
+
return {
|
|
48
|
+
user: getTestMetaOrgUser(),
|
|
49
|
+
_orgId: getTestMetaOrg()._id,
|
|
50
|
+
};
|
|
30
51
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const testOrgUser = {
|
|
47
|
-
_id: '6926167d06c0073a778a1250',
|
|
48
|
-
email: 'test-org-user@example.com',
|
|
49
|
-
password: 'testpassword',
|
|
50
|
-
firstName: 'Test',
|
|
51
|
-
lastName: 'User',
|
|
52
|
-
displayName: 'Test User',
|
|
53
|
-
roles: ['user'],
|
|
54
|
-
_orgId: testOrg._id,
|
|
55
|
-
_created: new Date(),
|
|
56
|
-
_createdBy: 'system',
|
|
57
|
-
_lastLoggedIn: new Date(),
|
|
58
|
-
_updated: new Date(),
|
|
59
|
-
_updatedBy: 'system',
|
|
60
|
-
};
|
|
52
|
+
;
|
|
53
|
+
export function getTestOrg() {
|
|
54
|
+
return {
|
|
55
|
+
_id: '6926167d06c0073a778a124f',
|
|
56
|
+
name: 'Test Organization',
|
|
57
|
+
code: 'test-org',
|
|
58
|
+
status: 1,
|
|
59
|
+
isMetaOrg: false,
|
|
60
|
+
_created: new Date(),
|
|
61
|
+
_createdBy: 'system',
|
|
62
|
+
_updated: new Date(),
|
|
63
|
+
_updatedBy: 'system',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
;
|
|
61
67
|
export function getTestOrgUser() {
|
|
62
|
-
return {
|
|
68
|
+
return {
|
|
69
|
+
_id: '6926167d06c0073a778a1250',
|
|
70
|
+
_orgId: getTestOrg()._id,
|
|
71
|
+
email: 'test-org-user@example.com',
|
|
72
|
+
password: 'testpassword',
|
|
73
|
+
firstName: 'Test',
|
|
74
|
+
lastName: 'User',
|
|
75
|
+
displayName: 'Test User',
|
|
76
|
+
authorizations: [{
|
|
77
|
+
_id: '6939c54e57a1c6576a40c591',
|
|
78
|
+
_orgId: getTestOrg()._id,
|
|
79
|
+
feature: 'testOrgUser',
|
|
80
|
+
config: {},
|
|
81
|
+
_created: new Date(),
|
|
82
|
+
_createdBy: 'system',
|
|
83
|
+
_updated: new Date(),
|
|
84
|
+
_updatedBy: 'system',
|
|
85
|
+
}],
|
|
86
|
+
_created: new Date(),
|
|
87
|
+
_createdBy: 'system',
|
|
88
|
+
_lastLoggedIn: new Date(),
|
|
89
|
+
_updated: new Date(),
|
|
90
|
+
_updatedBy: 'system',
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
;
|
|
94
|
+
export function getTestOrgUserContext() {
|
|
95
|
+
return {
|
|
96
|
+
user: getTestOrgUser(),
|
|
97
|
+
_orgId: getTestOrg()._id,
|
|
98
|
+
};
|
|
63
99
|
}
|
|
64
|
-
|
|
65
|
-
user: getTestOrgUser(),
|
|
66
|
-
_orgId: testOrg._id,
|
|
67
|
-
};
|
|
100
|
+
;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LoginResponseSpec, TokenResponseSpec, UserSpec, PublicUserSchema,
|
|
1
|
+
import { LoginResponseSpec, TokenResponseSpec, UserSpec, PublicUserSchema, passwordValidator, PublicUserContextSpec, } from '@loomcore/common/models';
|
|
2
2
|
import { entityUtils } from '@loomcore/common/utils';
|
|
3
3
|
import { BadRequestError, UnauthenticatedError } from '../errors/index.js';
|
|
4
4
|
import { isAuthenticated } from '../middleware/index.js';
|
|
@@ -38,13 +38,12 @@ export class AuthController {
|
|
|
38
38
|
apiUtils.apiResponse(res, 201, { data: user || undefined }, UserSpec, PublicUserSchema);
|
|
39
39
|
}
|
|
40
40
|
async requestTokenUsingRefreshToken(req, res, next) {
|
|
41
|
-
const userContext = req.userContext;
|
|
42
41
|
const refreshToken = req.query.refreshToken;
|
|
43
|
-
if (!
|
|
44
|
-
throw new BadRequestError('Missing required fields:
|
|
42
|
+
if (!refreshToken || typeof refreshToken !== 'string') {
|
|
43
|
+
throw new BadRequestError('Missing required fields: refreshToken is required.');
|
|
45
44
|
}
|
|
46
45
|
const deviceId = this.authService.getDeviceIdFromCookie(req);
|
|
47
|
-
const tokens = await this.authService.requestTokenUsingRefreshToken(
|
|
46
|
+
const tokens = await this.authService.requestTokenUsingRefreshToken(refreshToken, deviceId);
|
|
48
47
|
if (tokens) {
|
|
49
48
|
apiUtils.apiResponse(res, 200, { data: tokens }, TokenResponseSpec);
|
|
50
49
|
}
|
|
@@ -54,7 +53,7 @@ export class AuthController {
|
|
|
54
53
|
}
|
|
55
54
|
async getUserContext(req, res, next) {
|
|
56
55
|
const userContext = req.userContext;
|
|
57
|
-
apiUtils.apiResponse(res, 200, { data: userContext },
|
|
56
|
+
apiUtils.apiResponse(res, 200, { data: userContext }, PublicUserContextSpec);
|
|
58
57
|
}
|
|
59
58
|
afterAuth(req, res, loginResponse) {
|
|
60
59
|
console.log('in afterAuth');
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
|
+
import { doesTableExist } from "../utils/does-table-exist.util.js";
|
|
2
3
|
export class CreateMigrationTableMigration {
|
|
3
4
|
client;
|
|
4
5
|
constructor(client) {
|
|
@@ -8,42 +9,39 @@ export class CreateMigrationTableMigration {
|
|
|
8
9
|
async execute() {
|
|
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
|
-
return { success: false, error: new Error(`Error creating migrations table: ${error.message}`) };
|
|
12
|
+
await this.client.query('BEGIN');
|
|
13
|
+
const tableExists = await doesTableExist(this.client, 'migrations');
|
|
14
|
+
if (!tableExists) {
|
|
15
|
+
await this.client.query(`
|
|
16
|
+
CREATE TABLE "migrations" (
|
|
17
|
+
"_id" VARCHAR(255) PRIMARY KEY,
|
|
18
|
+
"index" INTEGER NOT NULL UNIQUE,
|
|
19
|
+
"hasRun" BOOLEAN NOT NULL,
|
|
20
|
+
"reverted" BOOLEAN NOT NULL
|
|
21
|
+
)
|
|
22
|
+
`);
|
|
23
23
|
}
|
|
24
|
-
}
|
|
25
|
-
try {
|
|
26
24
|
const result = await this.client.query(`
|
|
27
25
|
INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
|
|
28
26
|
VALUES ('${_id}', ${this.index}, TRUE, FALSE);
|
|
29
27
|
`);
|
|
30
28
|
if (result.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, 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, error: null };
|
|
38
39
|
}
|
|
39
40
|
async revert() {
|
|
40
41
|
try {
|
|
41
|
-
|
|
42
|
+
await this.client.query(`
|
|
42
43
|
DROP TABLE "migrations";
|
|
43
44
|
`);
|
|
44
|
-
if (result.rowCount === 0) {
|
|
45
|
-
return { success: false, error: new Error(`Error dropping migrations table: No row returned`) };
|
|
46
|
-
}
|
|
47
45
|
}
|
|
48
46
|
catch (error) {
|
|
49
47
|
return { success: false, error: new Error(`Error reverting migration ${this.index} from migrations table: ${error.message}`) };
|
|
@@ -2,9 +2,7 @@ import { Client } from "pg";
|
|
|
2
2
|
import { IMigration } from "./migration.interface.js";
|
|
3
3
|
export declare class CreateOrganizationsTableMigration implements IMigration {
|
|
4
4
|
private readonly client;
|
|
5
|
-
|
|
6
|
-
private readonly orgCode;
|
|
7
|
-
constructor(client: Client, orgName: string, orgCode: string);
|
|
5
|
+
constructor(client: Client);
|
|
8
6
|
index: number;
|
|
9
7
|
execute(): Promise<{
|
|
10
8
|
success: boolean;
|
|
@@ -1,83 +1,76 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
|
+
import { doesTableExist } from "../utils/does-table-exist.util.js";
|
|
2
3
|
export class CreateOrganizationsTableMigration {
|
|
3
4
|
client;
|
|
4
|
-
|
|
5
|
-
orgCode;
|
|
6
|
-
constructor(client, orgName, orgCode) {
|
|
5
|
+
constructor(client) {
|
|
7
6
|
this.client = client;
|
|
8
|
-
this.orgName = orgName;
|
|
9
|
-
this.orgCode = orgCode;
|
|
10
7
|
}
|
|
11
8
|
index = 2;
|
|
12
9
|
async execute() {
|
|
13
10
|
const _id = randomUUID().toString();
|
|
14
11
|
try {
|
|
15
|
-
await this.client.query(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
console.log(`Organization table already exists`);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
return { success: false, error: new Error(`Error creating organization table: ${error.message}`) };
|
|
12
|
+
await this.client.query('BEGIN');
|
|
13
|
+
const tableExists = await doesTableExist(this.client, 'organizations');
|
|
14
|
+
if (!tableExists) {
|
|
15
|
+
await this.client.query(`
|
|
16
|
+
CREATE TABLE "organizations" (
|
|
17
|
+
"_id" VARCHAR(255) PRIMARY KEY,
|
|
18
|
+
"name" VARCHAR(255) NOT NULL UNIQUE,
|
|
19
|
+
"code" VARCHAR(255) NOT NULL UNIQUE,
|
|
20
|
+
"description" TEXT,
|
|
21
|
+
"status" INTEGER NOT NULL,
|
|
22
|
+
"isMetaOrg" BOOLEAN NOT NULL,
|
|
23
|
+
"authToken" TEXT,
|
|
24
|
+
"_created" TIMESTAMP NOT NULL,
|
|
25
|
+
"_createdBy" VARCHAR(255) NOT NULL,
|
|
26
|
+
"_updated" TIMESTAMP NOT NULL,
|
|
27
|
+
"_updatedBy" VARCHAR(255) NOT NULL,
|
|
28
|
+
"_deleted" TIMESTAMP,
|
|
29
|
+
"_deletedBy" VARCHAR(255)
|
|
30
|
+
)
|
|
31
|
+
`);
|
|
39
32
|
}
|
|
40
|
-
}
|
|
41
|
-
try {
|
|
42
33
|
const result = await this.client.query(`
|
|
43
34
|
INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
|
|
44
35
|
VALUES ('${_id}', ${this.index}, TRUE, FALSE);
|
|
45
36
|
`);
|
|
46
37
|
if (result.rowCount === 0) {
|
|
38
|
+
await this.client.query('ROLLBACK');
|
|
47
39
|
return { success: false, error: new Error(`Error inserting migration ${this.index} to migrations table: No row returned`) };
|
|
48
40
|
}
|
|
41
|
+
await this.client.query('COMMIT');
|
|
42
|
+
return { success: true, error: null };
|
|
49
43
|
}
|
|
50
44
|
catch (error) {
|
|
51
|
-
|
|
45
|
+
await this.client.query('ROLLBACK');
|
|
46
|
+
return { success: false, error: new Error(`Error executing migration ${this.index}: ${error.message}`) };
|
|
52
47
|
}
|
|
53
|
-
return { success: true, error: null };
|
|
54
48
|
}
|
|
55
49
|
async revert() {
|
|
56
50
|
try {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
51
|
+
await this.client.query('BEGIN');
|
|
52
|
+
const tableExists = await doesTableExist(this.client, 'organizations');
|
|
53
|
+
if (tableExists) {
|
|
54
|
+
await this.client.query(`
|
|
55
|
+
DROP TABLE "organizations";
|
|
56
|
+
`);
|
|
62
57
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return { success: false, error: new Error(`Error dropping organizations table: ${error.message}`) };
|
|
66
|
-
}
|
|
67
|
-
try {
|
|
68
|
-
const result = await this.client.query(`
|
|
69
|
-
Update "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
|
|
58
|
+
const updateResult = await this.client.query(`
|
|
59
|
+
UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
|
|
70
60
|
`);
|
|
71
|
-
if (
|
|
61
|
+
if (updateResult.rowCount === 0) {
|
|
62
|
+
await this.client.query('ROLLBACK');
|
|
72
63
|
return {
|
|
73
64
|
success: false, error: new Error(`Error updating migration record for index ${this.index}: Migration record not found.
|
|
74
65
|
Migration index: ${this.index}`)
|
|
75
66
|
};
|
|
76
67
|
}
|
|
68
|
+
await this.client.query('COMMIT');
|
|
69
|
+
return { success: true, error: null };
|
|
77
70
|
}
|
|
78
71
|
catch (error) {
|
|
79
|
-
|
|
72
|
+
await this.client.query('ROLLBACK');
|
|
73
|
+
return { success: false, error: new Error(`Error reverting migration ${this.index}: ${error.message}`) };
|
|
80
74
|
}
|
|
81
|
-
return { success: true, error: null };
|
|
82
75
|
}
|
|
83
76
|
}
|