Pole typu lista w sealiousie

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 :smiley: