I try to build an RBAC authorization system into an application. Users, roles and permissions are stored in a database. Each role can be assigned to each user. That's why I have a user_account
and a role
table glued together into a many-to-many relationship by the user_role
junction table. Trimmed down, the database setup looks like this:
CREATE TABLE user_account (
id uuid NOT NULL DEFAULT uuid_generate_v1mc(),
email character varying(128) NOT NULL,
CONSTRAINT user_account_pkey PRIMARY KEY (id),
CONSTRAINT user_account_email_key UNIQUE (email)
);
CREATE TABLE role (
id uuid NOT NULL DEFAULT uuid_generate_v1mc(),
name character varying(128) NOT NULL,
CONSTRAINT role_pkey PRIMARY KEY (id),
CONSTRAINT role_name_key UNIQUE (name)
);
CREATE TABLE user_role (
user_id uuid NOT NULL,
role_id uuid NOT NULL,
CONSTRAINT user_role_pkey PRIMARY KEY (user_id, role_id),
CONSTRAINT user_role_fkey_user FOREIGN KEY (user_id) REFERENCES user_account (id) ON DELETE CASCADE,
CONSTRAINT user_role_fkey_role FOREIGN KEY (role_id) REFERENCES role (id) ON DELETE CASCADE
);
Obviously I have set up matching go structs:
type User struct {
ID string `db:"id"`
Email string `db:"email"`
}
type Role struct {
ID string `db:"id"`
Name string `db:"name"`
}
So far so good. Fetching one or more rows individually into the matching go struct is not an issue. But I would prefer to fetch a user and all its assigned roles. The resulting go struct would look something like this:
type User struct {
ID string `db:"id"`
Email string `db:"email"`
Roles []Role
}
What I'm asking is: What is the best strategy to fetch the data into the struct?
- Fetch the user record with a query, fetch all its assigned roles with another query and build the
User
struct.
or
- Fetch the user record and all its assigned roles with a single query.
I know how to do the first case but struggle with the second one. I'm using sqlx
and PostgreSQL. Is it even possible what I try to achieve? If yes, how? Which db
tag to use?
My naive query for approach two looks like this, but obviously doesn't work as intended:
SELECT user_account.id, user_account.email, role.id, role.name
FROM user_account
LEFT OUTER JOIN user_role
ON user_account.id = user_role.user_id
LEFT OUTER JOIN role
ON user_role.role_id = role.id
Any suggestions?