Supposons que j'ai un tableau d'articles:
CREATE TABLE items
(
item serial PRIMARY KEY,
...
);
Maintenant, je veux introduire le concept d '"autorisations" pour chaque élément (veuillez noter que je ne parle pas ici des autorisations d'accès à la base de données, mais des autorisations de logique métier pour cet élément). Chaque élément a des autorisations par défaut et également des autorisations par utilisateur qui peuvent remplacer les autorisations par défaut.
J'ai essayé de réfléchir à plusieurs façons de mettre en œuvre cela et j'ai trouvé les solutions suivantes, mais je ne sais pas laquelle est la meilleure et pourquoi:
1) La solution booléenne
Utilisez une colonne booléenne pour chaque autorisation:
CREATE TABLE items
(
item serial PRIMARY KEY,
can_change_description boolean NOT NULL,
can_change_price boolean NOT NULL,
can_delete_item_from_store boolean NOT NULL,
...
);
CREATE TABLE item_per_user_permissions
(
item int NOT NULL REFERENCES items(item),
user int NOT NULL REFERENCES users(user),
PRIMARY KEY(item, user),
can_change_description boolean NOT NULL,
can_change_price boolean NOT NULL,
can_delete_item_from_store boolean NOT NULL,
...
);
Les avantages : chaque autorisation est nommée.
Désavantages : il existe des dizaines d'autorisations, ce qui augmente considérablement le nombre de colonnes et vous devez les définir deux fois (une fois dans chaque tableau).
2) La solution entière
Utilisez un entier et traitez-le comme un champ de bits (c'est-à-dire que le bit 0 est pour can_change_description
, le bit 1 est pour can_change_price
, etc., et utilisez des opérations au niveau du bit pour définir ou lire les autorisations).
CREATE DOMAIN permissions AS integer;
Avantages : très rapide.
Inconvénients : vous devez garder une trace de quel bit représente quelle autorisation à la fois dans la base de données et dans l'interface frontale.
3) La solution Bitfield
Identique à 2), mais utilisez bit(n)
. Probablement les mêmes avantages et inconvénients, peut-être légèrement plus lents.
4) La solution Enum
Utilisez un type d'énumération pour les autorisations:
CREATE TYPE permission AS ENUM ('can_change_description', 'can_change_price', .....);
puis créez une table supplémentaire pour les autorisations par défaut:
CREATE TABLE item_default_permissions
(
item int NOT NULL REFERENCES items(item),
perm permission NOT NULL,
PRIMARY KEY(item, perm)
);
et changez la table de définition par utilisateur en:
CREATE TABLE item_per_user_permissions
(
item int NOT NULL REFERENCES items(item),
user int NOT NULL REFERENCES users(user),
perm permission NOT NULL,
PRIMARY KEY(item, user, perm)
);
Avantages : Facile à nommer les autorisations individuelles (vous n'avez pas à gérer les positions des bits).
Désavantages : même lors de la récupération des autorisations par défaut, il nécessite d'accéder à deux tables supplémentaires: premièrement, la table des autorisations par défaut et deuxièmement, le catalogue système stockant les valeurs d'énumération.
Surtout parce que les autorisations par défaut doivent être récupérées pour chaque vue de page unique de cet élément , l'impact sur les performances de la dernière alternative peut être significatif.
5) La solution d'Enum Array
Identique à 4), mais utilisez un tableau pour conserver toutes les autorisations (par défaut):
CREATE TYPE permission AS ENUM ('can_change_description', 'can_change_price', .....);
CREATE TABLE items
(
item serial PRIMARY KEY,
granted_permissions permission ARRAY,
...
);
Avantages : Facile à nommer les autorisations individuelles (vous n'avez pas à gérer les positions des bits).
Inconvénients : casse la 1ère forme normale et est un peu moche. Prend un nombre considérable d'octets d'affilée si le nombre d'autorisations est important (environ 50).
Pouvez-vous penser à d'autres alternatives?
Quelle approche adopter et pourquoi?
Remarque: il s'agit d'une version modifiée d'une question publiée précédemment sur Stackoverflow .
bigint
champs (chacun valable pour 64 bits) ou une chaîne de bits. J'ai écrit quelques réponses connexes sur SO qui pourraient être utiles.