mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-15 20:17:22 +00:00
369 lines
13 KiB
TypeScript
369 lines
13 KiB
TypeScript
// eslint-disable-next-line import/no-unresolved
|
|
import { afterAll, describe, expect, test } from "bun:test";
|
|
import { Entity, EntityManager, TextField } from "../../src/data";
|
|
import {
|
|
ManyToManyRelation,
|
|
ManyToOneRelation,
|
|
OneToOneRelation,
|
|
PolymorphicRelation,
|
|
RelationField
|
|
} from "../../src/data/relations";
|
|
import { getDummyConnection } from "./helper";
|
|
|
|
const { dummyConnection, afterAllCleanup } = getDummyConnection();
|
|
afterAll(afterAllCleanup);
|
|
|
|
describe("Relations", async () => {
|
|
test("RelationField", async () => {
|
|
const em = new EntityManager([], dummyConnection);
|
|
const schema = em.connection.kysely.schema;
|
|
|
|
//const r1 = new RelationField(new Entity("users"));
|
|
const r1 = new RelationField("users_id", {
|
|
reference: "users",
|
|
target: "users",
|
|
target_field: "id"
|
|
});
|
|
|
|
const sql1 = schema
|
|
.createTable("posts")
|
|
.addColumn(...r1.schema()!)
|
|
.compile().sql;
|
|
|
|
expect(sql1).toBe(
|
|
'create table "posts" ("users_id" integer references "users" ("id") on delete set null)'
|
|
);
|
|
|
|
//const r2 = new RelationField(new Entity("users"), "author");
|
|
const r2 = new RelationField("author_id", {
|
|
reference: "author",
|
|
target: "users",
|
|
target_field: "id"
|
|
});
|
|
|
|
const sql2 = schema
|
|
.createTable("posts")
|
|
.addColumn(...r2.schema()!)
|
|
.compile().sql;
|
|
|
|
expect(sql2).toBe(
|
|
'create table "posts" ("author_id" integer references "users" ("id") on delete set null)'
|
|
);
|
|
});
|
|
|
|
test("Required RelationField", async () => {
|
|
//const r1 = new RelationField(new Entity("users"), undefined, { required: true });
|
|
const r1 = new RelationField("users_id", {
|
|
reference: "users",
|
|
target: "users",
|
|
target_field: "id",
|
|
required: true
|
|
});
|
|
expect(r1.isRequired()).toBeTrue();
|
|
});
|
|
|
|
test("ManyToOne", async () => {
|
|
const users = new Entity("users", [new TextField("username")]);
|
|
const posts = new Entity("posts", [
|
|
new TextField("title", {
|
|
maxLength: 2
|
|
})
|
|
]);
|
|
|
|
const entities = [users, posts];
|
|
|
|
const relationName = "author";
|
|
const relations = [new ManyToOneRelation(posts, users, { mappedBy: relationName })];
|
|
const em = new EntityManager(entities, dummyConnection, relations);
|
|
|
|
// verify naming
|
|
const rel = em.relations.all[0];
|
|
expect(rel.source.entity.name).toBe(posts.name);
|
|
expect(rel.source.reference).toBe(posts.name);
|
|
expect(rel.target.entity.name).toBe(users.name);
|
|
expect(rel.target.reference).toBe(relationName);
|
|
|
|
// verify field
|
|
expect(posts.field(relationName + "_id")).toBeInstanceOf(RelationField);
|
|
|
|
// verify low level relation
|
|
expect(em.relationsOf(users.name).length).toBe(1);
|
|
expect(em.relationsOf(users.name).length).toBe(1);
|
|
expect(em.relationsOf(users.name)[0].source.entity).toBe(posts);
|
|
expect(posts.field("author_id")).toBeInstanceOf(RelationField);
|
|
expect(em.relationsOf(users.name).length).toBe(1);
|
|
expect(em.relationsOf(users.name).length).toBe(1);
|
|
expect(em.relationsOf(users.name)[0].source.entity).toBe(posts);
|
|
|
|
// verify high level relation (from users)
|
|
const userPostsRel = em.relationOf(users.name, "posts");
|
|
expect(userPostsRel).toBeInstanceOf(ManyToOneRelation);
|
|
expect(userPostsRel?.other(users).entity).toBe(posts);
|
|
|
|
// verify high level relation (from posts)
|
|
const postAuthorRel = em.relationOf(posts.name, "author")! as ManyToOneRelation;
|
|
expect(postAuthorRel).toBeInstanceOf(ManyToOneRelation);
|
|
expect(postAuthorRel?.other(posts).entity).toBe(users);
|
|
|
|
const kysely = em.connection.kysely;
|
|
const jsonFrom = (e) => e;
|
|
/**
|
|
* Relation Helper
|
|
*/
|
|
/**
|
|
* FROM POSTS
|
|
* ----------
|
|
- lhs: posts.author_id
|
|
- rhs: users.id
|
|
- as: author
|
|
- select: users.*
|
|
- cardinality: 1
|
|
*/
|
|
const selectPostsFromUsers = postAuthorRel.buildWith(
|
|
users,
|
|
kysely.selectFrom(users.name),
|
|
jsonFrom,
|
|
"posts"
|
|
);
|
|
expect(selectPostsFromUsers.compile().sql).toBe(
|
|
'select (select "posts"."id" as "id", "posts"."title" as "title", "posts"."author_id" as "author_id" from "posts" as "posts" where "posts"."author_id" = "users"."id" limit ?) as "posts" from "users"'
|
|
);
|
|
expect(postAuthorRel!.getField()).toBeInstanceOf(RelationField);
|
|
const userObj = { id: 1, username: "test" };
|
|
expect(postAuthorRel.hydrate(users, [userObj], em)).toEqual(userObj);
|
|
|
|
/**
|
|
FROM USERS
|
|
----------
|
|
- lhs: posts.author_id
|
|
- rhs: users.id
|
|
- as: posts
|
|
- select: posts.*
|
|
- cardinality:
|
|
*/
|
|
const selectUsersFromPosts = postAuthorRel.buildWith(
|
|
posts,
|
|
kysely.selectFrom(posts.name),
|
|
jsonFrom,
|
|
"author"
|
|
);
|
|
|
|
expect(selectUsersFromPosts.compile().sql).toBe(
|
|
'select (select "author"."id" as "id", "author"."username" as "username" from "users" as "author" where "author"."id" = "posts"."author_id" limit ?) as "author" from "posts"'
|
|
);
|
|
expect(postAuthorRel.getField()).toBeInstanceOf(RelationField);
|
|
const postObj = { id: 1, title: "test" };
|
|
expect(postAuthorRel.hydrate(posts, [postObj], em)).toEqual([postObj]);
|
|
|
|
// mutation info
|
|
expect(postAuthorRel!.helper(users.name)!.getMutationInfo()).toEqual({
|
|
reference: "posts",
|
|
local_field: undefined,
|
|
$set: false,
|
|
$create: false,
|
|
$attach: false,
|
|
$detach: false,
|
|
primary: undefined,
|
|
cardinality: undefined,
|
|
relation_type: "n:1"
|
|
});
|
|
|
|
expect(postAuthorRel!.helper(posts.name)!.getMutationInfo()).toEqual({
|
|
reference: "author",
|
|
local_field: "author_id",
|
|
$set: true,
|
|
$create: false,
|
|
$attach: false,
|
|
$detach: false,
|
|
primary: "id",
|
|
cardinality: 1,
|
|
relation_type: "n:1"
|
|
});
|
|
|
|
/*console.log("ManyToOne (source=posts, target=users)");
|
|
// prettier-ignore
|
|
console.log("users perspective",postAuthorRel!.helper(users.name)!.getMutationInfo());
|
|
// prettier-ignore
|
|
console.log("posts perspective", postAuthorRel!.helper(posts.name)!.getMutationInfo());
|
|
console.log("");*/
|
|
});
|
|
|
|
test("OneToOne", async () => {
|
|
const users = new Entity("users", [new TextField("username")]);
|
|
const settings = new Entity("settings", [new TextField("theme")]);
|
|
|
|
const entities = [users, settings];
|
|
const relations = [new OneToOneRelation(users, settings)];
|
|
|
|
const em = new EntityManager(entities, dummyConnection, relations);
|
|
|
|
// verify naming
|
|
const rel = em.relations.all[0];
|
|
expect(rel.source.entity.name).toBe(users.name);
|
|
expect(rel.source.reference).toBe(users.name);
|
|
expect(rel.target.entity.name).toBe(settings.name);
|
|
expect(rel.target.reference).toBe(settings.name);
|
|
|
|
// verify fields (only one added to users (source))
|
|
expect(users.field("settings_id")).toBeInstanceOf(RelationField);
|
|
|
|
expect(em.relationsOf(users.name).length).toBe(1);
|
|
expect(em.relationsOf(users.name).length).toBe(1);
|
|
expect(em.relationsOf(users.name)[0].source.entity).toBe(users);
|
|
expect(em.relationsOf(users.name)[0].target.entity).toBe(settings);
|
|
|
|
// verify high level relation (from users)
|
|
const userSettingRel = em.relationOf(users.name, settings.name);
|
|
expect(userSettingRel).toBeInstanceOf(OneToOneRelation);
|
|
expect(userSettingRel?.other(users).entity.name).toBe(settings.name);
|
|
|
|
// verify high level relation (from settings)
|
|
const settingUserRel = em.relationOf(settings.name, users.name);
|
|
expect(settingUserRel).toBeInstanceOf(OneToOneRelation);
|
|
expect(settingUserRel?.other(settings).entity.name).toBe(users.name);
|
|
|
|
// mutation info
|
|
expect(userSettingRel!.helper(users.name)!.getMutationInfo()).toEqual({
|
|
reference: "settings",
|
|
local_field: "settings_id",
|
|
$set: true,
|
|
$create: true,
|
|
$attach: false,
|
|
$detach: false,
|
|
primary: "id",
|
|
cardinality: 1,
|
|
relation_type: "1:1"
|
|
});
|
|
expect(userSettingRel!.helper(settings.name)!.getMutationInfo()).toEqual({
|
|
reference: "users",
|
|
local_field: undefined,
|
|
$set: false,
|
|
$create: false,
|
|
$attach: false,
|
|
$detach: false,
|
|
primary: undefined,
|
|
cardinality: 1,
|
|
relation_type: "1:1"
|
|
});
|
|
|
|
/*console.log("");
|
|
console.log("OneToOne (source=users, target=settings)");
|
|
// prettier-ignore
|
|
console.log("users perspective",userSettingRel!.helper(users.name)!.getMutationInfo());
|
|
// prettier-ignore
|
|
console.log("settings perspective", userSettingRel!.helper(settings.name)!.getMutationInfo());
|
|
console.log("");*/
|
|
});
|
|
|
|
test("ManyToMany", async () => {
|
|
const posts = new Entity("posts", [new TextField("title")]);
|
|
const categories = new Entity("categories", [new TextField("label")]);
|
|
|
|
const entities = [posts, categories];
|
|
const relations = [new ManyToManyRelation(posts, categories)];
|
|
|
|
const em = new EntityManager(entities, dummyConnection, relations);
|
|
|
|
//console.log((await em.schema().sync(true)).map((s) => s.sql).join(";\n"));
|
|
|
|
// don't expect new fields bc of connection table
|
|
expect(posts.getFields().length).toBe(2);
|
|
expect(categories.getFields().length).toBe(2);
|
|
|
|
// expect relations set
|
|
expect(em.relationsOf(posts.name).length).toBe(1);
|
|
expect(em.relationsOf(categories.name).length).toBe(1);
|
|
|
|
// expect connection table with fields
|
|
expect(em.entity("posts_categories")).toBeInstanceOf(Entity);
|
|
expect(em.entity("posts_categories").getFields().length).toBe(3);
|
|
expect(em.entity("posts_categories").field("posts_id")).toBeInstanceOf(RelationField);
|
|
expect(em.entity("posts_categories").field("categories_id")).toBeInstanceOf(RelationField);
|
|
|
|
// verify high level relation (from posts)
|
|
const postCategoriesRel = em.relationOf(posts.name, categories.name);
|
|
expect(postCategoriesRel).toBeInstanceOf(ManyToManyRelation);
|
|
expect(postCategoriesRel?.other(posts).entity.name).toBe(categories.name);
|
|
|
|
//console.log("relation", postCategoriesRel);
|
|
|
|
// verify high level relation (from posts)
|
|
const categoryPostsRel = em.relationOf(categories.name, posts.name);
|
|
expect(categoryPostsRel).toBeInstanceOf(ManyToManyRelation);
|
|
expect(categoryPostsRel?.other(categories.name).entity.name).toBe(posts.name);
|
|
|
|
// now get connection table from relation (from posts)
|
|
if (postCategoriesRel instanceof ManyToManyRelation) {
|
|
expect(postCategoriesRel.connectionEntity.name).toBe("posts_categories");
|
|
expect(em.entity(postCategoriesRel.connectionEntity.name).name).toBe("posts_categories");
|
|
} else {
|
|
throw new Error("Expected ManyToManyRelation");
|
|
}
|
|
|
|
/**
|
|
* Relation Helper
|
|
*/
|
|
const kysely = em.connection.kysely;
|
|
const jsonFrom = (e) => e;
|
|
|
|
/**
|
|
* FROM POSTS
|
|
* ----------
|
|
- lhs: posts.author_id
|
|
- rhs: users.id
|
|
- as: author
|
|
- select: users.*
|
|
- cardinality: 1
|
|
*/
|
|
const selectCategoriesFromPosts = postCategoriesRel.buildWith(
|
|
posts,
|
|
kysely.selectFrom(posts.name),
|
|
jsonFrom
|
|
);
|
|
expect(selectCategoriesFromPosts.compile().sql).toBe(
|
|
'select (select "categories"."id" as "id", "categories"."label" as "label" from "categories" inner join "posts_categories" on "categories"."id" = "posts_categories"."categories_id" where "posts"."id" = "posts_categories"."posts_id" limit ?) as "categories" from "posts"'
|
|
);
|
|
|
|
const selectPostsFromCategories = postCategoriesRel.buildWith(
|
|
categories,
|
|
kysely.selectFrom(categories.name),
|
|
jsonFrom
|
|
);
|
|
expect(selectPostsFromCategories.compile().sql).toBe(
|
|
'select (select "posts"."id" as "id", "posts"."title" as "title" from "posts" inner join "posts_categories" on "posts"."id" = "posts_categories"."posts_id" where "categories"."id" = "posts_categories"."categories_id" limit ?) as "posts" from "categories"'
|
|
);
|
|
|
|
// mutation info
|
|
expect(relations[0].helper(posts.name)!.getMutationInfo()).toEqual({
|
|
reference: "categories",
|
|
local_field: undefined,
|
|
$set: false,
|
|
$create: false,
|
|
$attach: true,
|
|
$detach: true,
|
|
primary: "id",
|
|
cardinality: undefined,
|
|
relation_type: "m:n"
|
|
});
|
|
expect(relations[0].helper(categories.name)!.getMutationInfo()).toEqual({
|
|
reference: "posts",
|
|
local_field: undefined,
|
|
$set: false,
|
|
$create: false,
|
|
$attach: false,
|
|
$detach: false,
|
|
primary: undefined,
|
|
cardinality: undefined,
|
|
relation_type: "m:n"
|
|
});
|
|
|
|
/*console.log("");
|
|
console.log("ManyToMany (source=posts, target=categories)");
|
|
// prettier-ignore
|
|
console.log("posts perspective",relations[0].helper(posts.name)!.getMutationInfo());
|
|
// prettier-ignore
|
|
console.log("categories perspective", relations[0]!.helper(categories.name)!.getMutationInfo());
|
|
console.log("");*/
|
|
});
|
|
});
|