Create foreign key that references another schema - postgresql

I have a multi tenant app which uses sequelize-typescript. Each time a new user is created, a new schema is created for them.
There's only one table in public schema - "Users".
Each tenant schema has "Roles" and "UserRoles" as a junction table.
I want UserRoles to reference Users in a public schema, not in a tenant schema. How can I achieve that?
user model
#Table({ paranoid: true })
export default class User extends Model {
#AutoIncrement
#PrimaryKey
#Column(DataType.BIGINT)
id: number;
#Column(DataType.STRING)
name: string;
#BelongsToMany(() => Role, () => UserRole)
roles: Role[];
role model
#Table({ paranoid: true })
export default class Role extends Model {
#AutoIncrement
#PrimaryKey
#Column(DataType.BIGINT)
id: number;
#Column(DataType.STRING)
name: string;
#BelongsToMany(() => User, () => UserRole)
users: User[];
}
user-role model
#Table({ paranoid: true, freezeTableName: true })
export default class UserRole extends Model {
#AutoIncrement
#PrimaryKey
#Column(DataType.BIGINT)
id: number;
#ForeignKey(() => Role)
#Column(DataType.BIGINT)
roleId: number;
#Unique
#ForeignKey(() => User)
userId: number;
}
I tried to specify schema inside column, but it still references tenant schema
#Table({ paranoid: true, freezeTableName: true })
export default class UserRole extends Model {
#AutoIncrement
#PrimaryKey
#Column(DataType.BIGINT)
id: number;
#ForeignKey(() => Role)
#Column(DataType.BIGINT)
roleId: number;
#Unique
#ForeignKey(() => User)
#Column({
type: DataType.BIGINT,
references: {
model: {
tableName: 'users',
schema: 'public',
},
key: 'id',
},
})
userId: number;
}

Related

How do I search in the postgresql using Typeorm and return the mutated value for relation?

I have a User entity with a Role relationship in an application Nestjs.
#Entity()
class User {
...
#ManyToOne(() => Role, {
eager: true,
})
role?: Role;
}
#Entity()
export class Role extends EntityHelper {
#PrimaryColumn()
id: number;
#Column()
name?: string;
}
when I want get users from the DB I do:
this.usersRepository.find({
relations: {
role: true,
},
})
and I get data like this:
{ id: 1, name: "John", role: { id: 2, name: "user" }}
but I don't want to get the role as an object, I just want the name from this
Example:
{ id: 1, name: "John", role: "user" }
So, my question is how can I get the relation and return only the value of { ... role: "user" }?
You can achieve it by using QueryBuilder:
this.usersRepository.createQueryBuilder('User')
.innerJoinAndSelect('User.role', 'Role')
.select(['Role.name as role', 'User.id as id'])
.getRawMany()

Nested populate not working for mikro-orm

I'm using mikro-orm with nest.js, I have Users, Roles and Permissions entities. I need to select user by id with it's role and permissions from database. I'm using the following code to select user with everything:
this._userRepo.findOne({ $or: [{ email }] }, { populate: ['role', 'role.permissions'] })
I need the result to look like the following code example, but permissions are not selected:
{
id: 1,
email: 'john.doe#inter.net',
firstName: 'john',
lastName: 'Doe',
...
role: {
id: 21,
name: 'Moderator',
permissions: [
{ id: 1, name: 'Create' },
{ id: 2, name: 'Update' },
{ id: 3, name: 'Delete' },
]
}
}
Here's how my entities and schema looks like:
// user.entity.ts
#Entity({ tableName: 'users' })
export class UserEntity {
#PrimaryKey() id: number;
#Property() email: string;
#Property() firstName: string;
#Property() lastName: string;
...
#ManyToOne(() => RoleEntity) role: ref<RoleEntity, 'id'>;
constructor(role: RoleEntity) {
this.role = ref(role);
}
}
// role.entity.ts
#Entity({ tableName: 'roles' })
export class RoleEntity {
#PrimaryKey() id: number;
#Property() name: string;
...
#ManyToMany(() => PermissionEntity) permissions = new Collection<PermissionEntity>(this);
}
// permission.entity.ts
#Entity({ tableName: 'permissions' })
export class PermissionEntity {
#PrimaryKey() id: number;
#Property() name: string;
}
And there's roles_permissions table generated in database:
|role_entity_id|permission_entity_id|
|--------------|--------------------|
| 1 | 1 |
How can I solve this issue?
After torturing for several hours, I found that I was missing some properties to be specified in #ManyToMany relation.
So, I changed my RoleEntity to:
#Entity({ tableName: 'roles' })
export class RoleEntity {
#PrimaryKey() id: number;
#Property() name: string;
...
#ManyToMany({
entity: () => PermissionEntity,
owner: true,
pivotTable: 'roles_permissions',
joinColumn: 'role_entity_id',
inverseJoinColumn: 'permission_entity_id',
hidden: true,
})
permissions = new Collection<PermissionEntity>(this);
}
And now I can select role with it's permissions from database.

