ModelQuery: add nested eagerloading
This commit is contained in:
parent
e86356ae74
commit
0e37014667
@ -41,6 +41,7 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
|
|||||||
private _sortBy?: string;
|
private _sortBy?: string;
|
||||||
private _sortDirection?: 'ASC' | 'DESC';
|
private _sortDirection?: 'ASC' | 'DESC';
|
||||||
private readonly relations: string[] = [];
|
private readonly relations: string[] = [];
|
||||||
|
private readonly subRelations: { [relation: string]: string[] } = {};
|
||||||
private _pivot?: string[];
|
private _pivot?: string[];
|
||||||
private _union?: ModelQueryUnion;
|
private _union?: ModelQueryUnion;
|
||||||
private _recursiveRelation?: RelationDatabaseProperties;
|
private _recursiveRelation?: RelationDatabaseProperties;
|
||||||
@ -102,10 +103,18 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param relation The relation field name to eagerload
|
* @param relations The relations field names to eagerload. To load nested relations, separate fields with '.'
|
||||||
|
* (i.e.: "author.roles.permissions" loads authors, their roles, and the permissions of these roles)
|
||||||
*/
|
*/
|
||||||
public with(relation: string): this {
|
public with(...relations: string[]): this {
|
||||||
this.relations.push(relation);
|
relations.forEach(relation => {
|
||||||
|
const parts = relation.split('.');
|
||||||
|
this.relations.push(parts[0]);
|
||||||
|
if (parts.length > 1) {
|
||||||
|
if (!this.subRelations[parts[0]]) this.subRelations[parts[0]] = [];
|
||||||
|
this.subRelations[parts[0]].push(parts.slice(1).join('.'));
|
||||||
|
}
|
||||||
|
});
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +284,7 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
|
|||||||
for (const relationName of this.relations) {
|
for (const relationName of this.relations) {
|
||||||
const relations = relationMap[relationName];
|
const relations = relationMap[relationName];
|
||||||
if (relations.length > 0) {
|
if (relations.length > 0) {
|
||||||
const allModels = await relations[0].eagerLoad(relations);
|
const allModels = await relations[0].eagerLoad(relations, this.subRelations[relationName]);
|
||||||
await Promise.all(relations.map(r => r.populate(allModels)));
|
await Promise.all(relations.map(r => r.populate(allModels)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,12 +69,13 @@ export default abstract class ModelRelation<S extends Model, O extends Model, R
|
|||||||
|
|
||||||
protected abstract collectionToOutput(models: O[]): R;
|
protected abstract collectionToOutput(models: O[]): R;
|
||||||
|
|
||||||
public async eagerLoad(relations: ModelRelation<S, O, R>[]): Promise<ModelQueryResult<O>> {
|
public async eagerLoad(relations: ModelRelation<S, O, R>[], subRelations: string[] = []): Promise<ModelQueryResult<O>> {
|
||||||
const ids = relations.map(r => r.getModelID()).filter(id => id !== null && id !== undefined);
|
const ids = relations.map(r => r.getModelID()).filter(id => id !== null && id !== undefined);
|
||||||
if (ids.length === 0) return [];
|
if (ids.length === 0) return [];
|
||||||
|
|
||||||
const query = this.makeQuery();
|
const query = this.makeQuery();
|
||||||
query.where(this.dbProperties.foreignKey, ids, WhereTest.IN);
|
query.where(this.dbProperties.foreignKey, ids, WhereTest.IN);
|
||||||
|
query.with(...subRelations);
|
||||||
return await query.get();
|
return await query.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,13 +176,14 @@ export class ManyThroughModelRelation<S extends Model, O extends Model> extends
|
|||||||
query.where(`pivot.${this.dbProperties.localPivotKey}`, this.getModelID());
|
query.where(`pivot.${this.dbProperties.localPivotKey}`, this.getModelID());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async eagerLoad(relations: ModelRelation<S, O, O[]>[]): Promise<ModelQueryResult<O>> {
|
public async eagerLoad(relations: ModelRelation<S, O, O[]>[], subRelations: string[] = []): Promise<ModelQueryResult<O>> {
|
||||||
const ids = relations.map(r => r.getModelID());
|
const ids = relations.map(r => r.getModelID());
|
||||||
if (ids.length === 0) return [];
|
if (ids.length === 0) return [];
|
||||||
|
|
||||||
const query = this.makeQuery();
|
const query = this.makeQuery();
|
||||||
query.where(`pivot.${this.dbProperties.localPivotKey}`, ids, WhereTest.IN);
|
query.where(`pivot.${this.dbProperties.localPivotKey}`, ids, WhereTest.IN);
|
||||||
query.pivot(`pivot.${this.dbProperties.localPivotKey}`, `pivot.${this.dbProperties.foreignPivotKey}`);
|
query.pivot(`pivot.${this.dbProperties.localPivotKey}`, `pivot.${this.dbProperties.foreignPivotKey}`);
|
||||||
|
query.with(...subRelations);
|
||||||
return await query.get();
|
return await query.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import {MIGRATIONS} from "./_migrations";
|
|||||||
import ModelFactory from "../src/db/ModelFactory";
|
import ModelFactory from "../src/db/ModelFactory";
|
||||||
import {ValidationBag} from "../src/db/Validator";
|
import {ValidationBag} from "../src/db/Validator";
|
||||||
import Logger from "../src/Logger";
|
import Logger from "../src/Logger";
|
||||||
|
import {ManyThroughModelRelation, OneModelRelation} from "../src/db/ModelRelation";
|
||||||
|
|
||||||
class FakeDummyModel extends Model {
|
class FakeDummyModel extends Model {
|
||||||
public id?: number = undefined;
|
public id?: number = undefined;
|
||||||
@ -16,24 +17,229 @@ class FakeDummyModel extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let factory: ModelFactory<FakeDummyModel>;
|
class Post extends Model {
|
||||||
|
public id?: number = undefined;
|
||||||
|
public author_id?: number = undefined;
|
||||||
|
public content?: string = undefined;
|
||||||
|
|
||||||
|
public readonly author: OneModelRelation<Post, Author> = new OneModelRelation<Post, Author>(this, ModelFactory.get(Author), {
|
||||||
|
localKey: 'author_id',
|
||||||
|
foreignKey: 'id',
|
||||||
|
});
|
||||||
|
|
||||||
|
protected init(): void {
|
||||||
|
this.setValidation('author_id').defined().exists(Author, 'id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Author extends Model {
|
||||||
|
public id?: number = undefined;
|
||||||
|
public name?: string = undefined;
|
||||||
|
|
||||||
|
public readonly roles: ManyThroughModelRelation<Author, Role> = new ManyThroughModelRelation<Author, Role>(this, ModelFactory.get(Role), {
|
||||||
|
localKey: 'id',
|
||||||
|
foreignKey: 'id',
|
||||||
|
pivotTable: 'author_role',
|
||||||
|
localPivotKey: 'author_id',
|
||||||
|
foreignPivotKey: 'role_id',
|
||||||
|
});
|
||||||
|
|
||||||
|
protected init(): void {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Role extends Model {
|
||||||
|
public id?: number = undefined;
|
||||||
|
public name?: string = undefined;
|
||||||
|
|
||||||
|
public readonly permissions: ManyThroughModelRelation<Role, Permission> = new ManyThroughModelRelation<Role, Permission>(this, ModelFactory.get(Permission), {
|
||||||
|
localKey: 'id',
|
||||||
|
foreignKey: 'id',
|
||||||
|
pivotTable: 'role_permission',
|
||||||
|
localPivotKey: 'role_id',
|
||||||
|
foreignPivotKey: 'permission_id',
|
||||||
|
});
|
||||||
|
|
||||||
|
protected init(): void {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Permission extends Model {
|
||||||
|
public id?: number = undefined;
|
||||||
|
public name?: string = undefined;
|
||||||
|
|
||||||
|
protected init(): void {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AuthorRole extends Model {
|
||||||
|
public static get table(): string {
|
||||||
|
return 'author_role';
|
||||||
|
}
|
||||||
|
|
||||||
|
public author_id?: number = undefined;
|
||||||
|
public role_id?: number = undefined;
|
||||||
|
|
||||||
|
protected init(): void {
|
||||||
|
this.setValidation('author_id').defined().exists(Author, 'id');
|
||||||
|
this.setValidation('role_id').defined().exists(Role, 'id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RolePermission extends Model {
|
||||||
|
public static get table(): string {
|
||||||
|
return 'role_permission';
|
||||||
|
}
|
||||||
|
|
||||||
|
public role_id?: number = undefined;
|
||||||
|
public permission_id?: number = undefined;
|
||||||
|
|
||||||
|
protected init(): void {
|
||||||
|
this.setValidation('role_id').defined().exists(Role, 'id');
|
||||||
|
this.setValidation('permission_id').defined().exists(Permission, 'id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let fakeDummyModelModelFactory: ModelFactory<FakeDummyModel>;
|
||||||
|
|
||||||
|
let postFactory: ModelFactory<Post>;
|
||||||
|
let authorFactory: ModelFactory<Author>;
|
||||||
|
let roleFactory: ModelFactory<Role>;
|
||||||
|
let permissionFactory: ModelFactory<Permission>;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
Logger.verbose();
|
Logger.verbose();
|
||||||
MysqlConnectionManager.registerMigrations(MIGRATIONS);
|
MysqlConnectionManager.registerMigrations(MIGRATIONS);
|
||||||
ModelFactory.register(FakeDummyModel);
|
ModelFactory.register(FakeDummyModel);
|
||||||
|
ModelFactory.register(Post);
|
||||||
|
ModelFactory.register(Author);
|
||||||
|
ModelFactory.register(Role);
|
||||||
|
ModelFactory.register(Permission);
|
||||||
|
ModelFactory.register(AuthorRole);
|
||||||
|
ModelFactory.register(RolePermission);
|
||||||
await MysqlConnectionManager.prepare();
|
await MysqlConnectionManager.prepare();
|
||||||
|
|
||||||
// Create FakeDummyModel table
|
// Create FakeDummyModel table
|
||||||
factory = ModelFactory.get(FakeDummyModel);
|
fakeDummyModelModelFactory = ModelFactory.get(FakeDummyModel);
|
||||||
await MysqlConnectionManager.query(`DROP TABLE IF EXISTS ${(factory.table)}`);
|
postFactory = ModelFactory.get(Post);
|
||||||
await MysqlConnectionManager.query(`CREATE TABLE ${(factory.table)}(
|
authorFactory = ModelFactory.get(Author);
|
||||||
|
roleFactory = ModelFactory.get(Role);
|
||||||
|
permissionFactory = ModelFactory.get(Permission);
|
||||||
|
|
||||||
|
await MysqlConnectionManager.query(`DROP TABLE IF EXISTS author_role`);
|
||||||
|
await MysqlConnectionManager.query(`DROP TABLE IF EXISTS role_permission`);
|
||||||
|
for (const factory of [
|
||||||
|
fakeDummyModelModelFactory,
|
||||||
|
postFactory,
|
||||||
|
authorFactory,
|
||||||
|
roleFactory,
|
||||||
|
permissionFactory
|
||||||
|
]) {
|
||||||
|
await MysqlConnectionManager.query(`DROP TABLE IF EXISTS ${(factory.table)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await MysqlConnectionManager.query(`CREATE TABLE ${(fakeDummyModelModelFactory.table)}(
|
||||||
id INT NOT NULL AUTO_INCREMENT,
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
name VARCHAR(256),
|
name VARCHAR(256),
|
||||||
date DATETIME,
|
date DATETIME,
|
||||||
date_default DATETIME DEFAULT NOW(),
|
date_default DATETIME DEFAULT NOW(),
|
||||||
PRIMARY KEY(id)
|
PRIMARY KEY(id)
|
||||||
)`);
|
)`);
|
||||||
|
|
||||||
|
await MysqlConnectionManager.query(`CREATE TABLE ${(authorFactory.table)}(
|
||||||
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
name VARCHAR(64),
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
)`);
|
||||||
|
await MysqlConnectionManager.query(`CREATE TABLE ${(postFactory.table)}(
|
||||||
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
author_id INT NOT NULL,
|
||||||
|
content VARCHAR(512),
|
||||||
|
PRIMARY KEY(id),
|
||||||
|
FOREIGN KEY post_author_fk (author_id) REFERENCES ${(authorFactory.table)} (id)
|
||||||
|
)`);
|
||||||
|
await MysqlConnectionManager.query(`CREATE TABLE ${(roleFactory.table)}(
|
||||||
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
name VARCHAR(64),
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
)`);
|
||||||
|
await MysqlConnectionManager.query(`CREATE TABLE ${(permissionFactory.table)}(
|
||||||
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
name VARCHAR(64),
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
)`);
|
||||||
|
|
||||||
|
await MysqlConnectionManager.query(`CREATE TABLE author_role(
|
||||||
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
author_id INT NOT NULL,
|
||||||
|
role_id INT NOT NULL,
|
||||||
|
PRIMARY KEY(id),
|
||||||
|
FOREIGN KEY author_role_author_fk (author_id) REFERENCES ${(authorFactory.table)} (id),
|
||||||
|
FOREIGN KEY author_role_role_fk (role_id) REFERENCES ${(roleFactory.table)} (id)
|
||||||
|
)`);
|
||||||
|
await MysqlConnectionManager.query(`CREATE TABLE role_permission(
|
||||||
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
role_id INT NOT NULL,
|
||||||
|
permission_id INT NOT NULL,
|
||||||
|
PRIMARY KEY(id),
|
||||||
|
FOREIGN KEY role_permission_role_fk (role_id) REFERENCES ${(roleFactory.table)} (id),
|
||||||
|
FOREIGN KEY role_permission_permission_fk (permission_id) REFERENCES ${(permissionFactory.table)} (id)
|
||||||
|
)`);
|
||||||
|
|
||||||
|
|
||||||
|
/// SEED ///
|
||||||
|
|
||||||
|
// permissions
|
||||||
|
createPostPermission = Permission.create({name: 'create-post'});
|
||||||
|
await createPostPermission.save();
|
||||||
|
|
||||||
|
moderatePostPermission = Permission.create({name: 'moderate-post'});
|
||||||
|
await moderatePostPermission.save();
|
||||||
|
|
||||||
|
viewLogsPermission = Permission.create({name: 'view-logs'});
|
||||||
|
await viewLogsPermission.save();
|
||||||
|
|
||||||
|
|
||||||
|
// roles
|
||||||
|
guestRole = Role.create({name: 'guest'});
|
||||||
|
await guestRole.save();
|
||||||
|
await RolePermission.create({role_id: guestRole.id, permission_id: createPostPermission.id}).save();
|
||||||
|
|
||||||
|
moderatorRole = Role.create({name: 'moderator'});
|
||||||
|
await moderatorRole.save();
|
||||||
|
await RolePermission.create({role_id: moderatorRole.id, permission_id: createPostPermission.id}).save();
|
||||||
|
await RolePermission.create({role_id: moderatorRole.id, permission_id: moderatePostPermission.id}).save();
|
||||||
|
|
||||||
|
adminRole = Role.create({name: 'admin'});
|
||||||
|
await adminRole.save();
|
||||||
|
await RolePermission.create({role_id: adminRole.id, permission_id: createPostPermission.id}).save();
|
||||||
|
await RolePermission.create({role_id: adminRole.id, permission_id: moderatePostPermission.id}).save();
|
||||||
|
await RolePermission.create({role_id: adminRole.id, permission_id: viewLogsPermission.id}).save();
|
||||||
|
|
||||||
|
|
||||||
|
// authors
|
||||||
|
glimmerAuthor = Author.create({name: 'glimmer'});
|
||||||
|
await glimmerAuthor.save();
|
||||||
|
await AuthorRole.create({author_id: glimmerAuthor.id, role_id: guestRole.id}).save();
|
||||||
|
|
||||||
|
bowAuthor = Author.create({name: 'bow'});
|
||||||
|
await bowAuthor.save();
|
||||||
|
await AuthorRole.create({author_id: bowAuthor.id, role_id: moderatorRole.id}).save();
|
||||||
|
|
||||||
|
adoraAuthor = Author.create({name: 'adora'});
|
||||||
|
await adoraAuthor.save();
|
||||||
|
await AuthorRole.create({author_id: adoraAuthor.id, role_id: adminRole.id}).save();
|
||||||
|
|
||||||
|
|
||||||
|
// posts
|
||||||
|
post1 = Post.create({author_id: glimmerAuthor.id, content: 'I\'m the queen now and you\'ll do as I order.'});
|
||||||
|
await post1.save();
|
||||||
|
|
||||||
|
post2 = Post.create({author_id: adoraAuthor.id, content: 'But you\'re wrong!'});
|
||||||
|
await post2.save();
|
||||||
|
|
||||||
|
post3 = Post.create({author_id: bowAuthor.id, content: 'Come on guys, let\'s talk this through.'});
|
||||||
|
await post3.save();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@ -43,7 +249,7 @@ afterAll(async () => {
|
|||||||
describe('Model', () => {
|
describe('Model', () => {
|
||||||
it('should construct properly', () => {
|
it('should construct properly', () => {
|
||||||
const date = new Date(888);
|
const date = new Date(888);
|
||||||
const model = factory.create({
|
const model = fakeDummyModelModelFactory.create({
|
||||||
name: 'a_name',
|
name: 'a_name',
|
||||||
date: date,
|
date: date,
|
||||||
non_existing_property: 'dropped_value',
|
non_existing_property: 'dropped_value',
|
||||||
@ -57,17 +263,17 @@ describe('Model', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should have a proper table name', () => {
|
it('should have a proper table name', () => {
|
||||||
expect(factory.table).toBe('fake_dummy_models');
|
expect(fakeDummyModelModelFactory.table).toBe('fake_dummy_models');
|
||||||
expect(FakeDummyModel.table).toBe('fake_dummy_models');
|
expect(FakeDummyModel.table).toBe('fake_dummy_models');
|
||||||
expect(FakeDummyModel.create({}).table).toBe('fake_dummy_models');
|
expect(FakeDummyModel.create({}).table).toBe('fake_dummy_models');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should insert properly', async () => {
|
it('should insert properly', async () => {
|
||||||
const date = new Date(569985);
|
const date = new Date(569985);
|
||||||
const insertInstance: FakeDummyModel | null = factory.create({
|
const insertInstance: FakeDummyModel | null = fakeDummyModelModelFactory.create({
|
||||||
name: 'name1',
|
name: 'name1',
|
||||||
date: date,
|
date: date,
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
|
|
||||||
// Insert
|
// Insert
|
||||||
@ -88,14 +294,14 @@ describe('Model', () => {
|
|||||||
expect(retrievedInstance!.date?.getTime()).toBeCloseTo(date.getTime(), -4);
|
expect(retrievedInstance!.date?.getTime()).toBeCloseTo(date.getTime(), -4);
|
||||||
expect(retrievedInstance!.date_default).toBeDefined();
|
expect(retrievedInstance!.date_default).toBeDefined();
|
||||||
|
|
||||||
const failingInsertModel = factory.create({
|
const failingInsertModel = fakeDummyModelModelFactory.create({
|
||||||
name: 'a',
|
name: 'a',
|
||||||
}, true);
|
}, true);
|
||||||
await expect(failingInsertModel.save()).rejects.toBeInstanceOf(ValidationBag);
|
await expect(failingInsertModel.save()).rejects.toBeInstanceOf(ValidationBag);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update properly', async () => {
|
it('should update properly', async () => {
|
||||||
const insertModel = factory.create({
|
const insertModel = fakeDummyModelModelFactory.create({
|
||||||
name: 'update',
|
name: 'update',
|
||||||
}, true);
|
}, true);
|
||||||
await insertModel.save();
|
await insertModel.save();
|
||||||
@ -116,7 +322,7 @@ describe('Model', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should delete properly', async () => {
|
it('should delete properly', async () => {
|
||||||
const insertModel = factory.create({
|
const insertModel = fakeDummyModelModelFactory.create({
|
||||||
name: 'delete',
|
name: 'delete',
|
||||||
}, true);
|
}, true);
|
||||||
await insertModel.save();
|
await insertModel.save();
|
||||||
@ -129,4 +335,57 @@ describe('Model', () => {
|
|||||||
const postDeleteModel = await FakeDummyModel.getById(insertModel.id);
|
const postDeleteModel = await FakeDummyModel.getById(insertModel.id);
|
||||||
expect(postDeleteModel).toBeNull();
|
expect(postDeleteModel).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let createPostPermission: Permission;
|
||||||
|
let moderatePostPermission: Permission;
|
||||||
|
let viewLogsPermission: Permission;
|
||||||
|
let guestRole: Role;
|
||||||
|
let moderatorRole: Role;
|
||||||
|
let adminRole: Role;
|
||||||
|
let glimmerAuthor: Author;
|
||||||
|
let bowAuthor: Author;
|
||||||
|
let adoraAuthor: Author;
|
||||||
|
let post1: Post;
|
||||||
|
let post2: Post;
|
||||||
|
let post3: Post;
|
||||||
|
|
||||||
|
describe('ModelRelation', () => {
|
||||||
|
test('Query and check relations', async () => {
|
||||||
|
const posts = await Post.select()
|
||||||
|
.with('author.roles.permissions')
|
||||||
|
.sortBy('id', 'ASC')
|
||||||
|
.get();
|
||||||
|
|
||||||
|
expect(posts.length).toBe(3);
|
||||||
|
|
||||||
|
async function testPost(post: Post, originalPost: Post, expectedAuthor: Author, expectedRoles: Role[], expectedPermissions: Permission[]) {
|
||||||
|
console.log('Testing post', post)
|
||||||
|
expect(post.id).toBe(originalPost.id);
|
||||||
|
expect(post.content).toBe(originalPost.content);
|
||||||
|
|
||||||
|
const actualAuthor = await post.author.get();
|
||||||
|
expect(actualAuthor).not.toBeNull()
|
||||||
|
expect(await post.author.has(expectedAuthor)).toBeTruthy();
|
||||||
|
expect(actualAuthor!.equals(expectedAuthor)).toBe(true);
|
||||||
|
|
||||||
|
const authorRoles = await actualAuthor!.roles.get();
|
||||||
|
console.log('Roles:');
|
||||||
|
expect(authorRoles.map(r => r.id)).toStrictEqual(expectedRoles.map(r => r.id));
|
||||||
|
|
||||||
|
const authorPermissions = (await Promise.all(authorRoles.map(async r => await r.permissions.get()))).flatMap(p => p);
|
||||||
|
console.log('Permissions:');
|
||||||
|
expect(authorPermissions.map(p => p.id)).toStrictEqual(expectedPermissions.map(p => p.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
await testPost(posts[0], post1, glimmerAuthor,
|
||||||
|
[guestRole],
|
||||||
|
[createPostPermission]);
|
||||||
|
await testPost(posts[1], post2, adoraAuthor,
|
||||||
|
[adminRole],
|
||||||
|
[createPostPermission, moderatePostPermission, viewLogsPermission]);
|
||||||
|
await testPost(posts[2], post3, bowAuthor,
|
||||||
|
[moderatorRole],
|
||||||
|
[createPostPermission, moderatePostPermission]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user