Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/create mixin #61

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/create/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@


const addService = require("./service");
const addMixin = require("./mixin");

/**
* Yargs command
*/
module.exports = {
command: ["create", "<fileType>", "<name>"],
describe: `Create a Moleculer service `,
describe: `Create a Moleculer service or mixin `,

builder(yargs) {
yargs.options({
typescript: {
describe: "Create service for typescript",
describe: "Create typescript file",
type: "boolean",
default: false,
},
Expand All @@ -27,6 +29,9 @@ module.exports = {
switch (fileType) {
case "service":
return addService(opts);

case "mixin":
return addMixin(opts);
}
},
};
124 changes: 124 additions & 0 deletions src/create/mixin/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* moleculer-cli
* Copyright (c) 2021 MoleculerJS (https://github.com/moleculerjs/moleculer-cli)
* MIT Licensed
*/

const fs = require("fs");
const path = require("path");
const inquirer = require("inquirer");
const render = require("consolidate").handlebars.render;
const ui = new inquirer.ui.BottomBar();

const { fail } = require("../../utils");

module.exports = async (opts) => {
const values = Object.assign({}, opts);
const _typescript = values.typescript ? true : false;
const name = opts._[2];

return (
Promise.resolve()
.then(() => {
const answers_options = [
{
type: "input",
name: "mixinFolder",
message: "Mixin directory",
default: "./mixins",
async validate(input) {
if (!fs.existsSync(path.resolve(input))) {
ui.log.write(`The ${input} doesn't exists!`);
fail("Aborted");
}
return true;
},
},
];

if (!name)
answers_options.push({
type: "input",
name: "mixinName",
message: "Mixin name",
default: "test",
});

return inquirer.prompt(answers_options).then((answers) => {
answers.name = answers.mixinName;
answers.mixinName = answers.mixinName || name;
answers.mixinName = answers.mixinName.replace(
/[^\w\s]/gi,
"-"
);

answers.className = answers.mixinName
.replace(/(\w)(\w*)/g, function (g0, g1, g2) {
return g1.toUpperCase() + g2.toLowerCase();
})
.replace(/[^\w\s]/gi, "");

Object.assign(values, answers);
const { mixinFolder, mixinName } = values;
const file_name = `${mixinName.toLowerCase()}.mixin${
_typescript ? ".ts" : ".js"
}`;
const newMixinPath = path.join(
mixinFolder,
`${mixinName.toLowerCase()}.mixin${
_typescript ? ".ts" : ".js"
}`
);

if (fs.existsSync(newMixinPath)) {
return inquirer
.prompt([
{
type: "confirm",
name: "sure",
message: `The file ${file_name} already exists! Do you want to overwrite it?`,
default: false,
},
])
.then(({ sure }) => {
if (!sure) fail("Aborted");
});
}
});
})
.then(() => {
const templatePath = _typescript
? path.join(
__dirname,
"moleculer-db.typescript.mixin.template"
)
: path.join(__dirname, "moleculer-db.mixin.template");
const template = fs.readFileSync(templatePath, "utf8");
return new Promise((resolve, reject) => {
render(template, values, async function (err, res) {
if (err) return reject(err);

const { mixinFolder, mixinName } = values;
const newMixinPath = path.join(
mixinFolder,
`${mixinName.toLowerCase()}.mixin${
_typescript ? ".ts" : ".js"
}`
);

fs.writeFileSync(
path.resolve(`${newMixinPath}`),
res,
"utf8"
);

resolve();
});
});
})

// Error handler
.catch((err) => fail(err))
);
};

68 changes: 68 additions & 0 deletions src/create/mixin/moleculer-db.mixin.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"use strict";

const fs = require("fs");
const mongoose = require("mongoose"); // npm i mongoose -S

module.exports = (collection, modelSchema) => {
const schema = {
actions: {
create: {
rest: "POST /",
async handler(ctx) {
const { params } = ctx;
console.log(this.adapter);
this.adapter.create(params, (err, saved) => {
if (err) this.logger.error(err);
this.logger.info(saved);
});
},
},
update: {
rest: "PUT /:id",
async handler(ctx) {
const { params } = ctx;
this.adapter.findOneAndUpdate(
{ _id: params.id },
params,
(err, saved) => {
if (err) this.logger.error(err);
this.logger.info(saved);
}
);
},
},
list: {
rest: "GET /",
async handler(ctx) {
const { params } = ctx;
return this.adapter.find({});
},
},

delete: {
rest: "DELETE /:id",
async handler(ctx) {
const { params } = ctx;
this.adapter.deleteOne({ _id: params.id });
},
},
},
methods: {
_connect() {
return mongoose
.connect("mongodb://localhost:27017/test")
.then(() => this.logger.info("Connected"))
.catch((err) => this.logger.error(err));
},
},

async started() {
this._connect();
if (!this.adapter) {
this.adapter = mongoose.model(collection, modelSchema);
}
},
};

return schema;
};
70 changes: 70 additions & 0 deletions src/create/mixin/moleculer-db.typescript.mixin.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Context, Service, ServiceSchema } from "moleculer";
import { Document, Schema, connect, model } from "mongoose";

export default class {{className}}Connection implements Partial<ServiceSchema>, ThisType<Service>{

private collection: string;
private modelSchema: Schema;
private schema: Partial<ServiceSchema> & ThisType<Service>;

public constructor(public collectionName: string, modelSchema: Schema) {
this.collection = collectionName;
this.modelSchema = modelSchema;
this.schema = {
actions: {
create: {
rest: "POST /",
async handler(ctx: Context) {
const { params } = ctx;
this.adapter.create(params, (err: Error, saved: Document) => {
if (err) {this.logger.error(err);};
this.logger.info(saved);
});
},
},
update: {
rest: "PUT /:id",
async handler(ctx: Context<{id: string}>) {
const { params } = ctx;
this.adapter.findOneAndUpdate(
{ _id: params.id },
params,
(err: Error, saved: Document) => {
if (err) {this.logger.error(err);}
this.logger.info(saved);
}
);
},
},
list: {
rest: "GET /",
async handler(ctx: Context) {
return this.adapter.find({});
},
},

delete: {
rest: "DELETE /:id",
async handler(ctx: Context<{id: string}>) {
const { params } = ctx;
this.adapter.deleteOne({ _id: params.id });
},
},
},
methods: {
connectDb() {
return connect("mongodb://localhost:27017/test")
.then(() => this.logger.info("Connected"))
.catch((err: Error) => this.logger.error(err));
},
},
async started(){
this.connectDb();
},
};
}
public start(){
this.schema.adapter = model(this.collection, this.modelSchema);
return this.schema;
}
};
99 changes: 99 additions & 0 deletions test/e2e/create/mixin/create.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
const YargsPromise = require("yargs-promise");
const yargs = require("yargs");
const inquirer = require("inquirer");
const path = require("path");
const fs = require("fs");
const create = require("../../../../src/create");
const answers = require("./create_answers.json");
const answers_ts = require("./create_answers_ts.json");
const tmp = path.resolve(__dirname, "../../../../tmp");

describe("test create", () => {
beforeAll(() => {
if (!fs.existsSync(tmp)) {
fs.mkdirSync(tmp,{mode: 0o777});
}
});
afterEach(() => {
jest.clearAllMocks();
});

afterAll(() => {
fs.rmdirSync(tmp, {recursive: true});
});

it("create js mixin", () => {
const _path = `../../../../${answers.mixinFolder}/${answers.mixinName}.mixin.js`;
const pathAbsoluteFile = path.resolve(__dirname, _path);
const mockFileAbsolute = path.resolve(
__dirname,
`./mocks/${answers.mixinName}.mixin.js`
);

jest.mock("inquirer");
inquirer.prompt = jest.fn().mockResolvedValue(answers);
yargs
.usage("Usage: $0 <command> [options]")
.version()
.command(create)
.help().argv;
const parser = new YargsPromise(yargs);
return parser
.parse(`create mixin ${answers.mixinName}`)
.then(({ data, argv }) => {
if (!fs.existsSync(pathAbsoluteFile)) {
throw new Error("file not exist");
}

expect(fs.existsSync(pathAbsoluteFile)).toBeTruthy();
expect(fs.readFileSync(pathAbsoluteFile)).toEqual(
fs.readFileSync(mockFileAbsolute)
);

fs.unlinkSync(pathAbsoluteFile);
})
.catch(({ error, argv }) => {
throw new Error(error);
});
});

it("create ts mixin", () => {
const _path = `../../../../${answers.mixinFolder}/${answers.mixinName}.mixin.ts`;
const pathAbsoluteFile = path.resolve(__dirname, _path);
const mockFileAbsolute = path.resolve(
__dirname,
`./mocks/${answers.mixinName}.mixin.ts`
);

jest.mock("inquirer");
inquirer.prompt = jest.fn().mockResolvedValue(answers);
yargs
.usage("Usage: $0 <command> [options]")
.version()
.command(create)
.default("--typescript", true)
.help().argv;
const parser = new YargsPromise(yargs);
return parser
.parse(`create mixin ${answers_ts.mixinName}`)
.then(({ data, argv }) => {
if (!fs.existsSync(pathAbsoluteFile)) {
fs.unlinkSync(pathAbsoluteFile);
throw new Error("file not exist");
}

expect(fs.existsSync(pathAbsoluteFile)).toBeTruthy();
expect(fs.readFileSync(pathAbsoluteFile)).toEqual(
fs.readFileSync(mockFileAbsolute)
);
fs.unlinkSync(pathAbsoluteFile);

})
.catch(({ error, argv }) => {
fs.unlinkSync(pathAbsoluteFile);

throw new Error(error);
});
});
});

Loading