boostr
Version:
Build and deploy your Layr apps
148 lines • 5.91 kB
JavaScript
import { join, resolve } from 'path';
import fsExtra from 'fs-extra';
import { Subservice } from './sub.js';
import { BackendService } from './backend.js';
import { requireGlobalNPMPackage } from '../npm.js';
const MONGODB_MEMORY_SERVER_GLOBAL_PACKAGE_VERSION = '8.11.0';
const LOCAL_DATA_DIRECTORY_NAME = 'data';
export class DatabaseService extends Subservice {
parseConfigURL() {
const directory = this.getDirectory();
const config = this.getConfig();
const { protocol, hostname, port, pathname } = this._parseConfigURL();
if (config.platform === 'local') {
if (protocol !== 'mongodb:') {
this.throwError(`The 'url' property in the configuration should start with 'mongodb://' (directory: '${directory}')`);
}
if (hostname !== 'localhost') {
this.throwError(`The host of the 'url' property in the configuration should be 'localhost' (directory: '${directory}')`);
}
if (!port) {
this.throwError(`The 'url' property in the configuration should specify a port (directory: '${directory}')`);
}
if (pathname.length < 2) {
this.throwError(`The 'url' property in the configuration should specify a database name (directory: '${directory}')`);
}
}
else {
this.throwError('Non-local database URL cannot be parsed for now');
}
return { protocol, hostname, port, pathname };
}
async start() {
await super.start();
const directory = this.getDirectory();
const config = this.getConfig();
const serviceName = this.getName();
if (config.platform !== 'local') {
return;
}
const { port, pathname } = this.parseConfigURL();
const databaseName = pathname.slice(1);
const dataDirectory = join(directory, LOCAL_DATA_DIRECTORY_NAME);
fsExtra.ensureDirSync(dataDirectory);
const { MongoMemoryServer } = await requireGlobalNPMPackage('mongodb-memory-server-global', MONGODB_MEMORY_SERVER_GLOBAL_PACKAGE_VERSION, { serviceName });
this._localServer = (await MongoMemoryServer.create({
instance: {
port,
dbName: databaseName,
dbPath: dataDirectory,
storageEngine: 'wiredTiger'
}
}));
let connectionString = this._localServer.getUri();
connectionString = connectionString.replace('127.0.0.1', 'localhost');
if (connectionString.endsWith('?')) {
connectionString = connectionString.slice(0, -1);
}
this.logMessage(`MongoDB server started at ${connectionString}`);
}
async stop() {
if (this._localServer !== undefined) {
await this._localServer.stop();
this.logMessage(`MongoDB server stopped`);
}
}
async migrate() {
const directory = this.getDirectory();
const { url } = this.getConfig();
if (!url) {
this.throwError(`A 'url' property is required in the configuration to migrate a database (directory: '${directory}')`);
}
await this.start();
for (const service of this.getDependents()) {
if (service instanceof BackendService) {
await service.migrateDatabase(url);
}
}
await this.stop();
}
async import(inputFile) {
inputFile = resolve(process.cwd(), inputFile);
const directory = this.getDirectory();
const { url } = this.getConfig();
if (!url) {
this.throwError(`A 'url' property is required in the configuration to import a database (directory: '${directory}')`);
}
await this.start();
for (const service of this.getDependents()) {
if (service instanceof BackendService) {
await service.importDatabase(url, inputFile);
}
}
await this.stop();
}
async export(outputFile) {
outputFile = resolve(process.cwd(), outputFile);
const directory = this.getDirectory();
const { url } = this.getConfig();
if (!url) {
this.throwError(`A 'url' property is required in the configuration to export a database (directory: '${directory}')`);
}
await this.start();
for (const service of this.getDependents()) {
if (service instanceof BackendService) {
await service.exportDatabase(url, outputFile);
}
}
await this.stop();
}
}
DatabaseService.type = 'database';
DatabaseService.description = 'A database service providing some storage capability to your app.';
DatabaseService.examples = [
'boostr {{serviceName}} start',
'boostr {{serviceName}} migrate',
'boostr {{serviceName}} migrate --production'
];
// === Commands ===
DatabaseService.commands = {
...Subservice.commands,
migrate: {
...Subservice.commands.migrate,
description: 'Migrates your database.',
examples: ['boostr {{serviceName}} migrate'],
async handler() {
await this.migrate();
}
},
import: {
...Subservice.commands.import,
description: 'Imports the specified JSON file to your database.',
examples: ['boostr {{serviceName}} import inputFile'],
arguments: ['inputFile'],
async handler([inputFile]) {
await this.import(inputFile);
}
},
export: {
...Subservice.commands.export,
description: 'Exports the your database to a JSON file.',
examples: ['boostr {{serviceName}} export outputFile'],
arguments: ['outputFile'],
async handler([outputFile]) {
await this.export(outputFile);
}
}
};
//# sourceMappingURL=database.js.map