How can I create a UUID FK column in NestJS?

I am running into an odd issue where I can't create a FK relationship between two entities.
// organization.entity.ts
#PrimaryGeneratedColumn('uuid')
id: string;
...
#OneToMany(() => User, (user) => user.organization)
users: User[];
// user.entity.ts
#PrimaryGeneratedColumn('uuid')
id: string;
#Column({
type: 'uuid',
})
organizationId: string;
...
#ManyToOne(() => Organization, (organization) => organization.users)
organization: Organization;
In my ormconfig.json file I have these settings (among connection creds)
...
"logging": true,
"entities": [
"dist/**/*.entity{.ts,.js}"
],
"synchronize": true
...
I am using "typeorm": "^0.2.45" in my package.json file.
Key columns "organizationId" and "id" are of incompatible types: character varying and uuid.
How can I create an FK relationship between users & organizations?
So from your question I understood is you want a "organizationId" field in your users table which will be a FK.
To create OnetoMany Relation between Organization and users do as below:
// organization.entity.ts
#Entity({ name: 'organizations' })
export class Organization {
#PrimaryGeneratedColumn('uuid')
id: string;
...
#OneToMany(() => User, (user) => user.organization)
users: User[];
}
// user.entity.ts
#Entity({ name: 'users' })
export class User {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column({ type: 'uuid' })
organizationId: string;
...
#ManyToOne(() => Organization, (organization) => organization.users)
#JoinColumn({ name: 'organizationId' })
organization: Organization;
}

How to select data by using typeorm from 3 tables which depend on each other?

I have 3 entity which depend on each other and I have a problem with querying data from them by using one request.
First one User:
#Entity()
export class User {
#PrimaryGeneratedColumn()
id: number;
#Column()
firstName: string;
#Column()
lastName: string;
#Column()
login: string;
#Column()
password: string;
#Column()
ownerId: number;
#OneToOne(() => Role, (role) => role.user)
#JoinColumn()
role?: Role;
}
Second one Role:
#Entity()
export class Role extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#Column()
description: string;
#ManyToOne(() => User, (user) => user.role)
#JoinColumn()
user: User | null;
#ManyToMany(() => Permission, { cascade: true })
#JoinTable({ name: 'roles_has_permissions' })
permissions: Permission[];
}
Third one Permission:
#Entity()
export class Permission {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: PossiblePermissions;
}
How to select data from database. I’m using typeorm with Postgresql and I want to get array like this.
[{
…user info by ownerId
role: {
…role which related this user
permissions: [{
…permissions which related this role
}, …]
}
}, …]
Use query builder https://typeorm.io/#/select-query-builder
In your case it should be something like this:
await connection
.getRepository(User)
.createQueryBuilder("user")
.leftJoinAndSelect("user.role", "role")
.leftJoinAndSelect("role.permissions", "permissions")
.getMany()

Typeorm update record in OneToMany relation

I have the following two entities with a OneToMany/ManyToOne relation between them:
#Entity({ name: 'user' })
export class User {
#PrimaryGeneratedColumn('increment')
id: number;
#Column({ type: 'varchar' })
firstName: string;
#Column({ type: 'varchar' })
lastName: string;
#ManyToOne(() => Group, group => group.id)
#JoinColumn({ name: 'groupId' })
group: Group;
#Column({ type: 'integer' })
groupId: number;
}
#Entity({ name: 'group' })
export class Group {
#PrimaryGeneratedColumn('increment')
id: number;
#Column({ type: 'varchar' })
name: string;
#OneToMany(() => User, user => user.group)
members: User[];
}
When I create a new group in my Group repository, I can add existing members as follows:
const group = new Group();
group.name = 'Test';
group.members = [{ id: 1 }, { id: 2 }]; // user ids
this.save(group);
I am wondering if I can update existing members in a similar way. For example if a group with id 1 has two members:
{ id: 1, firstName: 'Member', lastName: 'One', groupId: 1 }
{ id: 2, firstName: 'Member', lastName: 'Two', groupId: 1 }
Is it possible to update a member through the OneToMany relation in a similar way as I'm adding them ? Something like (making this up):
const group = await repository.findOne(groupId, { relations: ['members'] });
group.members = [{ id: 1, firstName: 'Updated' }]; // this would update the firstName of member with id 1 if it exists in the relation
repository.save(group);
Thanks!
There is no built in functionality in typeorm to update specific related entity from the base entity. However if you want to do this then you can add a general function which updates the base table as well as it's relations.