@getanthill/datastore
Version:
Event-Sourced Datastore
202 lines (158 loc) • 4.84 kB
text/typescript
import type { ModelConfig, Services } from '../typings';
import { ok } from 'assert';
import fs from 'fs';
import { Command, Option } from 'commander';
import * as utils from './utils';
import yaml from 'js-yaml';
export function upsertModel(services: Services) {
return async (modelPath: string, cmd: any) => {
try {
const datastore = services.datastores.get(cmd.datastore);
if (!datastore) {
return;
}
let modelConfigs: any = null;
if (cmd.yaml === true) {
modelConfigs = yaml.load(fs.readFileSync(modelPath, 'utf8'));
} else {
modelConfigs = require(modelPath);
if ('default' in modelConfigs) {
// @ts-ignore
modelConfigs = modelConfigs.default;
}
}
ok(modelConfigs !== null, 'Invalid model configuration');
ok(
cmd.multi !== true || cmd.name === undefined,
'Model name can not be used in conjunction of --multi',
);
ok(
cmd.multi !== true || cmd.description === undefined,
'Model description can not be used in conjunction of --multi',
);
const models: ModelConfig[] = [];
if (cmd.multi === false) {
models.push(modelConfigs);
} else if (Array.isArray(modelConfigs)) {
models.push(...modelConfigs);
} else {
models.push(...Object.values(modelConfigs as object));
}
for (const modelConfig of models) {
if (cmd.name) {
modelConfig.name = cmd.name;
modelConfig?.indexes?.forEach((index) => {
index.collection = cmd.name;
});
}
if (cmd.description) {
modelConfig.description = cmd.description;
}
let model;
try {
const { data } = await datastore.createModel(modelConfig);
model = data;
} catch (err: any) {
if (err.response && err.response.status === 409) {
const { data } = await datastore.updateModel(modelConfig);
model = data;
} else {
throw err;
}
}
utils.log(model, cmd.format);
if (cmd.withIndexes !== true) {
continue;
}
const { data: indexes } =
await datastore.createModelIndexes(modelConfig);
utils.log(indexes, cmd.format);
}
} catch (err: any) {
if (err.response) {
utils.log(err.response.data, cmd.format);
return;
}
utils.log(err, cmd.format);
}
};
}
export function models(services: Services) {
return async (cmd: any) => {
try {
const datastore = services.datastores.get(cmd.datastore);
if (!datastore) {
return;
}
const { data } = await datastore.getModels();
utils.log(Object.keys(data), cmd.format);
} catch (err: any) {
if (err.response) {
utils.log(err.response.data, cmd.format);
return;
}
utils.log(err, cmd.format);
}
};
}
export function graph(services: Services) {
return async (cmd: any) => {
try {
const datastore = services.datastores.get(cmd.datastore);
if (!datastore) {
return;
}
const { data } = await datastore.getGraph();
utils.log(data, cmd.format);
} catch (err: any) {
if (err.response) {
utils.log(err.response.data, cmd.format);
return;
}
utils.log(err, cmd.format);
}
};
}
export default function register(services: Services, name = 'admin') {
const program = new Command(name);
program.summary('Administration commands');
// Upsert
let c = program.command('upsert <model_path>');
utils.addDatastoreOptions(c, services);
c.option('--name <name>', 'Model name')
.option('--description <description>', 'Model description')
.option('--with-indexes', 'Update indexes', false)
.option('--yaml', 'Is model in YAML format', false)
.option('--multi', 'Do we import multiple models at once', false)
.addOption(
new Option('--format <format>', 'Response format').choices([
'json',
'yaml',
]),
)
.description('Admin create or update a model')
.action(upsertModel(services));
// Models
c = program.command('models');
utils.addDatastoreOptions(c, services);
c.addOption(
new Option('--format <format>', 'Response format').choices([
'json',
'yaml',
]),
)
.description('Get models available in the Datastore')
.action(models(services));
// Graph
c = program.command('graph');
utils.addDatastoreOptions(c, services);
c.addOption(
new Option('--format <format>', 'Response format').choices([
'json',
'yaml',
]),
)
.description('Get the entities dependency graph')
.action(graph(services));
return program;
}