@cubicweb/client 2.1.0 → 3.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +28 -16
  2. package/lib/api/Api.d.ts +34 -14
  3. package/lib/api/Api.d.ts.map +1 -1
  4. package/lib/api/Api.js +83 -40
  5. package/lib/api/Api.js.map +1 -1
  6. package/lib/api/Client.d.ts +17 -6
  7. package/lib/api/Client.d.ts.map +1 -1
  8. package/lib/api/Client.js +30 -11
  9. package/lib/api/Client.js.map +1 -1
  10. package/lib/api/Transaction.d.ts +33 -20
  11. package/lib/api/Transaction.d.ts.map +1 -1
  12. package/lib/api/Transaction.js +44 -37
  13. package/lib/api/Transaction.js.map +1 -1
  14. package/lib/schema/classes/EntitySchema.d.ts +16 -22
  15. package/lib/schema/classes/EntitySchema.d.ts.map +1 -1
  16. package/lib/schema/classes/EntitySchema.js +17 -25
  17. package/lib/schema/classes/EntitySchema.js.map +1 -1
  18. package/lib/schema/classes/RelationDefinitionSchema.d.ts +8 -10
  19. package/lib/schema/classes/RelationDefinitionSchema.d.ts.map +1 -1
  20. package/lib/schema/classes/RelationDefinitionSchema.js +7 -21
  21. package/lib/schema/classes/RelationDefinitionSchema.js.map +1 -1
  22. package/lib/schema/classes/Schema.d.ts +2 -0
  23. package/lib/schema/classes/Schema.d.ts.map +1 -1
  24. package/lib/schema/classes/Schema.js +2 -0
  25. package/lib/schema/classes/Schema.js.map +1 -1
  26. package/lib/schema/classes/Utils.d.ts +135 -1
  27. package/lib/schema/classes/Utils.d.ts.map +1 -1
  28. package/lib/schema/classes/Utils.js +165 -3
  29. package/lib/schema/classes/Utils.js.map +1 -1
  30. package/lib/schema/raw/Constraints.d.ts +17 -9
  31. package/lib/schema/raw/Constraints.d.ts.map +1 -1
  32. package/lib/schema/raw/Entities.d.ts +4 -0
  33. package/lib/schema/raw/Entities.d.ts.map +1 -1
  34. package/lib/schema/raw/RelationDefinitions.d.ts +15 -2
  35. package/lib/schema/raw/RelationDefinitions.d.ts.map +1 -1
  36. package/lib/schema/raw/Schema.d.ts +2 -0
  37. package/lib/schema/raw/Schema.d.ts.map +1 -1
  38. package/lib/schema/raw/Utils.d.ts +6 -0
  39. package/lib/schema/raw/Utils.d.ts.map +1 -1
  40. package/package.json +4 -8
  41. package/src/api/Api.ts +102 -45
  42. package/src/api/Client.ts +33 -20
  43. package/src/api/Transaction.ts +56 -37
  44. package/src/schema/classes/EntitySchema.ts +35 -41
  45. package/src/schema/classes/RelationDefinitionSchema.ts +10 -25
  46. package/src/schema/classes/Schema.ts +2 -0
  47. package/src/schema/classes/Utils.ts +178 -1
  48. package/src/schema/raw/Constraints.ts +20 -8
  49. package/src/schema/raw/Entities.ts +4 -0
  50. package/src/schema/raw/RelationDefinitions.ts +15 -2
  51. package/src/schema/raw/Schema.ts +2 -0
  52. package/src/schema/raw/Utils.ts +6 -0
package/src/api/Api.ts CHANGED
@@ -3,34 +3,46 @@ import { RawSchema } from "../schema/raw/Schema";
3
3
  import {
4
4
  TransactionResult,
5
5
  Transaction,
6
- isTransactionQueryRef,
6
+ TransactionQueryScalarRef,
7
+ TransactionQueryBinaryRef,
7
8
  } from "./Transaction";
