mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
feat(repository): add implicit joins in where clauses
This commit is contained in:
@@ -124,6 +124,81 @@ describe("[Repository]", async () => {
|
|||||||
.then((r) => [r.count, r.total]),
|
.then((r) => [r.count, r.total]),
|
||||||
).resolves.toEqual([undefined, undefined]);
|
).resolves.toEqual([undefined, undefined]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("auto join", async () => {
|
||||||
|
const schema = $em(
|
||||||
|
{
|
||||||
|
posts: $entity("posts", {
|
||||||
|
title: $text(),
|
||||||
|
content: $text(),
|
||||||
|
}),
|
||||||
|
comments: $entity("comments", {
|
||||||
|
content: $text(),
|
||||||
|
}),
|
||||||
|
another: $entity("another", {
|
||||||
|
title: $text(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
({ relation }, { posts, comments }) => {
|
||||||
|
relation(comments).manyToOne(posts);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const em = schema.proto.withConnection(getDummyConnection().dummyConnection);
|
||||||
|
await em.schema().sync({ force: true });
|
||||||
|
|
||||||
|
await em.mutator("posts").insertOne({ title: "post1", content: "content1" });
|
||||||
|
await em
|
||||||
|
.mutator("comments")
|
||||||
|
.insertMany([{ content: "comment1", posts_id: 1 }, { content: "comment2" }] as any);
|
||||||
|
|
||||||
|
const res = await em.repo("comments").findMany({
|
||||||
|
where: {
|
||||||
|
"posts.title": "post1",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.data as any).toEqual([
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
content: "comment1",
|
||||||
|
posts_id: 1,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
{
|
||||||
|
// manual join should still work
|
||||||
|
const res = await em.repo("comments").findMany({
|
||||||
|
join: ["posts"],
|
||||||
|
where: {
|
||||||
|
"posts.title": "post1",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.data as any).toEqual([
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
content: "comment1",
|
||||||
|
posts_id: 1,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// inexistent should be detected and thrown
|
||||||
|
expect(
|
||||||
|
em.repo("comments").findMany({
|
||||||
|
where: {
|
||||||
|
"random.title": "post1",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).rejects.toThrow(/Invalid where field/);
|
||||||
|
|
||||||
|
// existing alias, but not a relation should throw
|
||||||
|
expect(
|
||||||
|
em.repo("comments").findMany({
|
||||||
|
where: {
|
||||||
|
"another.title": "post1",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).rejects.toThrow(/Invalid where field/);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("[data] Repository (Events)", async () => {
|
describe("[data] Repository (Events)", async () => {
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ export class Repository<TBD extends object = DefaultDB, TB extends keyof TBD = a
|
|||||||
validated.with = options.with;
|
validated.with = options.with;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add explicit joins. Implicit joins are added in `where` builder
|
||||||
if (options.join && options.join.length > 0) {
|
if (options.join && options.join.length > 0) {
|
||||||
for (const entry of options.join) {
|
for (const entry of options.join) {
|
||||||
const related = this.em.relationOf(entity.name, entry);
|
const related = this.em.relationOf(entity.name, entry);
|
||||||
@@ -127,12 +128,28 @@ export class Repository<TBD extends object = DefaultDB, TB extends keyof TBD = a
|
|||||||
const invalid = WhereBuilder.getPropertyNames(options.where).filter((field) => {
|
const invalid = WhereBuilder.getPropertyNames(options.where).filter((field) => {
|
||||||
if (field.includes(".")) {
|
if (field.includes(".")) {
|
||||||
const [alias, prop] = field.split(".") as [string, string];
|
const [alias, prop] = field.split(".") as [string, string];
|
||||||
if (!aliases.includes(alias)) {
|
// check aliases first (added joins)
|
||||||
|
if (aliases.includes(alias)) {
|
||||||
|
this.checkIndex(alias, prop, "where");
|
||||||
|
return !this.em.entity(alias).getField(prop);
|
||||||
|
}
|
||||||
|
// check if alias (entity) exists
|
||||||
|
if (!this.em.hasEntity(alias)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// check related fields for auto join
|
||||||
|
const related = this.em.relationOf(entity.name, alias);
|
||||||
|
if (related) {
|
||||||
|
const other = related.other(entity);
|
||||||
|
if (other.entity.getField(prop)) {
|
||||||
|
// if related field is found, add join to validated options
|
||||||
|
validated.join?.push(alias);
|
||||||
|
this.checkIndex(alias, prop, "where");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.checkIndex(alias, prop, "where");
|
return true;
|
||||||
return !this.em.entity(alias).getField(prop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.checkIndex(entity.name, field, "where");
|
this.checkIndex(entity.name, field, "where");
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ class EntityManagerPrototype<Entities extends Record<string, Entity>> extends En
|
|||||||
super(Object.values(__entities), new DummyConnection(), relations, indices);
|
super(Object.values(__entities), new DummyConnection(), relations, indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
withConnection(connection: Connection): EntityManager<Schema<Entities>> {
|
withConnection(connection: Connection): EntityManager<Schemas<Entities>> {
|
||||||
return new EntityManager(this.entities, connection, this.relations.all, this.indices);
|
return new EntityManager(this.entities, connection, this.relations.all, this.indices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user