Skip to content

Commit

Permalink
Add complicated association test with join tables
Browse files Browse the repository at this point in the history
  • Loading branch information
Noah Bogart committed Jan 26, 2021
1 parent f0c014d commit dd7b34e
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 16 deletions.
166 changes: 166 additions & 0 deletions test/acceptance/associations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,3 +291,169 @@ describe("Complex associations", function() {
});
});
});

describe("Associations with a join table", function() {
class User extends Model {
static relationMappings = {};

id: number;
name: string;
teams?: Team[];

get props() {
return {
name: "string",
};
}
}

class Team extends Model {
static relationMappings = {};

id: number;
title: string;
users?: User[];

get props() {
return {
title: "string",
};
}
}

class Membership extends Model {
static idColumn = ["teamId", "userId"];
static relationMappings = {};

teamId: number;
userId: number;

team?: Team;
user?: User;

get props() {
return {
teamId: "integer",
userId: "integer",
};
}
}

User.relationMappings = {
teams: {
relation: Model.ManyToManyRelation,
modelClass: Team,
join: {
from: "users.id",
through: {
from: "memberships.userId",
to: "memberships.teamId",
},
to: "teams.id",
},
},
};

Team.relationMappings = {
users: {
relation: Model.ManyToManyRelation,
modelClass: User,
join: {
from: "teams.id",
through: {
from: "memberships.teamId",
to: "memberships.userId",
},
to: "users.id",
},
},
};

Membership.relationMappings = {
team: {
relation: Model.BelongsToOneRelation,
modelClass: Team,
join: {
from: "memberships.teamId",
to: "teams.id",
},
},
user: {
relation: Model.BelongsToOneRelation,
modelClass: User,
join: {
from: "memberships.userId",
to: "users.id",
},
},
};

let fr: FixtureRiveter;

before(async function() {
await createTable(User);
await createTable(Team);
await createTable(Membership, false);

fr = new FixtureRiveter();
fr.setAdapter(new ObjectionAdapter());

fr.fixture("user", User, (f) => {
f.attr("name", () => "Noah");

f.transient((t) => {
t.attr("team", () => false);
});

f.trait("on a team", (t) => {
t.after("create", async(user, evaluator: any) => {
let team = await evaluator.team();
if (!team) {
team = await fr.create("team");
}

await fr.create("membership", {user, team});
user.$setRelated("teams", [team]);
});
});
});

fr.fixture("team", Team, (f) => {
f.attr("title", () => "The City & The City");

f.transient((t) => {
t.attr("users", () => []);
t.attr("userCount", () => 1);
});

f.trait("with memberships", (t) => {
t.after("create", async(team, evaluator) => {
let users: User[] = await evaluator.attr("users");
const userCount: number = await evaluator.attr("userCount");

if (users.length === 0) {
users = await fr.createList<User>("user", userCount);
}

await Promise.all(users.map(async(user) => {
return fr.create("membership", {team, user});
}));

team.$setRelated("users", users);
});
});
});

fr.fixture("membership", Membership, (f) => {
f.user();
f.team();
});
});

it("works", async function() {
const user = await fr.create<User>("user", ["on a team"]);
expect(user.teams).to.exist.and.to.have.length(1);
const team = await fr.create<Team>("team", ["with memberships"]);
expect(team.users).to.exist.and.to.have.length(1);
});
});
23 changes: 7 additions & 16 deletions test/test-fixtures/define-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,20 @@ import {Model as ObjectionModel} from "objection";

const knex = ObjectionModel.knex();

type ColumnType = (
"integer" | "bigInteger" | "text" | "string" | "float" | "decimal" | "boolean" | "date" |
"datetime" | "time" | "timestamp" | "timestamps" | "dropTimestamps" | "binary" | "enu" |
"json" | "jsonb" | "uuid"
);

export async function createTable(
M: typeof Model,
propsArg?: Record<string, ColumnType>,
id = true,
): Promise<any> {
let props: Record<string, string>;
if (propsArg) {
props = propsArg;
} else {
const instance = new M();
({props} = instance);
}
const instance = new M();
const {props} = instance;

await knex.schema.dropTableIfExists(M.tableName);

await knex.schema.createTable(M.tableName, (table) => {
table.increments("id");
for (const [columnName, type] of Object.entries(props)) {
if (id) {
table.increments("id");
}
for (const [columnName, type] of Object.entries(props as Record<string, string>)) {
table[type](columnName);
}
});
Expand Down

0 comments on commit dd7b34e

Please sign in to comment.