Initial commit
This commit is contained in:
15
.github/workflows/lint.yml
vendored
Normal file
15
.github/workflows/lint.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
name: Lint
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '18.x'
|
||||||
|
|
||||||
|
- run: yarn
|
||||||
|
- run: yarn lint
|
||||||
22
.github/workflows/publish-releases.yml
vendored
Normal file
22
.github/workflows/publish-releases.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
name: Publish Package to npmjs.org
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '18.x'
|
||||||
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
scope: '@mep-agency'
|
||||||
|
|
||||||
|
- run: yarn
|
||||||
|
- run: yarn lint && yarn build
|
||||||
|
- run: yarn publish
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
bin
|
||||||
|
build
|
||||||
|
ldd
|
||||||
|
|
||||||
|
# misc
|
||||||
|
*.log
|
||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
.cache
|
||||||
|
dist
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
9
.npmignore
Normal file
9
.npmignore
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
.github
|
||||||
|
build
|
||||||
|
src
|
||||||
|
|
||||||
|
*.log
|
||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
.cache
|
||||||
|
*.lock
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Marco Lipparini
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
116
README.md
Normal file
116
README.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# Local Dev DB (ldd)
|
||||||
|
|
||||||
|
<span class="badge-lifecycle"><a href="https://github.com/mep-agency#lifecycle-policy" title="Check out our lifecycle stages"><img src="https://img.shields.io/badge/lifecycle-experimental-orange" alt="Project lifecyfle stage" /></a></span>
|
||||||
|
<span class="badge-license"><a href="https://github.com/mep-agency/local-dev-db" title="View this project on GitHub"><img src="https://img.shields.io/github/license/mep-agency/local-dev-db" alt="Project license" /></a></span>
|
||||||
|
<span class="badge-npmversion"><a href="https://www.npmjs.com/package/@mep-agency/local-dev-db" title="View this project on NPM"><img src="https://img.shields.io/npm/v/%40mep-agency/local-dev-db" alt="NPM version" /></a></span>
|
||||||
|
<span class="badge-npmdownloads"><a href="https://www.npmjs.com/package/@mep-agency/local-dev-db" title="View this project on NPM"><img src="https://img.shields.io/npm/dt/%40mep-agency/local-dev-db" alt="NPM downloads" /></a></span>
|
||||||
|
|
||||||
|
A zero-config local MariaDB instance for local development (using Docker) so you can finally stop doing things like:
|
||||||
|
|
||||||
|
- Using SQLite for dev and MariaDB/MySQL for production
|
||||||
|
- Installing a local database server directly
|
||||||
|
- Spending a lot of time to get up and running on a new dev environment
|
||||||
|
|
||||||
|
## How does it fit your workflow?
|
||||||
|
|
||||||
|
While this tool is meant to be installed as a dependency to your projects, it actually runs as a single database server.
|
||||||
|
This makes it possible to optimize the resources when working on multiple projects at the same time.
|
||||||
|
|
||||||
|
Feel free to install this tool as a dependency to all of your projects, CLI commands will act on the same instance and all of your databases will share the same storage volume.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Runs a fully-featured MariaDB server without touching your local system
|
||||||
|
- Runs a PhpMyAdmin instance attached to the DB server so you can manage your databases with no additional software
|
||||||
|
- Provides you with a simple set of CLI commands do run common tasks:
|
||||||
|
- Create/drop databases and dedicated users
|
||||||
|
- Export/import SQL files (single DB or full server)
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- **Docker:** this tool uses docker (compose) to spwan some containers for you. A basic default installation is usually more than enough (e.g. `brew install docker` or similar).
|
||||||
|
|
||||||
|
## Original author
|
||||||
|
|
||||||
|
- Marco Lipparini ([liarco](https://github.com/liarco))
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
Make sure Docker is installed and configured properly, the `docker` CLI must be available for this tool to work properly.
|
||||||
|
|
||||||
|
Simply install the package using any package manager:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# With Yarn
|
||||||
|
$ yarn add --dev @mep-agency/local-dev-db
|
||||||
|
|
||||||
|
# With NPM
|
||||||
|
$ npm install --save-dev @mep-agency/local-dev-db
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the `ldd` binary to see the available commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# With Yarn
|
||||||
|
$ yarn ldd
|
||||||
|
Usage: ldd [options] [command]
|
||||||
|
|
||||||
|
A zero-config local MariaDB instance for local development (using Docker)
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-V, --version output the version number
|
||||||
|
-h, --help display help for command
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
# ...
|
||||||
|
|
||||||
|
# With NPM
|
||||||
|
$ npx ldd
|
||||||
|
Usage: ldd [options] [command]
|
||||||
|
# ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Starting a new project
|
||||||
|
|
||||||
|
Creating a brand new database for your project is pretty easy:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ yarn add --dev @mep-agency/local-dev-db
|
||||||
|
# ...
|
||||||
|
|
||||||
|
$ yarn ldd start
|
||||||
|
Starting local database containers...
|
||||||
|
|
||||||
|
A PhpMyAdmin instance is running on: http://127.0.0.1:8010
|
||||||
|
|
||||||
|
$ yarn ldd create my-awesome-app
|
||||||
|
Creating a new DB named "my-awesome-app"...
|
||||||
|
A new user has been created with full permissions on "my-awesome-app".
|
||||||
|
|
||||||
|
Username: my-awesome-app
|
||||||
|
Password: my-awesome-app-pwd
|
||||||
|
```
|
||||||
|
|
||||||
|
Our main focus is DX and speed, so don't expect any fancy configuration options or proper security. You can connect to the new database with simple default auth: `mysql://my-awesome-app:my-awesome-app-pwd@127.0.0.1:3306/my-awesome-app`.
|
||||||
|
|
||||||
|
You can also connect to http://127.0.0.1:8010 to access a PhpMyAdmin instance attached to your server.
|
||||||
|
|
||||||
|
Once done, you can stop your containers from any of your projects:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# This will stop all containers at once!
|
||||||
|
$ yarn ldd stop
|
||||||
|
Stopping local database containers...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced configuration
|
||||||
|
|
||||||
|
We hope you never have to use it, but just in case, here are some ENV vars you can set on your machine to customize the behavior of the application:
|
||||||
|
|
||||||
|
- `LDD_DB_IMAGE_TAG` (default: `latest`): we use the official [MariaDB](https://hub.docker.com/_/mariadb) Docker image. You can pick a different tag if you wish.
|
||||||
|
- `LDD_DB_PORT` (default: `3306`): The database server will be attached to this port on your local machine. You can customize this to avoid any conflicts with other services.
|
||||||
|
- `LDD_DB_ROOT_PASSWORD` (default: `not-secure-pwd`): This tool is not secure by design, so you should probably leave this untouched to avoid issues.
|
||||||
|
- `LDD_PMA_IMAGE_TAG` (default: `latest`): we use the official [PhpMyAdmin](https://hub.docker.com/_/phpmyadmin) Docker image. You can pick a different tag if you wish.
|
||||||
|
- `LDD_PMA_PORT` (default: `8010`): The PhpMyAdmin instance will be attached to this port on your local machine. You can customize this to avoid any conflicts with other services.
|
||||||
|
|
||||||
|
Changing some of these variables after the initial server creation might break it due to the way storage is persisted in volumes. For instance, if you update the `LDD_DB_ROOT_PASSWORD` then your PhpMyAdmin instance won't be able to connect to your server anymore since the root password is set at creation and won't be updated unless you destroy the server and start from scratch (`yarn ldd destroy && yarn ldd start`).
|
||||||
35
docker/docker-compose.yml
Normal file
35
docker/docker-compose.yml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: "mariadb:${LDD_DB_IMAGE_TAG:-latest}"
|
||||||
|
ports:
|
||||||
|
- "${LDD_DB_PORT:-3306}:3306"
|
||||||
|
networks:
|
||||||
|
- private
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/mysql
|
||||||
|
environment:
|
||||||
|
MARIADB_ROOT_PASSWORD: "${LDD_DB_ROOT_PASSWORD:-not-secure-pwd}"
|
||||||
|
MARIADB_DATABASE: defaultdb
|
||||||
|
phpmyadmin:
|
||||||
|
image: "phpmyadmin:${LDD_PMA_IMAGE_TAG:-latest}"
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "${LDD_PMA_PORT:-8010}:80"
|
||||||
|
networks:
|
||||||
|
- private
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
environment:
|
||||||
|
PMA_HOST: db
|
||||||
|
PMA_PORT: 3306
|
||||||
|
PMA_USER: root
|
||||||
|
PMA_PASSWORD: "${LDD_DB_ROOT_PASSWORD:-not-secure-pwd}"
|
||||||
|
MYSQL_ROOT_PASSWORD: "${LDD_DB_ROOT_PASSWORD:-not-secure-pwd}"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
private:
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_data:
|
||||||
58
package.json
Normal file
58
package.json
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"name": "@mep-agency/local-dev-db",
|
||||||
|
"version": "1.0.0-alpha1",
|
||||||
|
"private": false,
|
||||||
|
"description": "A zero-config local MariaDB instance for local development (using Docker)",
|
||||||
|
"author": "Marco Lipparini <developer@liarco.net>",
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"development",
|
||||||
|
"local",
|
||||||
|
"database",
|
||||||
|
"db",
|
||||||
|
"mysql",
|
||||||
|
"mariadb"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/mep-agency/local-dev-db.git"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/mep-agency/local-dev-db/issues"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "rm -rf ./bin && rm -rf ./build && tsc && pkg -c package.json ./build/src/index.js && yarn postinstall",
|
||||||
|
"watch": "tsc --watch",
|
||||||
|
"format": "prettier --write \"**/*.{ts,md,scss,css,js}\"",
|
||||||
|
"lint": "prettier --check \"**/*.{ts,md,scss,css,js}\"",
|
||||||
|
"postinstall": "node postinstall.js install"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"ldd": "./ldd"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"bin",
|
||||||
|
"docker",
|
||||||
|
"LICENCE",
|
||||||
|
"README.md"
|
||||||
|
],
|
||||||
|
"pkg": {
|
||||||
|
"targets": [
|
||||||
|
"linux-x64",
|
||||||
|
"macos-x64",
|
||||||
|
"win-x64"
|
||||||
|
],
|
||||||
|
"outputPath": "bin"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@inquirer/prompts": "^3.0.0",
|
||||||
|
"@types/mysql": "^2.15.21",
|
||||||
|
"commander": "^11.0.0",
|
||||||
|
"docker-cli-js": "^2.10.0",
|
||||||
|
"mysql": "^2.18.1",
|
||||||
|
"pkg": "^5.8.1",
|
||||||
|
"prettier": "^2.8.8",
|
||||||
|
"typescript": "^5.1.3"
|
||||||
|
},
|
||||||
|
"dependencies": {}
|
||||||
|
}
|
||||||
67
postinstall.js
Normal file
67
postinstall.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
// Inspired by: https://blog.xendit.engineer/how-we-repurposed-npm-to-publish-and-distribute-our-go-binaries-for-internal-cli-23981b80911b
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const BIN_BASE_NAME = './bin/@mep-agency/local-dev-db';
|
||||||
|
|
||||||
|
if (!fs.existsSync(BIN_BASE_NAME) || !fs.statSync(BIN_BASE_NAME).isDirectory()) {
|
||||||
|
console.info('Binaries are not available, this probably means we are in a development environment... skipping!');
|
||||||
|
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ARCH_MAPPING = {
|
||||||
|
x64: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
const PLATFORM_MAPPING = {
|
||||||
|
darwin: 'macos',
|
||||||
|
linux: 'linux',
|
||||||
|
win32: 'win.exe',
|
||||||
|
};
|
||||||
|
|
||||||
|
async function install(callback) {
|
||||||
|
if (PLATFORM_MAPPING[process.platform] === undefined) {
|
||||||
|
callback(`Unsupported platform: "${process.platform}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ARCH_MAPPING[process.arch] === undefined) {
|
||||||
|
callback(`Unsupported architecture: "${process.arch}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const binaryNameTokens = [BIN_BASE_NAME, PLATFORM_MAPPING[process.platform], ARCH_MAPPING[process.arch]].filter(
|
||||||
|
(token) => token.length > 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
console.info(`Copying the relevant binary for your platform ${process.platform} (${process.arch})`);
|
||||||
|
|
||||||
|
fs.copyFileSync(binaryNameTokens.join('-'), './ldd');
|
||||||
|
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse command line arguments and call the right method
|
||||||
|
var actions = {
|
||||||
|
install: install,
|
||||||
|
};
|
||||||
|
|
||||||
|
const argv = process.argv;
|
||||||
|
|
||||||
|
if (argv && argv.length > 2) {
|
||||||
|
var cmd = process.argv[2];
|
||||||
|
if (!actions[cmd]) {
|
||||||
|
console.log('Invalid command.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
actions[cmd](function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
} else {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
5
prettier.config.js
Normal file
5
prettier.config.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
printWidth: 125,
|
||||||
|
trailingComma: 'all',
|
||||||
|
singleQuote: true,
|
||||||
|
};
|
||||||
230
src/index.ts
Normal file
230
src/index.ts
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { program } from 'commander';
|
||||||
|
import { confirm } from '@inquirer/prompts';
|
||||||
|
import { dockerCommand } from 'docker-cli-js';
|
||||||
|
import mysql from 'mysql';
|
||||||
|
|
||||||
|
import packageInfo from '../package.json';
|
||||||
|
|
||||||
|
let PACKAGE_INSTALLATION_PATH = path.normalize(
|
||||||
|
__dirname.startsWith('/snapshot') ? path.dirname(process.execPath) : `${__dirname}/../..`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const dockerCompose: typeof dockerCommand = async (command, options) => {
|
||||||
|
try {
|
||||||
|
return await dockerCommand(
|
||||||
|
`compose --file "${PACKAGE_INSTALLATION_PATH}/docker/docker-compose.yml" --project-name "ldd" ${command}`,
|
||||||
|
{ echo: false, ...(options ?? {}) },
|
||||||
|
);
|
||||||
|
} catch (e: any) {
|
||||||
|
if (e.stderr === undefined) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error(`ERROR: ${e.stderr}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const execQuery = (query: string, database: string = 'defaultdb') => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const connection = mysql.createConnection({
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: Number(process.env.LDD_DB_PORT ?? '3306'),
|
||||||
|
user: 'root',
|
||||||
|
password: process.env.LDD_DB_ROOT_PASSWORD ?? 'not-secure-pwd',
|
||||||
|
database,
|
||||||
|
multipleStatements: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
connection.connect((error) => {
|
||||||
|
if (error) {
|
||||||
|
if (error.code === 'ECONNREFUSED') {
|
||||||
|
console.error(`ERROR: Could't connect to the DB server. Did you forget to start it?`);
|
||||||
|
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connection.query(query, (error, results) => {
|
||||||
|
if (error) {
|
||||||
|
console.error(`ERROR: ${error.sqlMessage}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(results);
|
||||||
|
});
|
||||||
|
|
||||||
|
connection.end();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
program.name('ldd').description(packageInfo.description).version(packageInfo.version);
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('start')
|
||||||
|
.description('Starts your local DB server')
|
||||||
|
.action(async (str, options) => {
|
||||||
|
console.info('Starting local database containers...');
|
||||||
|
|
||||||
|
await dockerCompose('up -d');
|
||||||
|
|
||||||
|
console.info('');
|
||||||
|
console.info(`A PhpMyAdmin instance is running on: http://127.0.0.1:${process.env.LDD_PMA_PORT ?? 8010}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('stop')
|
||||||
|
.description('Stops your local DB server')
|
||||||
|
.action(async () => {
|
||||||
|
console.info('Stopping local database containers...');
|
||||||
|
|
||||||
|
await dockerCompose('down');
|
||||||
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('destroy')
|
||||||
|
.description('Stops all containers (if running) and deletes any related volumes')
|
||||||
|
.action(async () => {
|
||||||
|
const confirmation = await confirm({
|
||||||
|
message: 'This action will delete all of your data and cannot be reverted. Are you sure?',
|
||||||
|
default: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (confirmation !== true) {
|
||||||
|
console.info('Aborting...');
|
||||||
|
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.info('Destroying local database containers...');
|
||||||
|
|
||||||
|
await dockerCompose('down -v');
|
||||||
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('create')
|
||||||
|
.description('Creates a new database')
|
||||||
|
.argument('<db_name>', 'The database name')
|
||||||
|
.action(async (databaseName) => {
|
||||||
|
const username = databaseName;
|
||||||
|
const userPwd = `${databaseName}-pwd`;
|
||||||
|
|
||||||
|
console.info(`Creating a new DB named "${databaseName}"...`);
|
||||||
|
|
||||||
|
await execQuery(
|
||||||
|
`START TRANSACTION; CREATE DATABASE \`${databaseName}\`; CREATE USER '${username}'@'%' IDENTIFIED BY '${userPwd}'; GRANT ALL ON \`${databaseName}\`.* TO '${username}'@'%'; FLUSH PRIVILEGES; COMMIT;`,
|
||||||
|
);
|
||||||
|
|
||||||
|
console.info(`A new user has been created with full permissions on "${databaseName}".`);
|
||||||
|
console.info('');
|
||||||
|
console.info(`Username: ${username}`);
|
||||||
|
console.info(`Password: ${userPwd}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('drop')
|
||||||
|
.description('Drops the given database and its default user (if they exist)')
|
||||||
|
.argument('<db_name>', 'The database name')
|
||||||
|
.action(async (databaseName) => {
|
||||||
|
const username = databaseName;
|
||||||
|
const userPwd = `${databaseName}-pwd`;
|
||||||
|
|
||||||
|
const confirmation = await confirm({
|
||||||
|
message: `This action will delete your database "${databaseName}" and cannot be reverted. Are you sure?`,
|
||||||
|
default: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (confirmation !== true) {
|
||||||
|
console.info('Aborting...');
|
||||||
|
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.info(`Dropping DB "${databaseName}" and its default user...`);
|
||||||
|
|
||||||
|
await execQuery(`DROP DATABASE IF EXISTS \`${databaseName}\`; DROP USER IF EXISTS \`${databaseName}\`;`);
|
||||||
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('dump-all')
|
||||||
|
.description('Creates a SQL dump file of all databases')
|
||||||
|
.action(async () => {
|
||||||
|
const now = new Date();
|
||||||
|
const month = now.getMonth().toString().padStart(2, '0');
|
||||||
|
const date = now.getDate().toString().padStart(2, '0');
|
||||||
|
const hours = now.getHours().toString().padStart(2, '0');
|
||||||
|
const minutes = now.getMinutes().toString().padStart(2, '0');
|
||||||
|
const seconds = now.getSeconds().toString().padStart(2, '0');
|
||||||
|
const dumpFileName = `db-full-dump_${now.getFullYear()}-${month}-${date}_${hours}-${minutes}-${seconds}.sql`;
|
||||||
|
|
||||||
|
console.info(`Exporting all databases to "${dumpFileName}"...`);
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
`./${dumpFileName}`,
|
||||||
|
(
|
||||||
|
await dockerCompose(
|
||||||
|
'exec db sh -c \'exec mariadb-dump --all-databases --lock-tables -uroot -p"$MARIADB_ROOT_PASSWORD"\'',
|
||||||
|
)
|
||||||
|
).raw,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('dump')
|
||||||
|
.description('Creates a SQL dump file of the given database')
|
||||||
|
.argument('<db_name>', 'The database name')
|
||||||
|
.action(async (databaseName) => {
|
||||||
|
const now = new Date();
|
||||||
|
const month = now.getMonth().toString().padStart(2, '0');
|
||||||
|
const date = now.getDate().toString().padStart(2, '0');
|
||||||
|
const hours = now.getHours().toString().padStart(2, '0');
|
||||||
|
const minutes = now.getMinutes().toString().padStart(2, '0');
|
||||||
|
const seconds = now.getSeconds().toString().padStart(2, '0');
|
||||||
|
const dumpFileName = `db-${databaseName}-dump_${now.getFullYear()}-${month}-${date}_${hours}-${minutes}-${seconds}.sql`;
|
||||||
|
|
||||||
|
console.info(`Exporting database to "${dumpFileName}"...`);
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
`./${dumpFileName}`,
|
||||||
|
(
|
||||||
|
await dockerCompose(
|
||||||
|
`exec db sh -c \'exec mariadb-dump --databases "${databaseName}" --lock-tables -uroot -p"$MARIADB_ROOT_PASSWORD"\'`,
|
||||||
|
)
|
||||||
|
).raw,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('import')
|
||||||
|
.description('Runs all queries from the given SQL file')
|
||||||
|
.argument('<sql_file_path>', 'The SQL file to import')
|
||||||
|
.action(async (sqlFilePath) => {
|
||||||
|
const confirmation = await confirm({
|
||||||
|
message: 'This action will execute any SQL statement found in the given file and cannot be reverted. Are you sure?',
|
||||||
|
default: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (confirmation !== true) {
|
||||||
|
console.info('Aborting...');
|
||||||
|
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.info(`Importing data from "${sqlFilePath}"...`);
|
||||||
|
|
||||||
|
if (!sqlFilePath.endsWith('.sql') || !fs.existsSync(sqlFilePath) || !fs.statSync(sqlFilePath).isFile()) {
|
||||||
|
console.error(`ERROR: Invalid SQL file`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
execQuery(fs.readFileSync(sqlFilePath).toString());
|
||||||
|
|
||||||
|
console.info('Done. Remember you might have to create dedicated users in order to access new databases.');
|
||||||
|
});
|
||||||
|
|
||||||
|
program.parse();
|
||||||
16
tsconfig.json
Normal file
16
tsconfig.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./build",
|
||||||
|
"target": "ESNext",
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "CommonJS",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"incremental": true,
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
|
"exclude": ["node_modules"],
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user