Hej mam pytanko odnośnie pól w sealiousie. Piszę teraz jeden projekt z użyciem sealiousa na backendzie i potrzebuje przetrzymać liste stringów w kolekcji, ale nie mogę na to znaleźć pola. Najbliższe co znalazłem to pole typu JsonObject
, ale nie wydaje się to ładnym rozwiązaniem. Czy mogę jakimś instejącym polem to osiągnąć?
Kanonicznym rozwiązaniem takiego problemu w Sealiousie jest utworzenie osobnej kolekcji i podpięcie jej w polu do istniejącej kolekcji. Tak na przykład są zaimplementowane role użytkownika. Jeden użytkownik może mieć wiele ról:
// user-roles.ts
export class UserRoles extends Collection {
name = "user-roles";
fields = {
role: new FieldTypes.Enum((app: App) =>
app.ConfigManager.get("roles")
).setRequired(true),
user: new FieldTypes.SingleReference("users"),
};
}
// users.ts
export class Users extends Collections.users {
fields = {
...App.BaseCollections.users.fields,
email: new FieldTypes.Email().setRequired(true),
roles: new FieldTypes.ReverseSingleReference({
referencing_collection: "user-roles",
referencing_field: "user",
}),
};
}
Kluczowe jest tutaj użycie w klasie users
pola typu ReverseSingleReference
. Dla każdego usera wartością tego pola będzie lista id-ków elementów z kolekcji user-roles
, które w polu user
mają id tego właśnie użytkownika.
To pole jest read-only - aby dodać/usunąć rolę, wywołujemy odpowiednią metodą w kolekcji user-roles
.
Aby potem w kodzie pozyskać listę wszystkich ról przypisanych do użytkownika, można dodać .attach
do zapytania:
const { items: users } = ctx.$app.collections.users
.list()
.attach({ roles: true });
const user = users[0];
const roles = user.getAttachments("roles"); // zwraca Array<CollectionItem<UserRoles>>
Odpowiednik w restowym api:
GET localhost:8080/api/v1/collections/users?attachments[roles]=true
Dodanie ?attachments[roles]=true
sprawia, że do JSON-a z odpowiedzią jest dołączone pole attachments
. To pole jest obiektem, w którym klucze to id-ki, które są wymienione w parametrze attachements
, a wartości w tym obiekcie to body itemu o tym id. Przykładowa odpowiedź:
{
"items": [
{
"id": "9ssrGmhkrD",
"baseline_id": "id",
"email": "admin@example.com",
"username": "admin",
"requires_password_change": false,
"password": "secret",
"roles": ["6LBj1CZ8ZZ"]
}
],
"attachments": {
"6LBj1CZ8ZZ": { "id": "6LBj1CZ8ZZ", "user": "9ssrGmhkrD", "role": "admin" }
},
"fields_with_attachments": ["roles"]
}
PS. Pole typu ‘lista’ od zawsze było w TODO sealiousowym, ale za każdym razem ten trik z ReverseSingleReference w zupełności wystarczał, więc nie implementowaliśmy tego
Przydałaby się jakieś pole dla listy z podstawowymi typami. Tak jak pisałem potrzebuje listy stringów więc troche słabo by było tworzyć kolekcje z jednym polem i robić powiązania dla czegoś takiego. Czy trudne by było dla mnie napisać takie pole?
Inna opcja o jakiej myślałem to użyć new FieldTypes.JsonObject()
, ale nie jest to bezpieczne pod względem typów. Myślałem, że być może możnaby dodać sprawdzanie typu do tego pola poprzez np taką składnie
new FieldTypes.JsonObject<JsonSchema>()
Myślisz, że coś z tego ma sens?
W takim scenariuszu możesz zrobić klasę dziedziczącą z FieldTypes.JsonObject
i nadpisującą metodę isProperValue
wedle własnego uznania.
Można byłoby nawet w Sealiousie umieścić taki nowy typ pola oparty o JsonObject. Mógłby wykorzystywać ts-predicates do opisu kształtu tego JSON-a, pozwalając na:
- większe bezpieczeństwo typów
- implementację list
Diffs welcome