mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
Merge pull request #313 from bknd-io/feat/data-implicit-joins
feat: Add implicit joins in repository where clauses
This commit is contained in:
@@ -124,6 +124,81 @@ describe("[Repository]", async () => {
|
||||
.then((r) => [r.count, r.total]),
|
||||
).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 () => {
|
||||
|
||||
@@ -103,6 +103,7 @@ export class Repository<TBD extends object = DefaultDB, TB extends keyof TBD = a
|
||||
validated.with = options.with;
|
||||
}
|
||||
|
||||
// add explicit joins. Implicit joins are added in `where` builder
|
||||
if (options.join && options.join.length > 0) {
|
||||
for (const entry of options.join) {
|
||||
const related = this.em.relationOf(entity.name, entry);
|
||||
@@ -127,13 +128,29 @@ export class Repository<TBD extends object = DefaultDB, TB extends keyof TBD = a
|
||||
const invalid = WhereBuilder.getPropertyNames(options.where).filter((field) => {
|
||||
if (field.includes(".")) {
|
||||
const [alias, prop] = field.split(".") as [string, string];
|
||||
if (!aliases.includes(alias)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
this.checkIndex(entity.name, field, "where");
|
||||
return typeof entity.getField(field) === "undefined";
|
||||
|
||||
@@ -289,7 +289,7 @@ class EntityManagerPrototype<Entities extends Record<string, Entity>> extends En
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user