Załóżmy, że mam tabelę przedmiotów:
CREATE TABLE items
(
item serial PRIMARY KEY,
...
);
Teraz chcę wprowadzić pojęcie „uprawnień” dla każdego elementu (proszę zauważyć, że jestem nie mówię tu o uprawnieniach dostępu do bazy danych, ale o uprawnieniach logiki biznesowej dla tego elementu). Każdy element ma uprawnienia domyślne, a także uprawnienia na użytkownika, które mogą zastąpić uprawnienia domyślne.
Próbowałem wymyślić kilka sposobów na wdrożenie tego i wymyśliłem następujące rozwiązania, ale nie jestem pewien, który jest najlepszy i dlaczego:
1) Rozwiązanie logiczne
Użyj kolumny boolowskiej dla każdego pozwolenia:
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,
...
);
Zalety : Każde uprawnienie ma nazwę.
Niedogodności : Istnieją dziesiątki uprawnień, które znacznie zwiększają liczbę kolumn i trzeba je zdefiniować dwukrotnie (raz w każdej tabeli).
2) Rozwiązanie Integer
Użyj liczby całkowitej i traktuj ją jak pole bitowe (tj. Bit 0 oznacza can_change_description
, bit 1 oznacza can_change_price
itd. I użyj operacji bitowych, aby ustawić lub odczytać uprawnienia).
CREATE DOMAIN permissions AS integer;
Zalety : bardzo szybko.
Wady : Musisz śledzić, który bit oznacza, które uprawnienie zarówno w bazie danych, jak i interfejsie użytkownika.
3) Rozwiązanie Bitfield
Taki sam jak 2), ale użyj bit(n)
. Najprawdopodobniej te same zalety i wady, może nieco wolniejsze.
4) Rozwiązanie Enum
Użyj typu wyliczenia dla uprawnień:
CREATE TYPE permission AS ENUM ('can_change_description', 'can_change_price', .....);
a następnie utwórz dodatkową tabelę dla domyślnych uprawnień:
CREATE TABLE item_default_permissions
(
item int NOT NULL REFERENCES items(item),
perm permission NOT NULL,
PRIMARY KEY(item, perm)
);
i zmień tabelę definicji użytkownika na:
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)
);
Zalety : Łatwo nazwać poszczególne uprawnienia (nie musisz obsługiwać pozycji bitów).
Niedogodności : Nawet przy pobieraniu domyślnych uprawnień wymaga dostępu do dwóch dodatkowych tabel: po pierwsze, do domyślnej tabeli uprawnień, a po drugie, do katalogu systemowego przechowującego wartości wyliczeniowe.
Zwłaszcza, że należy przywrócić domyślne uprawnienia dla każdego pojedynczego wyświetlenia strony tego elementu , wpływ ostatniej alternatywy na wydajność może być znaczący.
5) Rozwiązanie Enum Array
Taki sam jak 4), ale użyj tablicy do przechowywania wszystkich (domyślnych) uprawnień:
CREATE TYPE permission AS ENUM ('can_change_description', 'can_change_price', .....);
CREATE TABLE items
(
item serial PRIMARY KEY,
granted_permissions permission ARRAY,
...
);
Zalety : Łatwo nazwać poszczególne uprawnienia (nie musisz obsługiwać pozycji bitów).
Wady : Łamie 1. normalną formę i jest trochę brzydka. Zajmuje znaczną liczbę bajtów z rzędu, jeśli liczba uprawnień jest duża (około 50).
Czy możesz wymyślić inne alternatywy?
Jakie podejście należy zastosować i dlaczego?
Uwaga: jest to zmodyfikowana wersja pytania opublikowanego wcześniej na Stackoverflow .
bigint
pól (każde dobre dla 64 bitów) lub ciąg znaków. Napisałem kilka powiązanych odpowiedzi na temat SO, które mogą być pomocne.