@vida-global/core 1.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.
- package/README.md +9 -0
- package/index.js +17 -0
- package/lib/active_record/README.md +205 -0
- package/lib/active_record/baseRecord.js +112 -0
- package/lib/active_record/db/connection.js +128 -0
- package/lib/active_record/db/connectionConfiguration.js +114 -0
- package/lib/active_record/db/importSchema.js +4 -0
- package/lib/active_record/db/migration.js +132 -0
- package/lib/active_record/db/migrationTemplate.js +8 -0
- package/lib/active_record/db/migrationVersion.js +68 -0
- package/lib/active_record/db/migrator.js +169 -0
- package/lib/active_record/db/queryInterface.js +47 -0
- package/lib/active_record/db/schema.js +113 -0
- package/lib/active_record/index.js +6 -0
- package/lib/active_record/utils.js +43 -0
- package/lib/http/README.md +32 -0
- package/lib/http/client.js +129 -0
- package/lib/http/error.js +34 -0
- package/lib/logger/README.md +2 -0
- package/lib/logger/index.js +16 -0
- package/lib/release/develop.js +27 -0
- package/lib/release/git.js +86 -0
- package/lib/release/increment.js +56 -0
- package/lib/release/index.js +10 -0
- package/lib/release/release.js +30 -0
- package/lib/release/utils.js +44 -0
- package/lib/server/README.md +37 -0
- package/lib/server/index.js +9 -0
- package/lib/server/server.js +359 -0
- package/lib/server/serverController.js +344 -0
- package/lib/server/systemController.js +23 -0
- package/package.json +37 -0
- package/scripts/active_record/migrate.js +30 -0
- package/scripts/release.js +62 -0
- package/test/active_record/baseRecord.test.js +179 -0
- package/test/active_record/db/connection.test.js +221 -0
- package/test/active_record/db/connectionConfiguration.test.js +184 -0
- package/test/active_record/db/migrator.test.js +266 -0
- package/test/active_record/db/queryInterface.test.js +66 -0
- package/test/http/client.test.js +271 -0
- package/test/http/error.test.js +71 -0
- package/test/release/develop.test.js +57 -0
- package/test/release/git.test.js +189 -0
- package/test/release/increment.test.js +145 -0
- package/test/release/release.test.js +72 -0
- package/test/release/utils.test.js +148 -0
- package/test/server/helpers/controllers/barController.js +9 -0
- package/test/server/helpers/controllers/fooController.js +48 -0
- package/test/server/helpers/controllers/sub/bazController.js +10 -0
- package/test/server/helpers/server.js +14 -0
- package/test/server/server.test.js +188 -0
- package/test/server/serverController.test.js +251 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const { VidaServerController } = require('./serverController');
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class SystemController extends VidaServerController {
|
|
5
|
+
|
|
6
|
+
getHealthCheck() {
|
|
7
|
+
this.render({});
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
getIndex() {
|
|
12
|
+
this.render('Hello World');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
static get routes() {
|
|
17
|
+
return {getIndex: '/'};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
module.exports = { SystemController };
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vida-global/core",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Core libraries for supporting Vida development",
|
|
5
|
+
"author": "",
|
|
6
|
+
"license": "ISC",
|
|
7
|
+
"main": "index.js",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules node_modules/jest/bin/jest.js"
|
|
10
|
+
},
|
|
11
|
+
"jest": {
|
|
12
|
+
"collectCoverage": true,
|
|
13
|
+
"coveragePathIgnorePatterns": [
|
|
14
|
+
"/helpers/"
|
|
15
|
+
],
|
|
16
|
+
"setupFilesAfterEnv": ["jest-extended/all"]
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"commander": "^13.1.0",
|
|
20
|
+
"express": "^4.21.2",
|
|
21
|
+
"mustache-express": "^1.2.8",
|
|
22
|
+
"pg": "^8.16.3",
|
|
23
|
+
"pino": "^9.6.0",
|
|
24
|
+
"pino-http": "^10.4.0",
|
|
25
|
+
"pino-pretty": "^13.0.0",
|
|
26
|
+
"response-time": "^2.3.3",
|
|
27
|
+
"sequelize": "^6.37.7",
|
|
28
|
+
"sequelize-cli": "^6.6.3",
|
|
29
|
+
"socket.io": "^4.4.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"jest": "^29.6.2",
|
|
33
|
+
"jest-express": "^1.12.0",
|
|
34
|
+
"jest-extended": "^7.0.0",
|
|
35
|
+
"@vida-global/test-helpers": "^1.0.1"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const migration = require('../../lib/active_record/db/migration');
|
|
2
|
+
const { Command } = require('commander');
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const program = new Command();
|
|
6
|
+
program.name('Active Record Migration')
|
|
7
|
+
.description('A CLI for generating and running Active Record migrations')
|
|
8
|
+
.version('1.0.0');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
program.command('create_migration')
|
|
12
|
+
.argument('<Description>', 'Description of your migration')
|
|
13
|
+
.option('--databaseId <databaseId>', 'databaseId from db/config.js')
|
|
14
|
+
.action((migrationDescription, options) => {
|
|
15
|
+
migration.generateMigrationFile(migrationDescription, options.databaseId);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
program.command('migrate')
|
|
20
|
+
.action(async () => {
|
|
21
|
+
await migration.runMigrations();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
program.command('rollback')
|
|
25
|
+
.action(async () => {
|
|
26
|
+
await migration.rollbackMigration();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
program.parse();
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const Release = require('../lib/release');
|
|
2
|
+
const commander = require('commander');
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
function validateIssueNumber(val) {
|
|
6
|
+
const issueNumber = parseInt(val, 10);
|
|
7
|
+
if (isNaN(issueNumber)) {
|
|
8
|
+
throw new commander.InvalidArgumentError('Invalid issue number');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return issueNumber;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
function validateProjectType(val) {
|
|
16
|
+
const types = ['bugfix', 'chore', 'feature', 'hotfix', 'refactor'];
|
|
17
|
+
if (!types.includes(val)) {
|
|
18
|
+
throw new commander.InvalidArgumentError(`must be one of: ${types.join(', ')}`);
|
|
19
|
+
}
|
|
20
|
+
return val;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
function validateVersionType(val) {
|
|
25
|
+
const types = ['major', 'minor', 'point'];
|
|
26
|
+
if (!types.includes(val)) {
|
|
27
|
+
throw new commander.InvalidArgumentError(`must be one of: ${types.join(', ')}`);
|
|
28
|
+
}
|
|
29
|
+
return val;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
const program = new commander.Command();
|
|
34
|
+
program.name('Vida Release')
|
|
35
|
+
.description('A CLI for generating vida releases')
|
|
36
|
+
.version('1.0.0');
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
program.command('increment')
|
|
40
|
+
.argument('<type>', 'version number to increment', validateVersionType)
|
|
41
|
+
.action(async (type) => {
|
|
42
|
+
await Release.increment(type);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
program.command('production')
|
|
47
|
+
.argument('[version]', 'optional version release')
|
|
48
|
+
.action(async (version) => {
|
|
49
|
+
await Release.release('staging', version);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
program.command('develop')
|
|
54
|
+
.requiredOption('-i, --issue <issueNumber>', 'Must provide an issue number', validateIssueNumber)
|
|
55
|
+
.option('-t, --type [projectType]', 'Project type', validateProjectType, 'feature')
|
|
56
|
+
.option('-s, --source [sourceBranch]', 'Branch to copy')
|
|
57
|
+
.argument('<description...>', 'a description of your project')
|
|
58
|
+
.action(async (description, { issue, type, source }) => {
|
|
59
|
+
await Release.develop(type, issue, description.join(' '), source);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
program.parse();
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
const { BaseRecord } = require('../../lib/active_record/baseRecord');
|
|
2
|
+
const { Connection} = require('../../lib/active_record/db/connection');
|
|
3
|
+
const { ConnectionConfiguration } = require('../../lib/active_record/db/connectionConfiguration');
|
|
4
|
+
const { getActiveRecordSchema } = require('../../lib/active_record/db/schema');
|
|
5
|
+
const importSchema = require('../../lib/active_record/db/importSchema');
|
|
6
|
+
const { Model, Sequelize } = require('sequelize');
|
|
7
|
+
const TestHelpers = require('@vida-global/test-helpers');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const connectionConfig = {database: ' ', host: ' ', password: ' ', username: ' '};
|
|
11
|
+
const configSpy = jest.spyOn(ConnectionConfiguration, '_fetchAllConfigs');
|
|
12
|
+
configSpy.mockImplementation(() => ({default: {test: connectionConfig}}));
|
|
13
|
+
|
|
14
|
+
const mockSequelize = new (class MockSequelize {})();
|
|
15
|
+
const connectionSpy = jest.spyOn(Connection.prototype, '_sequelize', 'get');
|
|
16
|
+
connectionSpy.mockImplementation(() => mockSequelize);
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
jest.mock('sequelize', () => {
|
|
20
|
+
class MockModel {
|
|
21
|
+
static init = jest.fn()
|
|
22
|
+
static findByPk = jest.fn();
|
|
23
|
+
static findAll = jest.fn();
|
|
24
|
+
}
|
|
25
|
+
const TestHelpers = require('@vida-global/test-helpers');
|
|
26
|
+
const dataTypeKey1 = TestHelpers.Faker.Text.randomString();
|
|
27
|
+
const dataTypeValue1 = TestHelpers.Faker.Text.randomString();
|
|
28
|
+
const dataTypeKey2 = TestHelpers.Faker.Text.randomString();
|
|
29
|
+
const dataTypeValue2 = TestHelpers.Faker.Text.randomString();
|
|
30
|
+
const Sequelize = {DataTypes: {
|
|
31
|
+
[dataTypeKey1]: {types: {postgres: [dataTypeValue1]}, key: dataTypeKey1},
|
|
32
|
+
[dataTypeKey2]: {types: {postgres: [dataTypeValue2]}, key: dataTypeKey2},
|
|
33
|
+
postgres: {}
|
|
34
|
+
}};
|
|
35
|
+
return { Model: MockModel, Sequelize } ;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const dataTypeKey1 = Object.keys(Sequelize.DataTypes)[0];
|
|
39
|
+
const dataTypeKey2 = Object.keys(Sequelize.DataTypes)[1];
|
|
40
|
+
const dataTypeValue1 = Sequelize.DataTypes[dataTypeKey1].types.postgres[0];
|
|
41
|
+
const dataTypeValue2 = Sequelize.DataTypes[dataTypeKey2].types.postgres[0];
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
jest.mock('../../lib/active_record/db/importSchema', () => jest.fn());
|
|
45
|
+
importSchema.mockImplementation(() => ({created_at: {type: dataTypeValue1}, updated_at: {type: dataTypeValue2}}));
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
jest.clearAllMocks();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
describe('ActiveRecord', () => {
|
|
54
|
+
describe('ActiveRecord#constructor', () => {
|
|
55
|
+
it ('will throw an error when creating an instance of BaseRecord', () => {
|
|
56
|
+
expect(() => new BaseRecord()).toThrow();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
describe('ActiveRecord.initialize', () => {
|
|
62
|
+
it ('calls `getActiveRecordSchema` and passes the response to init', () => {
|
|
63
|
+
class User extends BaseRecord {}
|
|
64
|
+
User.initialize();
|
|
65
|
+
const tableDetails = {created_at: {type: Sequelize.DataTypes[dataTypeKey1]},
|
|
66
|
+
updated_at: {type: Sequelize.DataTypes[dataTypeKey2]}
|
|
67
|
+
};
|
|
68
|
+
expect(importSchema).toHaveBeenCalledTimes(1);
|
|
69
|
+
expect(Model.init).toHaveBeenCalledTimes(1);
|
|
70
|
+
expect(Model.init).toHaveBeenCalledWith(tableDetails,
|
|
71
|
+
{
|
|
72
|
+
createdAt: 'created_at',
|
|
73
|
+
deletedAt: 'deleted_at',
|
|
74
|
+
modelName: 'User',
|
|
75
|
+
sequelize: mockSequelize,
|
|
76
|
+
tableName: 'users',
|
|
77
|
+
updatedAt: 'updated_at'
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it ('uses `timestamps: false` when the schema has no timestamps', () => {
|
|
82
|
+
importSchema.mockImplementation(() => ({}));
|
|
83
|
+
class User extends BaseRecord {}
|
|
84
|
+
User.initialize();
|
|
85
|
+
expect(Model.init).toHaveBeenCalledWith({},
|
|
86
|
+
{
|
|
87
|
+
createdAt: 'created_at',
|
|
88
|
+
deletedAt: 'deleted_at',
|
|
89
|
+
modelName: 'User',
|
|
90
|
+
sequelize: mockSequelize,
|
|
91
|
+
tableName: 'users',
|
|
92
|
+
timestamps: false,
|
|
93
|
+
updatedAt: 'updated_at'
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it ('does not run twice on the same model', () => {
|
|
98
|
+
class User extends BaseRecord {}
|
|
99
|
+
User.initialize();
|
|
100
|
+
User.initialize();
|
|
101
|
+
expect(Model.init).toHaveBeenCalledTimes(1);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it ('does run once per model', () => {
|
|
105
|
+
class User extends BaseRecord {}
|
|
106
|
+
class Team extends BaseRecord {}
|
|
107
|
+
User.initialize();
|
|
108
|
+
Team.initialize();
|
|
109
|
+
expect(Model.init).toHaveBeenCalledTimes(2);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it ('will throw an error when run on BaseRecord', () => {
|
|
113
|
+
expect(() => BaseRecord.initialize()).toThrow();
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
describe('ActiveRecord.tableName', () => {
|
|
119
|
+
it ('defaults to the puralized version of the class name', () => {
|
|
120
|
+
class User extends BaseRecord {}
|
|
121
|
+
expect(User._tableName).toEqual('users');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it ('handles atypical pluralizations', () => {
|
|
125
|
+
class Person extends BaseRecord {}
|
|
126
|
+
expect(Person._tableName).toEqual('people');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it ('converts to snake case', () => {
|
|
130
|
+
class BigDog extends BaseRecord {}
|
|
131
|
+
expect(BigDog._tableName).toEqual('big_dogs');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it ('can be overridden', () => {
|
|
135
|
+
class User extends BaseRecord {
|
|
136
|
+
static _tableName = 'foo';
|
|
137
|
+
}
|
|
138
|
+
expect(User._tableName).toEqual('foo');
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
describe('ActiveRecord#find', () => {
|
|
144
|
+
it ('calls the sequelize `findByPk` method', async () => {
|
|
145
|
+
class Person extends BaseRecord {}
|
|
146
|
+
Person.initialize();
|
|
147
|
+
const id = Math.random();
|
|
148
|
+
await Person.find(id);
|
|
149
|
+
expect(Person.findByPk).toHaveBeenCalledTimes(1);
|
|
150
|
+
expect(Person.findByPk).toHaveBeenCalledWith(id);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
describe('ActiveRecord#where', () => {
|
|
156
|
+
const column = TestHelpers.Faker.Text.randomString();
|
|
157
|
+
const value = TestHelpers.Faker.Text.randomString();
|
|
158
|
+
const condition = {[column]: value};
|
|
159
|
+
class Person extends BaseRecord {}
|
|
160
|
+
Person.initialize();
|
|
161
|
+
|
|
162
|
+
it ('calls findAll with the provided condition', async () => {
|
|
163
|
+
await Person.where(condition);
|
|
164
|
+
expect(Person.findAll).toHaveBeenCalledWith({where: condition});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it ('passes additional options', async () => {
|
|
168
|
+
const option1 = TestHelpers.Faker.Text.randomString();
|
|
169
|
+
const option2 = TestHelpers.Faker.Text.randomString();
|
|
170
|
+
const value1 = TestHelpers.Faker.Text.randomString();
|
|
171
|
+
const value2 = TestHelpers.Faker.Text.randomString();
|
|
172
|
+
const options = {[option1]: value1, [option2]: value2};
|
|
173
|
+
|
|
174
|
+
await Person.where(condition, options);
|
|
175
|
+
const expected = {...options, where: condition };
|
|
176
|
+
expect(Person.findAll).toHaveBeenCalledWith(expected);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
});
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
const { Connection } = require('../../../lib/active_record/db/connection');
|
|
2
|
+
const { ConnectionConfiguration } = require('../../../lib/active_record/db/connectionConfiguration');
|
|
3
|
+
const TestHelpers = require('@vida-global/test-helpers');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
jest.mock('sequelize', () => {
|
|
7
|
+
class MockSequelize {
|
|
8
|
+
constructor(_1, _2, _3, options) {
|
|
9
|
+
this.options = options;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
transaction = jest.fn(callback => callback())
|
|
13
|
+
close = jest.fn();
|
|
14
|
+
}
|
|
15
|
+
return {Sequelize: MockSequelize};
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
let spy;
|
|
20
|
+
const origEnv = process.env.NODE_ENV;
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
if (spy) spy.mockRestore();
|
|
23
|
+
spy = null;
|
|
24
|
+
Connection.clearConnectionsCache();
|
|
25
|
+
process.env.NODE_ENV = origEnv;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
const config1 = {
|
|
30
|
+
database: TestHelpers.Faker.Text.randomString(),
|
|
31
|
+
host: TestHelpers.Faker.Text.randomString(),
|
|
32
|
+
password: TestHelpers.Faker.Text.randomString(),
|
|
33
|
+
port: Math.random(),
|
|
34
|
+
username: TestHelpers.Faker.Text.randomString(),
|
|
35
|
+
pool: {
|
|
36
|
+
min: Math.random(),
|
|
37
|
+
max: Math.random(),
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const config2 = {
|
|
42
|
+
database: TestHelpers.Faker.Text.randomString(),
|
|
43
|
+
host: TestHelpers.Faker.Text.randomString(),
|
|
44
|
+
password: TestHelpers.Faker.Text.randomString(),
|
|
45
|
+
port: Math.random(),
|
|
46
|
+
username: TestHelpers.Faker.Text.randomString()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const config3 = {
|
|
50
|
+
database: TestHelpers.Faker.Text.randomString(),
|
|
51
|
+
host: TestHelpers.Faker.Text.randomString(),
|
|
52
|
+
password: TestHelpers.Faker.Text.randomString(),
|
|
53
|
+
port: Math.random(),
|
|
54
|
+
ssl: true,
|
|
55
|
+
username: TestHelpers.Faker.Text.randomString()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const sqliteConfig = {
|
|
59
|
+
dialect: 'sqlite'
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const databaseId1 = TestHelpers.Faker.Text.randomString();
|
|
63
|
+
const databaseId2 = TestHelpers.Faker.Text.randomString();
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
describe('Connection', () => {
|
|
67
|
+
beforeEach(() => {
|
|
68
|
+
spy = jest.spyOn(ConnectionConfiguration, '_fetchAllConfigs');
|
|
69
|
+
spy.mockImplementation(() => ({
|
|
70
|
+
default: {test: config1, development: config1, production: config1},
|
|
71
|
+
[databaseId1]: {test: config2, production: {}},
|
|
72
|
+
[databaseId2]: {test: config3, production: {}},
|
|
73
|
+
sqlite: {test: sqliteConfig}
|
|
74
|
+
}));
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('Connection#_sequelize', () => {
|
|
78
|
+
it ('caches the connection to the same database', () => {
|
|
79
|
+
const conn1 = new Connection();
|
|
80
|
+
const conn2 = new Connection();
|
|
81
|
+
expect(conn1._sequelize).toBe(conn2._sequelize);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it ('does not cache connections to different databases', () => {
|
|
85
|
+
const conn1 = new Connection();
|
|
86
|
+
const conn2 = new Connection(databaseId1);
|
|
87
|
+
expect(conn1._sequelize).not.toBe(conn2._sequelize);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe('settings (postgres)', () => {
|
|
91
|
+
it ('sets the connection settings to the correct values', () => {
|
|
92
|
+
const conn1 = new Connection();
|
|
93
|
+
expect(conn1._sequelize.options.database).toEqual(config1.database);
|
|
94
|
+
expect(conn1._sequelize.options.dialect).toEqual('postgres');
|
|
95
|
+
expect(conn1._sequelize.options.host).toEqual(config1.host);
|
|
96
|
+
expect(conn1._sequelize.options.password).toEqual(config1.password);
|
|
97
|
+
expect(conn1._sequelize.options.port).toEqual(config1.port);
|
|
98
|
+
expect(conn1._sequelize.options.username).toEqual(config1.username);
|
|
99
|
+
|
|
100
|
+
const conn2 = new Connection(databaseId1);
|
|
101
|
+
expect(conn2._sequelize.options.database).toEqual(config2.database);
|
|
102
|
+
expect(conn2._sequelize.options.dialect).toEqual('postgres');
|
|
103
|
+
expect(conn2._sequelize.options.host).toEqual(config2.host);
|
|
104
|
+
expect(conn2._sequelize.options.password).toEqual(config2.password);
|
|
105
|
+
expect(conn2._sequelize.options.port).toEqual(config2.port);
|
|
106
|
+
expect(conn2._sequelize.options.username).toEqual(config2.username);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it ('requires ssl when the configuration says to', () => {
|
|
110
|
+
const conn = new Connection(databaseId2);
|
|
111
|
+
expect(conn._sequelize.options.dialectOptions).toEqual({ssl: {require: true}});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it ('enables logging in development', () => {
|
|
115
|
+
process.env.NODE_ENV = 'development';
|
|
116
|
+
const conn = new Connection();
|
|
117
|
+
expect(conn._sequelize.options.logging).toBe(undefined); // undefined defaults to true
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it ('does not enable logging in production', () => {
|
|
121
|
+
process.env.NODE_ENV = 'production';
|
|
122
|
+
const conn = new Connection();
|
|
123
|
+
expect(conn._sequelize.options.logging).toBeFalsy();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it ('sets the connection pool to the configured values', () => {
|
|
127
|
+
const conn1 = new Connection();
|
|
128
|
+
expect(conn1._sequelize.options.pool).toEqual(config1.pool);
|
|
129
|
+
|
|
130
|
+
const conn2 = new Connection(databaseId1);
|
|
131
|
+
expect(conn2._sequelize.options.pool).toEqual({min: 0, max: 5})
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it ('configures the connection to use underscores for columns', () => {
|
|
135
|
+
const conn = new Connection();
|
|
136
|
+
expect(conn._sequelize.options.define.underscored).toBeTruthy();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
describe('replication', () => {
|
|
141
|
+
it ('configures a read and writer when replicas are configured', () => {
|
|
142
|
+
const config = {
|
|
143
|
+
database: TestHelpers.Faker.Text.randomString(),
|
|
144
|
+
host: TestHelpers.Faker.Text.randomString(),
|
|
145
|
+
password: TestHelpers.Faker.Text.randomString(),
|
|
146
|
+
port: Math.random(),
|
|
147
|
+
username: TestHelpers.Faker.Text.randomString(),
|
|
148
|
+
readers: [
|
|
149
|
+
{
|
|
150
|
+
database: TestHelpers.Faker.Text.randomString(),
|
|
151
|
+
host: TestHelpers.Faker.Text.randomString(),
|
|
152
|
+
password: TestHelpers.Faker.Text.randomString(),
|
|
153
|
+
port: Math.random(),
|
|
154
|
+
username: TestHelpers.Faker.Text.randomString(),
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
database: TestHelpers.Faker.Text.randomString(),
|
|
158
|
+
host: TestHelpers.Faker.Text.randomString(),
|
|
159
|
+
password: TestHelpers.Faker.Text.randomString(),
|
|
160
|
+
port: Math.random(),
|
|
161
|
+
username: TestHelpers.Faker.Text.randomString(),
|
|
162
|
+
},
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
spy.mockImplementation(() => ({default: {test: config }}));
|
|
166
|
+
const conn = new Connection();
|
|
167
|
+
const options = conn._sequelize.options;
|
|
168
|
+
expect(options.database).toBe(undefined);
|
|
169
|
+
expect(options.dialect).toBe('postgres');
|
|
170
|
+
expect(options.host).toBe(undefined);
|
|
171
|
+
expect(options.password).toBe(undefined);
|
|
172
|
+
expect(options.port).toBe(undefined);
|
|
173
|
+
expect(options.username).toBe(undefined);
|
|
174
|
+
|
|
175
|
+
expect(options.replication).toEqual({
|
|
176
|
+
write: {
|
|
177
|
+
database: config.database,
|
|
178
|
+
host: config.host,
|
|
179
|
+
password: config.password,
|
|
180
|
+
port: config.port,
|
|
181
|
+
username: config.username,
|
|
182
|
+
},
|
|
183
|
+
read: config.readers
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
describe('settings (sqlite)', () => {
|
|
191
|
+
it ('sets the connection settings to the correct values for sqlite', () => {
|
|
192
|
+
const conn = new Connection('sqlite');
|
|
193
|
+
expect(conn._sequelize.options.dialect).toEqual('sqlite');
|
|
194
|
+
expect(conn._sequelize.options.storage).toEqual(`${process.cwd()}/config/db/database.test.sqlite`);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
describe('Connection#close', () => {
|
|
201
|
+
it ('calls close on the underlying sequelize connection', () => {
|
|
202
|
+
const conn = new Connection();
|
|
203
|
+
conn._sequelize; // reference it to initiate the connection
|
|
204
|
+
conn.close();
|
|
205
|
+
expect(conn._sequelize.close).toHaveBeenCalledTimes(1);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
describe('Connection.closeAll', () => {
|
|
211
|
+
it ('calls close on all cached connections', () => {
|
|
212
|
+
const conn1 = new Connection();
|
|
213
|
+
const conn2 = new Connection(databaseId1);
|
|
214
|
+
conn1._sequelize // reference it to initiate the connection
|
|
215
|
+
conn2._sequelize // reference it to initiate the connection
|
|
216
|
+
Connection.closeAll();
|
|
217
|
+
expect(conn1._sequelize.close).toHaveBeenCalledTimes(1);
|
|
218
|
+
expect(conn2._sequelize.close).toHaveBeenCalledTimes(1);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
});
|