8
9
 
9
10
  /**
10
11
  * Type representing an RQL request and its associated parameters.
12
+ *
13
+ * @category Api
11
14
  */
12
15
  export type RQLQuery = [string, RQLParams];
13
16
 
14
17
  export type RQLParamValue = string | number | boolean | null;
15
18
  /**
16
19
  * Type representing RQL parameters to send along a request.
20
+ *
21
+ * @category Api
17
22
  */
18
- export interface RQLParams {
19
- [key: string]: RQLParamValue;
20
- }
23
+ export type RQLParams = Record<
24
+ string,
25
+ RQLParamValue | TransactionQueryScalarRef | TransactionQueryBinaryRef
26
+ >;
21
27
 
22
28
  /**
23
29
  * Type representing a row returned in a result set.
30
+ *
31
+ * @category Api
24
32
  */
25
33
  export type RqlRow = Array<string | number | boolean | null>;
26
34
 
27
35
  /**
28
36
  * Type representing a RQL request result.
37
+ *
38
+ * @category Api
29
39
  */
30
40
  export type ResultSet = Array<RqlRow>;
31
41
 
32
42
  /**
33
43
  * Type representing the currently logged user's data
44
+ *
45
+ * @category Api
34
46
  */
35
47
  export interface CurrentUser {
36
48
  login: string;
@@ -40,6 +52,8 @@ export interface CurrentUser {
40
52
 
41
53
  /**
42
54
  * Type representing the body of an error sent by CubicWeb's API.
55
+ *
56
+ * @category Api
43
57
  */
44
58
  type ApiError = {
45
59
  title: string;
@@ -49,6 +63,8 @@ type ApiError = {
49
63
 
50
64
  /**
51
65
  * Type representing the error data sent to clients when retrieving an API error.
66
+ *
67
+ * @category Api
52
68
  */
53
69
  export type ApiErrorResponse = {
54
70
  status: number;
@@ -68,8 +84,9 @@ export default class Api {
68
84
  private _rqlApiUrl: string;
69
85
  private _schemaApiUrl: string;
70
86
  private _loginApiUrl: string;
87
+ private _logoutApiUrl: string;
71
88
  private _currentUserApiUrl: string;
72
- private _transactionApiUrl: string;
89
+ private _binaryApiUrl: string;
73
90
 
74
91
  /**
75
92
  * Class used to handle requests to the CubicWeb API.
@@ -86,8 +103,9 @@ export default class Api {
86
103
  this._rqlApiUrl = this.getApiRoute("rql");
87
104
  this._schemaApiUrl = this.getApiRoute("schema");
88
105
  this._loginApiUrl = this.getApiRoute("login");
106
+ this._logoutApiUrl = this.getApiRoute("logout");
89
107
  this._currentUserApiUrl = this.getApiRoute("current-user");
90
- this._transactionApiUrl = this.getApiRoute("transaction");
108
+ this._binaryApiUrl = this.getApiRoute("binary");
91
109
  }
92
110
 
93
111
  get apiUrl() {
@@ -98,25 +116,6 @@ export default class Api {
98
116
  return `${this._apiUrl}/${this._version}/${route}`;
99
117
  }
100
118
 
101
- /**
102
- * Executes the given query and waits for the response.
103
- *
104
- * @param query The RQL query to send
105
- * @param params The additional parameters for the request
106
- * @returns A promise with the request's result set
107
- */
108
- async execute(query: string, params: RQLParams): Promise<ResultSet> {
109
- try {
110
- return await nonNullFetchApi<ResultSet>(this._rqlApiUrl, {
111
- method: "POST",
112
- body: JSON.stringify({ query, params }),
113
- credentials: "include", // FIXME is it secure?
114
- });
115
- } catch (e) {
116
- this.handleUserErrors(e);
117
- }
118
- }
119
-
120
119
  /**
121
120
  * Retrieves the CubicWeb instance's JSON schema.
122
121
  *
@@ -152,6 +151,18 @@ export default class Api {
152
151
  }
153
152
  }
154
153
 
154
+ /**
155
+ * Logs out the current user. Will invalidate any authentication cookie active.
156
+ *
157
+ * @returns A promise which will resolve when the user is properly logged out
158
+ */
159
+ async logout(): Promise<void> {
160
+ await fetchApi<null>(this._logoutApiUrl, {
161
+ method: "POST",
162
+ credentials: "include",
163
+ });
164
+ }
165
+
155
166
  /**
156
167
  * Get the current user associated to this client
157
168
  *
@@ -164,30 +175,67 @@ export default class Api {
164
175
  });
165
176
  }
166
177
 
167
- async executeTransaction(
168
- transaction: Transaction
169
- ): Promise<TransactionResult> {
170
- const data = transaction.queries.map((transactionQuery) => ({
178
+ /**
179
+ * Get the binary for the given entity attribute
180
+ *
181
+ * @returns A promise resolving to the binary
182
+ */
183
+ async binary(eid: number, attribute: string): Promise<Blob> {
184
+ const params = new URLSearchParams({
185
+ eid: eid.toString(),
186
+ attribute,
187
+ });
188
+ return await nonNullFetchApi<Blob>(this._binaryApiUrl + params, {
189
+ method: "GET",
190
+ credentials: "include",
191
+ });
192
+ }
193
+
194
+ async rql(transaction: Transaction): Promise<TransactionResult> {
195
+ try {
196
+ if (Object.keys(transaction.binaries).length > 0) {
197
+ return await this.multipartTransaction(transaction);
198
+ } else {
199
+ return await this.jsonTransaction(transaction);
200
+ }
201
+ } catch (e) {
202
+ this.handleUserErrors(e);
203
+ }
204
+ }
205
+
206
+ private getTransactionParams(transaction: Transaction) {
207
+ return transaction.queries.map((transactionQuery) => ({
171
208
  query: transactionQuery.query,
172
- params: Object.fromEntries(
173
- Object.entries(transactionQuery.params).map(([key, value]) => [
174
- key,
175
- isTransactionQueryRef(value)
176
- ? {
177
- queryIndex: value.queryIndex,
178
- row: value.row,
179
- column: value.column,
180
- }
181
- : value,
182
- ])
183
- ),
209
+ params: transactionQuery.params,
184
210
  }));
211
+ }
212
+
213
+ private async multipartTransaction(transaction: Transaction) {
214
+ const jsonParams = this.getTransactionParams(transaction);
215
+ const formData = new FormData();
216
+ formData.append("queries", JSON.stringify(jsonParams));
217
+ Object.entries(transaction.binaries).forEach(([key, value]) => {
218
+ formData.append(key, value);
219
+ });
220
+
221
+ const resultSets = await nonNullFetchApi<ReadonlyArray<ResultSet>>(
222
+ this._rqlApiUrl,
223
+ {
224
+ method: "POST",
225
+ credentials: "include",
226
+ body: formData,
227
+ }
228
+ );
229
+ return new TransactionResult(resultSets);
230
+ }
231
+
232
+ private async jsonTransaction(transaction: Transaction) {
185
233
  const resultSets = await nonNullFetchApi<ReadonlyArray<ResultSet>>(
186
- this._transactionApiUrl,
234
+ this._rqlApiUrl,
187
235
  {
188
236
  method: "POST",
189
237
  credentials: "include",
190
- body: JSON.stringify(data),
238
+ body: JSON.stringify(this.getTransactionParams(transaction)),
191
239
  }
192
240
  );
193
241
  return new TransactionResult(resultSets);
@@ -250,9 +298,18 @@ async function fetchApi<R = unknown>(
250
298
  init?: RequestInit
251
299
  ): Promise<R | null> {
252
300
  let headers = init?.headers;
253
- if (init?.method && init.method !== "GET" && init.method !== "DELETE") {
301
+ if (init?.method && init.method !== "GET") {
302
+ headers = {
303
+ // CSRF custom header necessary for POST requests
304
+ "X-Client-Name": "XMLHttpRequest",
305
+ };
306
+ // Browsers will automatically set the multipart content type
307
+ // with the right boundary if the body is FormData
308
+ if (!(init.body instanceof FormData)) {
309
+ headers["Content-Type"] = "application/json;charset=UTF-8";
310
+ }
254
311
  headers = {
255
- "Content-Type": "application/json;charset=UTF-8",
312
+ ...headers,
256
313
  ...init?.headers,
257
314
  };
258
315
  }
package/src/api/Client.ts CHANGED
@@ -1,18 +1,14 @@
1
1
  import { Schema } from "../schema/classes/Schema";
2
2
  import Api, { RQLParams, ResultSet, CurrentUser } from "./Api";
3
- import {
4
- NativeTransactionBackend,
5
- Transaction,
6
- TransactionBackend,
7
- TransactionResult,
8
- } from "./Transaction";
3
+ import { BinariesParam, Transaction, TransactionResult } from "./Transaction";
9
4
 
10
5
  /**
11
6
  * Class used to communicate with a CubicWeb instance's API.
7
+ *
8
+ * @category Api
12
9
  */
13
10
  export default class Client {
14
11
  private api: Api;
15
- private transactionBackend: TransactionBackend;
16
12
 
17
13
  /**
18
14
  * Class used to communicate with a CubicWeb instance's API.
@@ -21,17 +17,8 @@ export default class Client {
21
17
  * Example: if you can retrieve the schema with https://example.com/api/v1/schema,
22
18
  * use https://example.com/api as `apiUrl`.
23
19
  */
24
- constructor(
25
- apiUrl: string,
26
- options: { transactionBackend?: TransactionBackend } = {}
27
- ) {
20
+ constructor(apiUrl: string) {
28
21
  this.api = new Api(apiUrl);
29
- const { transactionBackend } = options;
30
- if (transactionBackend === undefined) {
31
- this.transactionBackend = new NativeTransactionBackend(this.api);
32
- } else {
33
- this.transactionBackend = transactionBackend;
34
- }
35
22
  }
36
23
 
37
24
  get apiUrl() {
@@ -45,8 +32,16 @@ export default class Client {
45
32
  * @param params The additional parameters for the request
46
33
  * @returns A promise with the request's result set
47
34
  */
48
- async execute(query: string, params: RQLParams = {}): Promise<ResultSet> {
49
- return await this.api.execute(query, params);
35
+ async execute(
36
+ query: string,
37
+ params: RQLParams = {},
38
+ binaries?: BinariesParam
39
+ ): Promise<ResultSet> {
40
+ const transaction = new Transaction();
41
+ const transactionQuery = transaction.push(query, params);
42
+ transaction.setBinaries(binaries);
43
+ const result = await this.executeTransaction(transaction);
44
+ return result.resolveQuery(transactionQuery.ref());
50
45
  }
51
46
 
52
47
  /**
@@ -70,6 +65,15 @@ export default class Client {
70
65
  return await this.api.login(login, password);
71
66
  }
72
67
 
68
+ /**
69
+ * Logs out the current user. Will invalidate any authentication cookie active.
70
+ *
71
+ * @returns A promise which will resolve when the user is properly logged out
72
+ */
73
+ async logout() {
74
+ return await this.api.logout();
75
+ }
76
+
73
77
  /**
74
78
  * Get the user associated to this client
75
79
  *
@@ -86,6 +90,15 @@ export default class Client {
86
90
  async executeTransaction(
87
91
  transaction: Transaction
88
92
  ): Promise<TransactionResult> {
89
- return await this.transactionBackend.execute(transaction);
93
+ return await this.api.rql(transaction);
94
+ }
95
+
96
+ /**
97
+ * Get the binary for the given entity attribute
98
+ *
99
+ * @returns A promise resolving to the binary
100
+ */
101
+ async getBinary(eid: number, attribute: string) {
102
+ return await this.api.binary(eid, attribute);
90
103
  }
91
104
  }
@@ -1,12 +1,12 @@
1
- import Api, { ResultSet, RQLParamValue } from "./Api";
1
+ import { RQLParams, ResultSet } from "./Api";
2
+
3
+ export type BinariesParam = Record<string, Blob>;
2
4
 
3
5
  export class Transaction {
4
6
  private _queries: Array<TransactionQuery> = [];
7
+ private _binaries: BinariesParam = {};
5
8
 
6
- push(
7
- query: string,
8
- params: Record<string, RQLParamValue | TransactionQueryRef>
9
- ): TransactionQuery {
9
+ push(query: string, params: RQLParams): TransactionQuery {
10
10
  const stackedQuery = new TransactionQuery(
11
11
  query,
12
12
  params,
@@ -16,60 +16,79 @@ export class Transaction {
16
16
  return stackedQuery;
17
17
  }
18
18
 
19
+ setBinaries(binaries?: BinariesParam) {
20
+ this._binaries = binaries ?? {};
21
+ }
22
+
23
+ get binaries(): BinariesParam {
24
+ return this._binaries;
25
+ }
26
+
19
27
  get queries(): ReadonlyArray<TransactionQuery> {
20
28
  return this._queries;
21
29
  }
22
30
  }
23
31
 
32
+ export class TransactionQuery {
33
+ constructor(
34
+ public readonly query: string,
35
+ public readonly params: RQLParams,
36
+ public readonly index: number
37
+ ) {}
38
+
39
+ ref(): TransactionQueryRef {
40
+ return new TransactionQueryRef(this.index);
41
+ }
42
+ }
43
+
24
44
  export class TransactionResult {
25
45
  constructor(private resultSets: ReadonlyArray<ResultSet>) {}
26
46
 
27
- resolve(ref: TransactionQueryRef) {
47
+ resolveQuery(ref: TransactionQueryRef) {
48
+ return this.resultSets[ref.queryIndex];
49
+ }
50
+
51
+ resolveRow(ref: TransactionQueryRowRef) {
52
+ return this.resultSets[ref.queryIndex][ref.row];
53
+ }
54
+
55
+ resolveScalar(ref: TransactionQueryScalarRef) {
28
56
  return this.resultSets[ref.queryIndex][ref.row][ref.column];
29
57
  }
30
58
  }
31
59
 
32
- export interface TransactionQueryRef {
33
- queryIndex: number;
34
- row: number;
35
- column: number;
60
+ export class TransactionQueryRef {
61
+ constructor(public readonly queryIndex: number) {}
62
+
63
+ row(r: number): TransactionQueryRowRef {
64
+ return new TransactionQueryRowRef(this.queryIndex, r);
65
+ }
36
66
  }
37
67
 
38
- export class TransactionQuery {
68
+ export class TransactionQueryRowRef {
39
69
  constructor(
40
- public readonly query: string,
41
- public readonly params: Record<string, RQLParamValue | TransactionQueryRef>,
42
- public readonly index: number
70
+ public readonly queryIndex: number,
71
+ public readonly row: number
43
72
  ) {}
44
73
 
45
- ref(row = 0, column = 0): TransactionQueryRef {
74
+ column(c: number): TransactionQueryScalarRef {
46
75
  return {
47
- queryIndex: this.index,
48
- row,
49
- column,
76
+ type: "query_reference",
77
+ queryIndex: this.queryIndex,
78
+ row: this.row,
79
+ column: c,
50
80
  };
51
81
  }
52
82
  }
53
83
 
54
- export function isTransactionQueryRef(
55
- value: RQLParamValue | TransactionQueryRef
56
- ): value is TransactionQueryRef {
57
- return (
58
- typeof value === "object" &&
59
- value !== null &&
60
- ["queryIndex", "row", "column"].every((key) =>
61
- Object.keys(value).includes(key)
62
- )
63
- );
84
+ export interface TransactionQueryScalarRef {
85
+ readonly queryIndex: number;
86
+ readonly row: number;
87
+ readonly column: number;
88
+ readonly type: "query_reference";
64
89
  }
65
90
 
66
- export interface TransactionBackend {
67
- execute(transaction: Transaction): Promise<TransactionResult>;
68
- }
69
-
70
- export class NativeTransactionBackend implements TransactionBackend {
71
- constructor(private _api: Api) {}
72
- async execute(transaction: Transaction): Promise<TransactionResult> {
73
- return this._api.executeTransaction(transaction);
74
- }
91
+ export interface TransactionQueryBinaryRef {
92
+ readonly ref: string;
93
+ readonly type: "binary_reference";
75
94
  }
@@ -8,6 +8,8 @@ import { MatchedRelationDefinition, RelationDefinitionMatcher } from "./Utils";
8
8
  * Wrapper around raw entity schemas from the Schema.
9
9
  * You should never have to create this object yourself.
10
10
  * Instead, retrieve these objects from the methods in the `Schema` class.
11
+ *
12
+ * @category Schema
11
13
  */
12
14
  export class EntitySchema<
13
15
  E extends EntityRawSchemaArray = EntityRawSchemaArray,
@@ -49,43 +51,54 @@ export class EntitySchema<
49
51
  }
50
52
 
51
53
  /**
52
- * Gets the list of relation definitions schemas with this entity as subject.
53
- * In case a relation definition schema has this entity as both object and subject,
54
- * there will be dupicates when used along with `objectRelationsDefinitions`.
54
+ * Gets the list of attribute schemas (relation definition schemas with final at false)
55
+ * for this entity schema.
55
56
  */
56
- get subjectRelationDefinitions(): RelationDefinitionSchema<
57
+ get attributes(): RelationDefinitionSchema<
57
58
  E,
58
59
  R,
59
60
  MatchedRelationDefinition<
60
61
  E,
61
62
  R,
62
- { subject: ERawSchema["type"]; final: false }
63
+ { subject: ERawSchema["type"]; final: true }
63
64
  >
64
65
  >[] {
65
66
  return this.schema.matchRelationDefinitions({
67
+ final: true,
66
68
  subject: this.type,
67
- final: false,
68
69
  });
69
70
  }
70
71
 
71
- /**
72
- * Gets the list of relation definitions schemas with this entity as object.
73
- * In case a relation definition schema has this entity as both object and subject,
74
- * there will be dupicates when used along with `subjectRelationDefinitions`.
75
- */
76
- get objectRelationsDefinitions(): RelationDefinitionSchema<
77
- E,
78
- R,
79
- MatchedRelationDefinition<
72
+ get relationDefinitions(): {
73
+ subject: RelationDefinitionSchema<
80
74
  E,
81
75
  R,
82
- { object: ERawSchema["type"]; final: false }
83
- >
84
- >[] {
85
- return this.schema.matchRelationDefinitions({
86
- object: this.type,
87
- final: false,
88
- });
76
+ MatchedRelationDefinition<
77
+ E,
78
+ R,
79
+ { subject: ERawSchema["type"]; final: false }
80
+ >
81
+ >[];
82
+ object: RelationDefinitionSchema<
83
+ E,
84
+ R,
85
+ MatchedRelationDefinition<
86
+ E,
87
+ R,
88
+ { object: ERawSchema["type"]; final: false }
89
+ >
90
+ >[];
91
+ } {
92
+ return {
93
+ subject: this.schema.matchRelationDefinitions({
94
+ subject: this.type,
95
+ final: false,
96
+ }),
97
+ object: this.schema.matchRelationDefinitions({
98
+ object: this.type,
99
+ final: false,
100
+ }),
101
+ };
89
102
  }
90
103
 
91
104
  /**
@@ -103,23 +116,4 @@ export class EntitySchema<
103
116
  >[] {
104
117
  return this.schema.matchRelationDefinitions(matcher);
105
118
  }
106
-
107
- /**
108
- * Gets the list of attribute schemas (relation definition schemas with final at false)
109
- * for this entity schema.
110
- */
111
- get attributes(): RelationDefinitionSchema<
112
- E,
113
- R,
114
- MatchedRelationDefinition<
115
- E,
116
- R,
117
- { subject: ERawSchema["type"]; final: true }
118
- >
119
- >[] {
120
- return this.schema.matchRelationDefinitions({
121
- final: true,
122
- subject: this.type,
123
- });
124
- }
125
119
  }
@@ -7,12 +7,14 @@ import {
7
7
  import { IsLooseSchema, EntityRawSchemaByType } from "../raw/Utils";
8
8
  import { EntitySchema } from "./EntitySchema";
9
9
  import { Schema } from "./Schema";
10
- import { cardinalityRequired } from "./Utils";
10
+ import { EntityRole, isCardinalityRequired } from "./Utils";
11
11
 
12
12
  /**
13
13
  * Wrapper around raw relation definition schemas from the Schema.
14
14
  * You should never have to create this object yourself.
15
15
  * Instead, retrieve these objects from the methods in the `Schema` class.
16
+ *
17
+ * @category Schema
16
18
  */
17
19
  export class RelationDefinitionSchema<
18
20
  E extends EntityRawSchemaArray = EntityRawSchemaArray,
@@ -84,22 +86,11 @@ export class RelationDefinitionSchema<
84
86
  /**
85
87
  * The cardinality of this relation definition schema.
86
88
  */
87
- get cardinality(): RDef["cardinality"] {
88
- return this.relDef.cardinality;
89
- }
90
-
91
- /**
92
- * The cardinality of this relation definition schema's subject.
93
- */
94
- get subjectCardinality(): Cardinality {
95
- return this.relDef.cardinality[0] as Cardinality;
96
- }
97
-
98
- /**
99
- * The cardinality of this relation definition schema's object.
100
- */
101
- get objectCardinality(): Cardinality {
102
- return this.relDef.cardinality[1] as Cardinality;
89
+ get cardinality(): { subject: Cardinality; object: Cardinality } {
90
+ return {
91
+ subject: this.relDef.cardinality[0] as Cardinality,
92
+ object: this.relDef.cardinality[1] as Cardinality,
93
+ };
103
94
  }
104
95
 
105
96
  /**
@@ -144,13 +135,7 @@ export class RelationDefinitionSchema<
144
135
  * @param role The point of view to use
145
136
  * @returns
146
137
  */
147
- isRequired(role: "subject" | "object") {
148
- let cardinality: Cardinality;
149
- if (role === "subject") {
150
- cardinality = this.subjectCardinality;
151
- } else {
152
- cardinality = this.objectCardinality;
153
- }
154
- return cardinalityRequired(cardinality);
138
+ isRequired(role: EntityRole) {
139
+ return isCardinalityRequired(this.cardinality[role]);
155
140
  }
156
141
  }
@@ -19,6 +19,8 @@ const rawSchemaKey: unique symbol = Symbol("Indexer of the rawSchema");
19
19
  * Wrapper around the raw JSON Schema.
20
20
  * It is recommended to use this class instead of the raw JSON Schema
21
21
  * as it is more robust to schema changes and provides utility functions.
22
+ *
23
+ * @category Schema
22
24
  */
23
25
  export class Schema<
24
26
  E extends EntityRawSchemaArray = EntityRawSchemaArray,