Merge pull request #98 from pawelmalak/db-migrations

Added database migrations
This commit is contained in:
pawelmalak 2021-10-05 13:29:42 +02:00 committed by GitHub
commit afc0f16470
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 304 additions and 54 deletions

3
.env
View file

@ -1,2 +1,3 @@
PORT=5005
NODE_ENV=development
NODE_ENV=development
VERSION=1.6.8

View file

@ -1,3 +1,6 @@
### v1.6.8 (2021-10-05)
- Implemented migration system for database
### v1.6.7 (2021-10-04)
- Add multiple labels to Docker Compose ([#90](https://github.com/pawelmalak/flame/issues/90))
- Custom icons via Docker Compose labels ([#91](https://github.com/pawelmalak/flame/issues/91))

View file

@ -1 +1 @@
REACT_APP_VERSION=1.6.7
REACT_APP_VERSION=1.6.8

32
db.js
View file

@ -1,32 +0,0 @@
const { Sequelize } = require('sequelize');
const Logger = require('./utils/Logger');
const logger = new Logger();
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: './data/db.sqlite',
logging: false,
});
const connectDB = async () => {
try {
await sequelize.authenticate();
logger.log('Connected to database');
const syncModels = true;
if (syncModels) {
logger.log('Starting model synchronization');
await sequelize.sync({ alter: true });
logger.log('All models were synchronized');
}
} catch (error) {
logger.log(`Unable to connect to the database: ${error.message}`, 'ERROR');
process.exit(1);
}
};
module.exports = {
connectDB,
sequelize,
};

50
db/index.js Normal file
View file

@ -0,0 +1,50 @@
const { Sequelize } = require('sequelize');
const { join } = require('path');
const fs = require('fs');
const Umzug = require('umzug');
const backupDB = require('./utils/backupDb');
const Logger = require('../utils/Logger');
const logger = new Logger();
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: './data/db.sqlite',
logging: false,
});
const umzug = new Umzug({
migrations: {
path: join(__dirname, './migrations'),
params: [sequelize.getQueryInterface()],
},
storage: 'sequelize',
storageOptions: {
sequelize,
},
});
const connectDB = async () => {
try {
backupDB();
await sequelize.authenticate();
logger.log('Connected to database');
// migrations
const pendingMigrations = await umzug.pending();
if (pendingMigrations.length > 0) {
logger.log('Executing pending migrations');
await umzug.up();
}
} catch (error) {
logger.log(`Unable to connect to the database: ${error.message}`, 'ERROR');
process.exit(1);
}
};
module.exports = {
connectDB,
sequelize,
};

189
db/migrations/00_initial.js Normal file
View file

@ -0,0 +1,189 @@
const { DataTypes } = require('sequelize');
const { INTEGER, DATE, STRING, TINYINT, FLOAT, TEXT } = DataTypes;
const up = async (query) => {
// CONFIG TABLE
await query.createTable('config', {
id: {
type: INTEGER,
autoIncrement: true,
primaryKey: true,
},
key: {
type: STRING,
allowNull: false,
unique: true,
},
value: {
type: STRING,
allowNull: false,
},
valueType: {
type: STRING,
allowNull: false,
},
isLocked: {
type: TINYINT,
defaultValue: 0,
},
createdAt: {
type: DATE,
allowNull: false,
},
updatedAt: {
type: DATE,
allowNull: false,
},
});
// WEATHER TABLE
await query.createTable('weather', {
id: {
type: INTEGER,
autoIncrement: true,
primaryKey: true,
},
externalLastUpdate: {
type: STRING,
},
tempC: {
type: FLOAT,
},
tempF: {
type: FLOAT,
},
isDay: {
type: INTEGER,
},
cloud: {
type: INTEGER,
},
conditionText: {
type: TEXT,
},
conditionCode: {
type: INTEGER,
},
createdAt: {
type: DATE,
allowNull: false,
},
updatedAt: {
type: DATE,
allowNull: false,
},
});
// CATEGORIES TABLE
await query.createTable('categories', {
id: {
type: INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: STRING,
allowNull: false,
},
isPinned: {
type: TINYINT,
defaultValue: 0,
},
createdAt: {
type: DATE,
allowNull: false,
},
updatedAt: {
type: DATE,
allowNull: false,
},
orderId: {
type: INTEGER,
defaultValue: null,
},
});
// BOOKMARKS TABLE
await query.createTable('bookmarks', {
id: {
type: INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: STRING,
allowNull: false,
},
url: {
type: STRING,
allowNull: false,
},
categoryId: {
type: INTEGER,
allowNull: false,
},
icon: {
type: STRING,
defaultValue: '',
},
createdAt: {
type: DATE,
allowNull: false,
},
updatedAt: {
type: DATE,
allowNull: false,
},
});
// APPS TABLE
await query.createTable('apps', {
id: {
type: INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: STRING,
allowNull: false,
},
url: {
type: STRING,
allowNull: false,
},
icon: {
type: STRING,
allowNull: false,
defaultValue: 'cancel',
},
isPinned: {
type: TINYINT,
defaultValue: 0,
},
createdAt: {
type: DATE,
allowNull: false,
},
updatedAt: {
type: DATE,
allowNull: false,
},
orderId: {
type: INTEGER,
defaultValue: null,
},
});
};
const down = async (query) => {
await query.dropTable('config');
await query.dropTable('weather');
await query.dropTable('categories');
await query.dropTable('bookmarks');
await query.dropTable('apps');
};
module.exports = {
up,
down,
};

21
db/utils/backupDb.js Normal file
View file

@ -0,0 +1,21 @@
const fs = require('fs');
const backupDB = () => {
if (!fs.existsSync('data/db_backups')) {
fs.mkdirSync('data/db_backups');
}
const version = process.env.VERSION;
const slug = `db-${version.replace(/\./g, '')}-backup.sqlite`;
const srcPath = 'data/db.sqlite';
const destPath = `data/db_backups/${slug}`;
if (fs.existsSync(srcPath)) {
if (!fs.existsSync(destPath)) {
fs.copyFileSync(srcPath, destPath);
}
}
};
module.exports = backupDB;

View file

@ -1,26 +1,30 @@
const { DataTypes } = require('sequelize');
const { sequelize } = require('../db');
const Config = sequelize.define('Config', {
key: {
type: DataTypes.STRING,
allowNull: false,
unique: true
const Config = sequelize.define(
'Config',
{
key: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
value: {
type: DataTypes.STRING,
allowNull: false,
},
valueType: {
type: DataTypes.STRING,
allowNull: false,
},
isLocked: {
type: DataTypes.TINYINT,
defaultValue: 0,
},
},
value: {
type: DataTypes.STRING,
allowNull: false
},
valueType: {
type: DataTypes.STRING,
allowNull: false
},
isLocked: {
type: DataTypes.BOOLEAN,
defaultValue: false
{
tableName: 'config',
}
}, {
tableName: 'config'
});
);
module.exports = Config;
module.exports = Config;

13
package-lock.json generated
View file

@ -525,6 +525,11 @@
"inherits": "~2.0.0"
}
},
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
},
"body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
@ -3240,6 +3245,14 @@
"is-typedarray": "^1.0.0"
}
},
"umzug": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz",
"integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==",
"requires": {
"bluebird": "^3.7.2"
}
},
"undefsafe": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz",

View file

@ -27,6 +27,7 @@
"node-schedule": "^2.0.0",
"sequelize": "^6.6.2",
"sqlite3": "^5.0.2",
"umzug": "^2.3.0",
"ws": "^7.4.6"
},
"devDependencies": {