diff --git a/.gitignore b/.gitignore index b51ea71..337e585 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ -build/ \ No newline at end of file +build/ +data/ \ No newline at end of file diff --git a/src/db/index.ts b/src/db/index.ts new file mode 100644 index 0000000..e67077c --- /dev/null +++ b/src/db/index.ts @@ -0,0 +1,47 @@ +require('ts-node/register'); +import { Sequelize } from 'sequelize'; +import { Umzug, SequelizeStorage } from 'umzug'; +import { Logger } from '../utils'; + +const logger = new Logger(); + +// DB config +export const sequelize = new Sequelize({ + dialect: 'sqlite', + storage: 'data/db.sqlite3', + logging: false +}); + +// Migrations config +const umzug = new Umzug({ + migrations: { glob: '**/migrations/*.ts' }, + context: sequelize.getQueryInterface(), + storage: new SequelizeStorage({ sequelize }), + logger: undefined +}); + +export type Migration = typeof umzug._types.migration; + +export const connectDB = async () => { + try { + // Create & connect db + await sequelize.authenticate(); + logger.log('Database connected'); + + // Check migrations + const pendingMigrations = await umzug.pending(); + if (pendingMigrations.length > 0) { + logger.log(`Found pending migrations. Executing...`); + } + + await umzug.up(); + } catch (err) { + logger.log(`Database connection error`, 'ERROR'); + + if (process.env.NODE_ENV == 'development') { + console.log(err); + } + + process.exit(1); + } +}; diff --git a/src/db/migrations/00_initial.ts b/src/db/migrations/00_initial.ts new file mode 100644 index 0000000..275a7a9 --- /dev/null +++ b/src/db/migrations/00_initial.ts @@ -0,0 +1,45 @@ +import { DataTypes, Model } from 'sequelize'; +import type { Migration } from '../'; +import { + Snippet, + SnippetCreationAttributes +} from '../../typescript/interfaces'; + +const { INTEGER, STRING, DATE } = DataTypes; + +export const up: Migration = async ({ + context: queryInterface +}): Promise => { + await queryInterface.createTable>( + 'snippets', + { + id: { + type: INTEGER, + allowNull: false, + primaryKey: true + }, + title: { + type: STRING, + allowNull: false + }, + language: { + type: STRING, + allowNull: false + }, + createdAt: { + type: DATE, + allowNull: false + }, + updatedAt: { + type: DATE, + allowNull: false + } + } + ); +}; + +export const down: Migration = async ({ + context: queryInterface +}): Promise => { + await queryInterface.dropTable('snippets'); +}; diff --git a/src/server.ts b/src/server.ts index e1d682b..aeca8fa 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,6 +1,7 @@ import dotenv from 'dotenv'; import express from 'express'; import { Logger } from './utils'; +import { connectDB } from './db'; // Env config dotenv.config({ path: './src/config/.env' }); @@ -9,8 +10,15 @@ const app = express(); const logger = new Logger(); const PORT = process.env.PORT; -app.listen(PORT, () => { - logger.log( - `Server is working on port ${PORT} in ${process.env.NODE_ENV} mode` - ); -}); +// App config +app.use(express.json()); + +(async () => { + await connectDB(); + + app.listen(PORT, () => { + logger.log( + `Server is working on port ${PORT} in ${process.env.NODE_ENV} mode` + ); + }); +})(); diff --git a/src/typescript/interfaces/Model.ts b/src/typescript/interfaces/Model.ts new file mode 100644 index 0000000..72b5cd7 --- /dev/null +++ b/src/typescript/interfaces/Model.ts @@ -0,0 +1,5 @@ +export interface Model { + id: number; + createdAt: Date; + updatedAt: Date; +} diff --git a/src/typescript/interfaces/Snippet.ts b/src/typescript/interfaces/Snippet.ts new file mode 100644 index 0000000..8cee678 --- /dev/null +++ b/src/typescript/interfaces/Snippet.ts @@ -0,0 +1,10 @@ +import { Model } from '.'; +import { Optional } from 'sequelize'; + +export interface Snippet extends Model { + title: string; + language: string; +} + +export interface SnippetCreationAttributes + extends Optional {} diff --git a/src/typescript/interfaces/index.ts b/src/typescript/interfaces/index.ts new file mode 100644 index 0000000..063adcb --- /dev/null +++ b/src/typescript/interfaces/index.ts @@ -0,0 +1,2 @@ +export * from './Model'; +export * from './Snippet';