model creation and fetching with tests

This commit is contained in:
Martin McKeaveney 2020-04-13 11:47:53 +01:00
parent 3b57af74ca
commit 093e52afb0
11 changed files with 8180 additions and 102 deletions

View File

@ -4,6 +4,7 @@
"packages": [
"packages/*"
],
"useWorkspaces": true,
"command": {
"publish": {
"ignoreChanges": [

View File

@ -1,6 +1,9 @@
{
"name": "root",
"private": true,
"workspaces": [
"packages/*"
],
"devDependencies": {
"babel-eslint": "^10.0.3",
"eslint": "^6.8.0",

0
packages/cli/bin/budi Normal file → Executable file
View File

View File

@ -1,10 +1,59 @@
const couchdb = require("../../db");
const MODEL_SCHEMA = {
id: "foo",
name: "Contact",
key: "wutwut",
fields: [
{
name: "name",
type: "string",
constraints: {
min: "",
max: ""
}
},
{
name: "age",
type: "number",
constraints: {
min: 0,
max: 100
}
}
],
validationRules: [
]
}
exports.fetch = async function(ctx) {
const db = couchdb.db.use(ctx.params.instanceId);
const body = await db.view("database", "by_type", {
include_docs: true,
key: ["model"]
});
ctx.body = body.rows;
}
exports.create = async function(ctx) {
const db = couchdb.db.use(ctx.params.instanceId)
ctx.body = await db.insert(ctx.request.body);
// Create the "all" view for that model
const db = couchdb.db.use(ctx.params.instanceId);
const newModel = await db.insert(ctx.request.body);
const designDoc = await db.get("_design/database");
designDoc.views = {
...designDoc.views,
[`all_${newModel.id}`]: {
map: function(doc) {
emit([doc.modelId], doc._id);
}
}
};
await db.insert(designDoc, designDoc._id);
ctx.body = {
...newModel,
message: `Model ${ctx.request.body.name} created successfully.`,
status: 200,
}
}
exports.update = async function(ctx) {

View File

@ -1,10 +1,9 @@
const couchdb = require("../../db")
const { mapValues, keyBy } = require("lodash/fp")
const { mapValues, keyBy, compose } = require("lodash/fp")
const {
validateRecord,
} = require("../../../common/src/records/validateRecord")
const { events } = require("../../../common/src/common/events")
const { $ } = require("../../../common/src/common")
const { safeParseField } = require("../../../common/src/schema/types");
exports.save = async function(ctx) {
@ -80,12 +79,12 @@ async function _findRecord({ db, schema, id }) {
const model = schema.findModel(storedData._modelId)
// TODO refactor
const loadedRecord = $(model.fields, [
keyBy("name"),
const loadRecord = compose(
mapValues(f => safeParseField(f, storedData)),
])
keyBy("name")
);
const loadedRecord = loadRecord(model.fields);
return {
...loadedRecord,

View File

@ -20,6 +20,7 @@ const databaseRoutes = require("./routes/neo/database");
const neoUserRoutes = require("./routes/neo/user");
const clientRoutes = require("./routes/neo/client");
const applicationRoutes = require("./routes/neo/application");
const modelsRoutes = require("./routes/neo/model");
const builderPath = resolve(__dirname, "../builder")
@ -128,11 +129,14 @@ module.exports = (config, app) => {
ctx.status = err.status || 500;
ctx.body = {
message: err.message,
status: ctx.status
status: ctx.status
};
}
});
router.use(modelsRoutes.routes());
router.use(modelsRoutes.allowedMethods());
router.use(applicationRoutes.routes());
router.use(applicationRoutes.allowedMethods());

View File

@ -6,8 +6,8 @@ const router = Router();
router
.get("/api/:instanceId/models", controller.fetch)
.post("/api/:instanceId/models", controller.create)
.patch("/api/:instanceId/models", controller.update)
.delete("/api/:instanceId/models/:modelId", controller.delete)
// .patch("/api/:instanceId/models", controller.update)
// .delete("/api/:instanceId/models/:modelId", controller.delete)
module.exports = router;

View File

@ -4,6 +4,22 @@ const CLIENT_DB_ID = "client-testing";
exports.destroyDatabase = couchdb.db.destroy;
exports.createModel = async instanceId => {
const model = {
"name": "TestModel",
"type": "model",
"key": "name",
"fields": [
{
"name": "name",
"type": "string"
}
]
}
await couchdb.db.use(instanceId).insert(model);
return model;
}
exports.createClientDatabase = async () => {
await couchdb.db.create(CLIENT_DB_ID);
@ -30,6 +46,8 @@ exports.createInstanceDatabase = async instanceId => {
}
}
}, '_design/database');
return instanceId;
}
exports.insertDocument = async (databaseId, document) => {

View File

@ -1,4 +1,3 @@
const couchdb = require("../../../../db");
const supertest = require("supertest");
const app = require("../../../../app");
const { createInstanceDatabase, destroyDatabase } = require("./couchTestUtils");

View File

@ -0,0 +1,83 @@
const supertest = require("supertest");
const app = require("../../../../app");
const { createInstanceDatabase, createModel, destroyDatabase } = require("./couchTestUtils");
const TEST_INSTANCE_ID = "testing-123";
describe("/models", () => {
let request;
let server;
beforeAll(async () => {
server = await app({
config: {
port: 3000
}
});
request = supertest(server);
});
afterAll(async () => {
server.close();
})
describe("create", () => {
beforeEach(async () => {
await createInstanceDatabase(TEST_INSTANCE_ID);
});
afterEach(async () => {
await destroyDatabase(TEST_INSTANCE_ID);
});
it("returns a success message when the model is successfully created", done => {
request
.post(`/api/${TEST_INSTANCE_ID}/models`)
.send({
name: "TestModel",
key: "name",
fields: [
{
name: "name",
type: "string"
}
]
})
.set("Accept", "application/json")
.expect('Content-Type', /json/)
.expect(200)
.end(async (err, res) => {
expect(res.body.message).toEqual("Model TestModel created successfully.");
done();
});
})
});
describe("fetch", () => {
let testModel;
beforeEach(async () => {
await createInstanceDatabase(TEST_INSTANCE_ID);
testModel = await createModel(TEST_INSTANCE_ID);
});
afterEach(async () => {
await destroyDatabase(TEST_INSTANCE_ID);
});
it("returns all the models for that instance in the response body", done => {
request
.get(`/api/${TEST_INSTANCE_ID}/models`)
.set("Accept", "application/json")
.expect('Content-Type', /json/)
.expect(200)
.end(async (_, res) => {
const fetchedModel = res.body[0].doc;
expect(fetchedModel.name).toEqual(testModel.name);
expect(fetchedModel.type).toEqual("model");
done();
});
})
});
});

8096
yarn.lock

File diff suppressed because it is too large Load Diff