Merge pull request #98 from pawelmalak/db-migrations
Added database migrations
This commit is contained in:
commit
afc0f16470
10 changed files with 304 additions and 54 deletions
3
.env
3
.env
|
@ -1,2 +1,3 @@
|
|||
PORT=5005
|
||||
NODE_ENV=development
|
||||
NODE_ENV=development
|
||||
VERSION=1.6.8
|
|
@ -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))
|
||||
|
|
|
@ -1 +1 @@
|
|||
REACT_APP_VERSION=1.6.7
|
||||
REACT_APP_VERSION=1.6.8
|
32
db.js
32
db.js
|
@ -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
50
db/index.js
Normal 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
189
db/migrations/00_initial.js
Normal 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
21
db/utils/backupDb.js
Normal 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;
|
|
@ -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
13
package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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": {
|
||||
|
|
Loading…
Reference in a new issue