feat(cli): create DB in start command if not exists (#285)

This commit is contained in:
Ali BARIN
2022-04-08 11:36:35 +02:00
committed by GitHub
parent 75eda7f2af
commit c227dc86bb
19 changed files with 211 additions and 126 deletions

View File

@@ -1,42 +1,3 @@
import appConfig from '../../src/config/app';
import logger from '../../src/helpers/logger';
import client from './client';
const createDatabaseAndUser = async () => {
if(appConfig.appEnv !== 'development' && appConfig.appEnv !== 'test') {
const errorMessage = 'Database creation can be used only with development or test environments!'
logger.error(errorMessage)
return;
}
await client.connect();
await createDatabase();
await createDatabaseUser();
await grantPrivileges();
await client.end();
}
const createDatabase = async () => {
await client.query(`CREATE DATABASE ${appConfig.postgresDatabase}`);
logger.info(`Database: ${appConfig.postgresDatabase} created!`);
}
const createDatabaseUser = async () => {
await client.query(`CREATE USER ${appConfig.postgresUsername}`);
logger.info(`Database User: ${appConfig.postgresUsername} created!`);
}
const grantPrivileges = async () => {
await client.query(
`GRANT ALL PRIVILEGES ON DATABASE ${appConfig.postgresDatabase} TO ${appConfig.postgresUsername};`
);
logger.info(
`${appConfig.postgresUsername} has granted all privileges on ${appConfig.postgresDatabase}!`
);
}
import { createDatabaseAndUser } from './utils';
createDatabaseAndUser();

View File

@@ -1,29 +1,3 @@
import appConfig from '../../src/config/app';
import logger from '../../src/helpers/logger';
import client from './client';
const dropDatabase = async () => {
if (appConfig.appEnv != 'development' && appConfig.appEnv != 'test') {
const errorMessage = 'Drop database command can be used only with development or test environments!'
logger.error(errorMessage)
return;
}
await client.connect();
await dropDatabaseAndUser();
await client.end();
}
const dropDatabaseAndUser = async() => {
await client.query(`DROP DATABASE IF EXISTS ${appConfig.postgresDatabase}`);
logger.info(`Database: ${appConfig.postgresDatabase} removed!`);
await client.query(`DROP USER IF EXISTS ${appConfig.postgresUsername}`);
logger.info(`Database User: ${appConfig.postgresUsername} removed!`);
}
import { dropDatabase } from './utils';
dropDatabase();

View File

@@ -1,15 +1,3 @@
import User from '../../src/models/user';
import '../../src/config/orm';
import logger from '../../src/helpers/logger';
const userParams = {
email: 'user@automatisch.io',
password: 'sample',
};
async function createUser() {
const user = await User.query().insertAndFetch(userParams);
logger.info(`User has been saved: ${user.email}`);
}
import { createUser } from './utils';
createUser();

View File

@@ -0,0 +1,100 @@
import appConfig from '../../src/config/app';
import logger from '../../src/helpers/logger';
import client from './client';
import User from '../../src/models/user';
import '../../src/config/orm';
export async function createUser(email = 'user@automatisch.io', password = 'sample') {
const UNIQUE_VIOLATION_CODE = '23505';
const userParams = {
email,
password,
};
try {
const user = await User.query().insertAndFetch(userParams);
logger.info(`User has been saved: ${user.email}`);
} catch (err) {
if ((err as any).nativeError.code !== UNIQUE_VIOLATION_CODE) {
throw err;
}
logger.info(`User already exists: ${email}`);
}
}
export const createDatabaseAndUser = async (database = appConfig.postgresDatabase, user = appConfig.postgresUsername) => {
await client.connect();
await createDatabase(database);
await createDatabaseUser(user);
await grantPrivileges(database, user);
await client.end();
}
export const createDatabase = async (database = appConfig.postgresDatabase) => {
const DUPLICATE_DB_CODE = '42P04';
try {
await client.query(`CREATE DATABASE ${database}`);
logger.info(`Database: ${database} created!`);
} catch (err) {
if ((err as any).code !== DUPLICATE_DB_CODE) {
throw err;
}
logger.info(`Database: ${database} already exists!`);
}
}
export const createDatabaseUser = async (user = appConfig.postgresUsername) => {
const DUPLICATE_OBJECT_CODE = '42710';
try {
const result = await client.query(`CREATE USER ${user}`);
logger.info(`Database User: ${user} created!`);
return result;
} catch (err) {
if ((err as any).code !== DUPLICATE_OBJECT_CODE) {
throw err;
}
logger.info(`Database User: ${user} already exists!`);
}
}
export const grantPrivileges = async (
database = appConfig.postgresDatabase, user = appConfig.postgresUsername
) => {
await client.query(
`GRANT ALL PRIVILEGES ON DATABASE ${database} TO ${user};`
);
logger.info(
`${user} has granted all privileges on ${database}!`
);
}
export const dropDatabase = async () => {
if (appConfig.appEnv != 'development' && appConfig.appEnv != 'test') {
const errorMessage = 'Drop database command can be used only with development or test environments!'
logger.error(errorMessage)
return;
}
await client.connect();
await dropDatabaseAndUser();
await client.end();
}
export const dropDatabaseAndUser = async(database = appConfig.postgresDatabase, user = appConfig.postgresUsername) => {
await client.query(`DROP DATABASE IF EXISTS ${database}`);
logger.info(`Database: ${database} removed!`);
await client.query(`DROP USER IF EXISTS ${user}`);
logger.info(`Database User: ${user} removed!`);
}

2
packages/backend/database.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export * as utils from './dist/bin/database/utils';
export * as database from './dist/src/config/database';

View File

@@ -0,0 +1,3 @@
/* eslint-disable */
module.exports.utils = require('./dist/bin/database/utils');
module.exports.database = require('./dist/src/config/database');

1
packages/backend/logger.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
export * from './dist/src/helpers/logger';

View File

@@ -0,0 +1,2 @@
/* eslint-disable */
module.exports = require('./dist/src/helpers/logger');

View File

@@ -3,9 +3,10 @@
"version": "0.1.0",
"description": "> TODO: description",
"scripts": {
"dev": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/server.ts",
"dev": "nodemon --watch 'src/**/*.ts' --watch 'bin/**/*.ts' --exec 'ts-node' src/server.ts",
"worker": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/worker.ts",
"build": "tsc && yarn copy-statics",
"build:watch": "nodemon --watch 'src/**/*.ts' --watch 'bin/**/*.ts' --exec yarn build --ext ts",
"start": "node dist/src/server.js",
"test": "ava",
"lint": "eslint . --ignore-path ../../.eslintignore",
@@ -53,7 +54,7 @@
"twilio": "3.70.0",
"twitch-js": "2.0.0-beta.42",
"twitter-api-v2": "1.6.0",
"winston": "^3.3.3"
"winston": "^3.7.1"
},
"contributors": [
{
@@ -64,11 +65,19 @@
"homepage": "https://github.com/automatisch/automatisch#readme",
"main": "dist/src/app",
"directories": {
"bin": "bin",
"src": "src",
"test": "__tests__"
},
"files": [
"src"
"bin",
"src",
"server.js",
"server.d.ts",
"logger.js",
"logger.d.ts",
"database.js",
"database.d.ts"
],
"repository": {
"type": "git",

1
packages/backend/server.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
export * from './dist/src/server';

View File

@@ -0,0 +1,2 @@
/* eslint-disable */
module.exports = require('./dist/src/server.js');

View File

@@ -4,16 +4,14 @@ import type { Knex } from 'knex';
import knexConfig from '../../knexfile';
import logger from '../helpers/logger';
const knexInstance: Knex = knex(knexConfig);
export const client: Knex = knex(knexConfig);
const CONNECTION_REFUSED = 'ECONNREFUSED';
knexInstance.raw('SELECT 1')
client.raw('SELECT 1')
.catch((err) => {
if (err.code === CONNECTION_REFUSED) {
logger.error('Make sure you have installed PostgreSQL and it is running.', err);
process.exit();
}
});
export default knexInstance;

View File

@@ -1,4 +1,4 @@
import { Model } from 'objection';
import database from './database';
import { client } from './database';
Model.knex(database)
Model.knex(client);

View File

@@ -1,5 +1,5 @@
import winston from 'winston'
import appConfig from '../config/app'
import * as winston from 'winston';
import appConfig from '../config/app';
const levels = {
error: 0,
@@ -7,11 +7,11 @@ const levels = {
info: 2,
http: 3,
debug: 4,
}
};
const level = () => {
return appConfig.appEnv === 'development' ? 'debug' : 'info'
}
};
const colors = {
error: 'red',
@@ -19,9 +19,9 @@ const colors = {
info: 'green',
http: 'magenta',
debug: 'white',
}
};
winston.addColors(colors)
winston.addColors(colors);
const format = winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms' }),
@@ -29,7 +29,7 @@ const format = winston.format.combine(
winston.format.printf(
(info) => `${info.timestamp} [${info.level}]: ${info.message}`,
),
)
);
const transports = [
new winston.transports.Console(),
@@ -38,13 +38,13 @@ const transports = [
level: 'error',
}),
new winston.transports.File({ filename: 'logs/server.log' }),
]
];
const logger = winston.createLogger({
export const logger = winston.createLogger({
level: level(),
levels,
format,
transports,
})
});
export default logger
export default logger;

View File

@@ -13,7 +13,7 @@ class Connection extends Base {
formattedData?: IJSONObject;
userId!: string;
verified = false;
count: number;
count?: number;
static tableName = 'connections';

View File

@@ -26,10 +26,5 @@
"include": [
"src/**/*",
"bin/**/*"
],
"ts-node": {
"compilerOptions": {
"module": "commonjs"
}
}
]
}