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

Fix bug - populate not working - idField mapped to undefined (issue #325, maybe #296) #327

Merged
Merged
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
29 changes: 17 additions & 12 deletions packages/moleculer-db/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -493,13 +493,13 @@ module.exports = {
// Convert entity to JS object
.then(docs => docs.map(doc => this.adapter.entityToObject(doc)))

// Apply idField
.then(docs => docs.map(doc => this.adapter.afterRetrieveTransformID(doc, this.settings.idField)))
// Encode IDs
.then(docs => docs.map(doc => {
doc[this.settings.idField] = this.encodeID(doc[this.settings.idField]);
return doc;
}))
// Apply idField
.then(docs => docs.map(doc => this.adapter.afterRetrieveTransformID(doc, this.settings.idField)))
// Populate
.then(json => (ctx && params.populate) ? this.populateDocs(ctx, json, params.populate) : json)

Expand Down Expand Up @@ -844,28 +844,33 @@ module.exports = {
_get(ctx, params) {
let id = params.id;
let origDoc;
let shouldMapping = params.mapping === true;
return this.getById(id, true)
.then(doc => {
if (!doc)
return Promise.reject(new EntityNotFoundError(id));
origDoc = doc;

if (shouldMapping)
origDoc = _.isArray(doc) ? doc.map(d => _.cloneDeep(d)) : _.cloneDeep(doc);
else
origDoc = doc;

return this.transformDocuments(ctx, params, doc);
})
.then(json => {
if (_.isArray(json) && params.mapping === true) {
let res = {};
if (params.mapping !== true) return json;

let res = {};
if (_.isArray(json)) {
json.forEach((doc, i) => {
const id = this.adapter.afterRetrieveTransformID(origDoc[i], this.settings.idField)[this.settings.idField];
const id = this.encodeID(this.adapter.afterRetrieveTransformID(origDoc[i], this.settings.idField)[this.settings.idField]);
res[id] = doc;
});
return res;
} else if (_.isObject(json) && params.mapping === true) {
let res = {};
const id = this.adapter.afterRetrieveTransformID(origDoc, this.settings.idField)[this.settings.idField];
} else if (_.isObject(json)) {
const id = this.encodeID(this.adapter.afterRetrieveTransformID(origDoc, this.settings.idField)[this.settings.idField]);
res[id] = json;
return res;
}
return json;
return res;
});
},

Expand Down
199 changes: 198 additions & 1 deletion packages/moleculer-db/test/integration/idField.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe("Test CRUD methods with idField", () => {
];

it("should create a new entity", () => {
broker.call("posts.create", posts[0]).then(res => {
return broker.call("posts.create", posts[0]).then(res => {
expect(typeof res).toBe("object");
expect(res._id).toEqual(undefined);
expect(typeof res.myID).toEqual("string");
Expand All @@ -45,6 +45,7 @@ describe("Test CRUD methods with idField", () => {
});

it("should throw an error", () => {
expect.assertions(1);
return broker.call("posts.create", posts[0]).catch(err => {
expect(err).toEqual(new Error("Can't insert key 0000000, it violates the unique constraint"));
});
Expand All @@ -66,6 +67,7 @@ describe("Test CRUD methods with idField", () => {
});

it("should throw an error", () => {
expect.assertions(1);
return broker.call("posts.insert", { entities: [ posts[1], posts[2]] })
.catch(err => {
expect(err).toEqual(new Error("Can't insert key 0000001, it violates the unique constraint"));
Expand All @@ -77,6 +79,11 @@ describe("Test CRUD methods with idField", () => {
.then(res => expect(res).toEqual(posts[1]));
});

it("should return with the entity mapped by ID", () => {
return broker.call("posts.get", { id: posts[1].myID, mapping:true })
.then(res => expect(res[posts[1].myID]).toEqual(posts[1]));
});

it("should return with multiple entity by IDs", () => {
return broker.call("posts.get", { id: [posts[2].myID, posts[0].myID] })
.then(res => {
Expand All @@ -85,6 +92,14 @@ describe("Test CRUD methods with idField", () => {
});
});

it("should return with multiple entities mapped by IDs", () => {
return broker.call("posts.get", { id: [posts[2].myID, posts[0].myID], mapping: true })
.then(res => {
expect(res[posts[2].myID]).toEqual(posts[2]);
expect(res[posts[0].myID]).toEqual(posts[0]);
});
});

it("should find filtered entities (search)", () => {
return broker.call("posts.find", { search: "first" })
.then(res => {
Expand Down Expand Up @@ -169,6 +184,7 @@ describe("Test CRUD methods with idField", () => {
});

test("should throw an error", () => {
expect.assertions(1);
return broker.call("posts.insert", { entity: posts[3] })
.catch(err => {
expect(err).toEqual(new Error("Can't insert key 0000003, it violates the unique constraint"));
Expand All @@ -182,3 +198,184 @@ describe("Test CRUD methods with idField", () => {
});
});
});

describe("Test CRUD methods with idField and encoding", () => {
// Create broker
let broker = new ServiceBroker({
logger: console,
logLevel: "error"
});

// Load my service
broker.createService(DbService, Object.assign({
name: "posts",
settings: {
idField: "myID"
},
adapter: new Adapter(),
methods: {
encodeID(id) {
return "enc:" + id;
},
decodeID(id) {
return id.substring(4);
}
}
}));

beforeAll(() => {
return broker.start().delay(1000);
});

afterAll(() => {
return broker.stop();
});

const posts = [
{ title: "My first post", content: "This is the content", votes: 2 },
{ title: "Second post", content: "Waiting for the next...", votes: 5 },
{ title: "My post", content: "This is the end! Good bye!", votes: 0 },
{ title: "Final post", content: "A final good bye!", votes: 123 }
];

it("should create a new entity", () => {
return broker.call("posts.create", posts[0]).then(res => {
expect(typeof res).toBe("object");
expect(res._id).toEqual(undefined);
expect(typeof res.myID).toEqual("string");
posts[0].myID = res.myID;
});
});

it("should create multiple entities", () => {
return broker.call("posts.insert", { entities: [ posts[1], posts[2]] })
.then(res => {
expect(res.length).toBe(2);

expect(res[0]._id).toEqual(undefined);
expect(typeof res[0].myID).toEqual("string");
posts[1].myID = res[0].myID;

expect(res[1]._id).toEqual(undefined);
expect(typeof res[1].myID).toEqual("string");
posts[2].myID = res[1].myID;
});
});

it("should return with the entity by ID", () => {
return broker.call("posts.get", { id: posts[1].myID })
.then(res => expect(res).toEqual(posts[1]));
});

it("should return with the entity mapped by ID", () => {
return broker.call("posts.get", { id: posts[1].myID, mapping:true })
.then(res => expect(res[posts[1].myID]).toEqual(posts[1]));
});

it("should return with multiple entity by IDs", () => {
return broker.call("posts.get", { id: [posts[2].myID, posts[0].myID] })
.then(res => {
expect(res[0]).toEqual(posts[2]);
expect(res[1]).toEqual(posts[0]);
});
});

it("should return with multiple entities mapped by IDs", () => {
return broker.call("posts.get", { id: [posts[2].myID, posts[0].myID], mapping: true })
.then(res => {
expect(res[posts[2].myID]).toEqual(posts[2]);
expect(res[posts[0].myID]).toEqual(posts[0]);
});
});

it("should find filtered entities (search)", () => {
return broker.call("posts.find", { search: "first" })
.then(res => {
expect(res[0]).toEqual(posts[0]);
});
});

it("should update an entity", () => {
return broker.call("posts.update", {
id: posts[1].myID,
title: "Other title",
content: "Modify my content",
votes: 8
}).then(res => {
expect(res.myID).toEqual(posts[1].myID);
expect(res.title).toEqual("Other title");
expect(res.content).toEqual("Modify my content");
expect(res.votes).toEqual(8);
});
});

it("should find filtered entities (sort)", () => {
return broker.call("posts.find", { sort: "-votes" })
.then(res => {
expect(res.length).toBe(3);

expect(res[0].myID).toEqual(posts[1].myID);
expect(res[1].myID).toEqual(posts[0].myID);
expect(res[2].myID).toEqual(posts[2].myID);
});
});

it("should find filtered entities (limit, offset)", () => {
return broker.call("posts.find", { sort: "votes", limit: "2", offset: 1 })
.then(res => {
expect(res.length).toBe(2);
expect(res[0].myID).toEqual(posts[0].myID);
expect(res[1].myID).toEqual(posts[1].myID);
});
});

it("should find filtered entities (search)", () => {
return broker.call("posts.find", { search: "post", sort: "-votes" })
.then(res => {
expect(res.length).toBe(2);
expect(res[0].myID).toEqual(posts[0].myID);
expect(res[1].myID).toEqual(posts[2].myID);
});
});

it("should find filtered entities (search)", () => {
return broker.call("posts.find", { search: "post", searchFields: ["title"], sort: "-votes" })
.then(res => {
expect(res.length).toBe(2);
expect(res[0].myID).toEqual(posts[0].myID);
expect(res[1].myID).toEqual(posts[2].myID);
});
});

it("should list paginated entities", () => {
return broker.call("posts.list", { sort: "-votes" })
.then(res => {
expect(res.page).toBe(1);
expect(res.pageSize).toBe(10);
expect(res.total).toBe(3);
expect(res.totalPages).toBe(1);

expect(res.rows.length).toBe(3);
expect(res.rows[0].myID).toEqual(posts[1].myID);
expect(res.rows[1].myID).toEqual(posts[0].myID);
expect(res.rows[2].myID).toEqual(posts[2].myID);
});
});

it("should create single entity", () => {
return broker.call("posts.insert", { entity: posts[3] })
.then(res => {
expect(res).toBeInstanceOf(Object);
expect(res._id).toEqual(undefined);
expect(typeof res.myID).toEqual("string");
posts[3].myID = res.myID;
});
});

it("should remove entity by ID", () => {
return broker.call("posts.remove", { id: posts[2].myID })
.then(res => {
expect(res).toBe(1);
});
});
});