@cubicweb/client 1.4.0 → 1.5.0
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.
- package/lib/api/Api.d.ts +87 -3
- package/lib/api/Api.d.ts.map +1 -1
- package/lib/api/Api.js +99 -10
- package/lib/api/Api.js.map +1 -1
- package/lib/api/Client.d.ts +39 -1
- package/lib/api/Client.d.ts.map +1 -1
- package/lib/api/Client.js +41 -1
- package/lib/api/Client.js.map +1 -1
- package/lib/api/Transaction.d.ts +42 -0
- package/lib/api/Transaction.d.ts.map +1 -1
- package/lib/api/Transaction.js +42 -0
- package/lib/api/Transaction.js.map +1 -1
- package/lib/index.d.ts +9 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +13 -9
- package/lib/index.js.map +1 -1
- package/lib/schema/classes/EntitySchema.d.ts +71 -0
- package/lib/schema/classes/EntitySchema.d.ts.map +1 -0
- package/lib/schema/classes/EntitySchema.js +83 -0
- package/lib/schema/classes/EntitySchema.js.map +1 -0
- package/lib/schema/classes/RelationDefinitionSchema.d.ts +87 -0
- package/lib/schema/classes/RelationDefinitionSchema.d.ts.map +1 -0
- package/lib/schema/classes/RelationDefinitionSchema.js +128 -0
- package/lib/schema/classes/RelationDefinitionSchema.js.map +1 -0
- package/lib/schema/classes/Schema.d.ts +54 -0
- package/lib/schema/classes/Schema.d.ts.map +1 -0
- package/lib/schema/classes/Schema.js +75 -0
- package/lib/schema/classes/Schema.js.map +1 -0
- package/lib/schema/classes/Utils.d.ts +30 -0
- package/lib/schema/classes/Utils.d.ts.map +1 -0
- package/lib/schema/classes/Utils.js +25 -0
- package/lib/schema/classes/Utils.js.map +1 -0
- package/lib/schema/raw/Constraints.d.ts +58 -0
- package/lib/schema/raw/Constraints.d.ts.map +1 -0
- package/lib/schema/raw/Constraints.js +3 -0
- package/lib/schema/raw/Constraints.js.map +1 -0
- package/lib/schema/raw/Entities.d.ts +13 -0
- package/lib/schema/raw/Entities.d.ts.map +1 -0
- package/lib/schema/{SchemaJSON.js → raw/Entities.js} +1 -1
- package/lib/schema/raw/Entities.js.map +1 -0
- package/lib/schema/raw/RelationDefinitions.d.ts +113 -0
- package/lib/schema/raw/RelationDefinitions.d.ts.map +1 -0
- package/lib/schema/raw/RelationDefinitions.js +3 -0
- package/lib/schema/raw/RelationDefinitions.js.map +1 -0
- package/lib/schema/raw/Schema.d.ts +13 -0
- package/lib/schema/raw/Schema.d.ts.map +1 -0
- package/lib/schema/raw/Schema.js +3 -0
- package/lib/schema/raw/Schema.js.map +1 -0
- package/lib/schema/raw/Utils.d.ts +22 -0
- package/lib/schema/raw/Utils.d.ts.map +1 -0
- package/lib/schema/raw/Utils.js +3 -0
- package/lib/schema/raw/Utils.js.map +1 -0
- package/package.json +1 -1
- package/src/api/Api.ts +128 -15
- package/src/api/Client.ts +42 -1
- package/src/api/Transaction.ts +42 -0
- package/src/index.ts +15 -8
- package/src/schema/classes/EntitySchema.ts +125 -0
- package/src/schema/classes/RelationDefinitionSchema.ts +156 -0
- package/src/schema/classes/Schema.ts +122 -0
- package/src/schema/classes/Utils.ts +52 -0
- package/src/schema/raw/Constraints.ts +77 -0
- package/src/schema/raw/Entities.ts +13 -0
- package/src/schema/{SchemaJSON.ts → raw/RelationDefinitions.ts} +36 -101
- package/src/schema/raw/Schema.ts +16 -0
- package/src/schema/raw/Utils.ts +33 -0
- package/lib/schema/Schema.d.ts +0 -156
- package/lib/schema/Schema.d.ts.map +0 -1
- package/lib/schema/Schema.js +0 -246
- package/lib/schema/Schema.js.map +0 -1
- package/lib/schema/SchemaJSON.d.ts +0 -140
- package/lib/schema/SchemaJSON.d.ts.map +0 -1
- package/lib/schema/SchemaJSON.js.map +0 -1
- package/src/schema/Schema.ts +0 -371
package/src/api/Transaction.ts
CHANGED
|
@@ -1,36 +1,78 @@
|
|
|
1
1
|
import { TransactionClosedError } from "../Errors";
|
|
2
2
|
import Api, { RQLParams } from "./Api";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Class used to handle CubicWeb's transactions.
|
|
6
|
+
* A transaction allows to execute several RQL requests without altering the database until all
|
|
7
|
+
* changes are committed.
|
|
8
|
+
*
|
|
9
|
+
* You should never have to create this object yourself.
|
|
10
|
+
* Instead, retrieve this object from the methods in the `Client` class.
|
|
11
|
+
*/
|
|
4
12
|
export default class Transaction {
|
|
5
13
|
private _uuid: string | null = null;
|
|
6
14
|
private _closed = false;
|
|
7
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Class used to handle CubicWeb's transactions.
|
|
18
|
+
* A transaction allows to execute several RQL requests without altering the database until all
|
|
19
|
+
* changes are committed.
|
|
20
|
+
*
|
|
21
|
+
* You should never have to create this object yourself.
|
|
22
|
+
* Instead, retrieve this object from the methods in the `Client` class.
|
|
23
|
+
*
|
|
24
|
+
* @param api The API object used to communicate with the CubicWeb backend.
|
|
25
|
+
*/
|
|
8
26
|
constructor(private api: Api) {}
|
|
9
27
|
|
|
28
|
+
/**
|
|
29
|
+
* @returns True if the connection is closed.
|
|
30
|
+
*/
|
|
10
31
|
isClosed() {
|
|
11
32
|
return this._closed;
|
|
12
33
|
}
|
|
13
34
|
|
|
35
|
+
/**
|
|
36
|
+
* This transaction unique identifier.
|
|
37
|
+
*/
|
|
14
38
|
get uuid() {
|
|
15
39
|
return this._uuid;
|
|
16
40
|
}
|
|
17
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Begins a new transaction an retrieves the associated uuid.
|
|
44
|
+
*/
|
|
18
45
|
async begin() {
|
|
19
46
|
this._closed = false;
|
|
20
47
|
this._uuid = await this.api.transactionBegin();
|
|
21
48
|
}
|
|
22
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Executes the given query and waits for the response.
|
|
52
|
+
* Make sure you called `begin` before using this method.
|
|
53
|
+
* As this is a transaction changes will only be applied when you call the `commit` method.
|
|
54
|
+
*
|
|
55
|
+
* @param query The RQL query to send
|
|
56
|
+
* @param params The additional parameters for the request
|
|
57
|
+
* @returns A promise with the request's result set
|
|
58
|
+
*/
|
|
23
59
|
async execute(query: string, params: RQLParams = {}) {
|
|
24
60
|
this.preventUsageIfClosed();
|
|
25
61
|
return await this.api.transactionExecute(this.uuid, query, params);
|
|
26
62
|
}
|
|
27
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Commits the transaction to apply all the RQL queries sent with `execute`.
|
|
66
|
+
*/
|
|
28
67
|
async commit() {
|
|
29
68
|
this.preventUsageIfClosed();
|
|
30
69
|
await this.api.transactionCommit(this.uuid);
|
|
31
70
|
this._closed = true;
|
|
32
71
|
}
|
|
33
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Rollbacks all the queries sent with `execute` and closes the transaction.
|
|
75
|
+
*/
|
|
34
76
|
async rollback() {
|
|
35
77
|
this.preventUsageIfClosed();
|
|
36
78
|
await this.api.transactionRollback(this.uuid);
|
package/src/index.ts
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
// Raw Schema
|
|
2
|
+
export * from "./schema/raw/Constraints";
|
|
3
|
+
export * from "./schema/raw/Entities";
|
|
4
|
+
export * from "./schema/raw/RelationDefinitions";
|
|
5
|
+
export * from "./schema/raw/Schema";
|
|
6
|
+
export * from "./schema/raw/Utils";
|
|
7
|
+
|
|
8
|
+
// Schema Abstraction class
|
|
9
|
+
export * from "./schema/classes/EntitySchema";
|
|
10
|
+
export * from "./schema/classes/RelationDefinitionSchema";
|
|
11
|
+
export * from "./schema/classes/Schema";
|
|
12
|
+
export * from "./schema/classes/Utils";
|
|
13
|
+
|
|
8
14
|
export * from "./Errors";
|
|
15
|
+
|
|
16
|
+
// API
|
|
9
17
|
export { default as Client } from "./api/Client";
|
|
10
|
-
export { default as Api } from "./api/Api";
|
|
11
18
|
export { default as Transaction } from "./api/Transaction";
|
|
12
19
|
export {
|
|
13
20
|
RQLQuery,
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { EntityRawSchemaArray } from "../raw/Entities";
|
|
2
|
+
import { RelationDefinitionRawSchemaArray } from "../raw/RelationDefinitions";
|
|
3
|
+
import { RelationDefinitionSchema } from "./RelationDefinitionSchema";
|
|
4
|
+
import { Schema } from "./Schema";
|
|
5
|
+
import { MatchedRelationDefinition, RelationDefinitionMatcher } from "./Utils";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Wrapper around raw entity schemas from the Schema.
|
|
9
|
+
* You should never have to create this object yourself.
|
|
10
|
+
* Instead, retrieve these objects from the methods in the `Schema` class.
|
|
11
|
+
*/
|
|
12
|
+
export class EntitySchema<
|
|
13
|
+
E extends EntityRawSchemaArray = EntityRawSchemaArray,
|
|
14
|
+
R extends RelationDefinitionRawSchemaArray<E> = RelationDefinitionRawSchemaArray<E>,
|
|
15
|
+
ERawSchema extends E[number] = E[number]
|
|
16
|
+
> {
|
|
17
|
+
/**
|
|
18
|
+
* Wrapper around raw entity schemas from the Schema.
|
|
19
|
+
* You should never have to create this object yourself.
|
|
20
|
+
* Instead, retrieve these objects from the methods in the `Schema` class.
|
|
21
|
+
*
|
|
22
|
+
* @param schema The Schema abstraction class used to create this object
|
|
23
|
+
* @param entityRawSchema The raw entity schema
|
|
24
|
+
*/
|
|
25
|
+
constructor(
|
|
26
|
+
private schema: Schema<E, R>,
|
|
27
|
+
private entityRawSchema: ERawSchema
|
|
28
|
+
) {}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The type of the entity schema. This can also be referred to as the entity schema's name.
|
|
32
|
+
*/
|
|
33
|
+
get type(): ERawSchema["type"] {
|
|
34
|
+
return this.entityRawSchema.type;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A short description which can be used as documentation for the entity schema.
|
|
39
|
+
*/
|
|
40
|
+
get description(): ERawSchema["description"] {
|
|
41
|
+
return this.entityRawSchema.description;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* True if the current entity schema is a primitive type such as string or int
|
|
46
|
+
*/
|
|
47
|
+
get final(): ERawSchema["final"] {
|
|
48
|
+
return this.entityRawSchema.final;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
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`.
|
|
55
|
+
*/
|
|
56
|
+
get subjectRelationDefinitions(): RelationDefinitionSchema<
|
|
57
|
+
E,
|
|
58
|
+
R,
|
|
59
|
+
MatchedRelationDefinition<
|
|
60
|
+
E,
|
|
61
|
+
R,
|
|
62
|
+
{ subject: ERawSchema["type"]; final: false }
|
|
63
|
+
>
|
|
64
|
+
>[] {
|
|
65
|
+
return this.schema.matchRelationDefinitions({
|
|
66
|
+
subject: this.type,
|
|
67
|
+
final: false,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
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<
|
|
80
|
+
E,
|
|
81
|
+
R,
|
|
82
|
+
{ object: ERawSchema["type"]; final: false }
|
|
83
|
+
>
|
|
84
|
+
>[] {
|
|
85
|
+
return this.schema.matchRelationDefinitions({
|
|
86
|
+
object: this.type,
|
|
87
|
+
final: false,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Finds relations in the Schema matching the partial relation given.
|
|
93
|
+
*
|
|
94
|
+
* @param matcher Partial relation definition to match against
|
|
95
|
+
* @returns Matched relation schema classes
|
|
96
|
+
*/
|
|
97
|
+
matchRelationDefinitions<M extends RelationDefinitionMatcher<E>>(
|
|
98
|
+
matcher: M
|
|
99
|
+
): RelationDefinitionSchema<
|
|
100
|
+
E,
|
|
101
|
+
R,
|
|
102
|
+
MatchedRelationDefinition<E, R, { subject: ERawSchema["type"] }>
|
|
103
|
+
>[] {
|
|
104
|
+
return this.schema.matchRelationDefinitions(matcher);
|
|
105
|
+
}
|
|
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
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { InconsistentSchemaError } from "../../Errors";
|
|
2
|
+
import { EntityRawSchemaArray } from "../raw/Entities";
|
|
3
|
+
import {
|
|
4
|
+
RelationDefinitionRawSchemaArray,
|
|
5
|
+
Cardinality,
|
|
6
|
+
} from "../raw/RelationDefinitions";
|
|
7
|
+
import { IsLooseSchema, EntityRawSchemaByType } from "../raw/Utils";
|
|
8
|
+
import { EntitySchema } from "./EntitySchema";
|
|
9
|
+
import { Schema } from "./Schema";
|
|
10
|
+
import { cardinalityRequired } from "./Utils";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Wrapper around raw relation definition schemas from the Schema.
|
|
14
|
+
* You should never have to create this object yourself.
|
|
15
|
+
* Instead, retrieve these objects from the methods in the `Schema` class.
|
|
16
|
+
*/
|
|
17
|
+
export class RelationDefinitionSchema<
|
|
18
|
+
E extends EntityRawSchemaArray = EntityRawSchemaArray,
|
|
19
|
+
R extends RelationDefinitionRawSchemaArray<E> = RelationDefinitionRawSchemaArray<E>,
|
|
20
|
+
RDef extends R[number] = R[number]
|
|
21
|
+
> {
|
|
22
|
+
/**
|
|
23
|
+
* Wrapper around raw relation definition schemas from the Schema.
|
|
24
|
+
* You should never have to create this object yourself.
|
|
25
|
+
* Instead, retrieve these objects from the methods in the `Schema` class.
|
|
26
|
+
*
|
|
27
|
+
* @param schema The Schema abstractin class used to create this object
|
|
28
|
+
* @param relDef The raw relation definition schema
|
|
29
|
+
*/
|
|
30
|
+
constructor(private schema: Schema<E, R>, private relDef: RDef) {}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The type of the relation definition. This can also be referred to as the relation definition's name.
|
|
34
|
+
*/
|
|
35
|
+
get type(): RDef["type"] {
|
|
36
|
+
return this.relDef.type;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* A short description which can be used as documentation for the relation definition schema.
|
|
41
|
+
*/
|
|
42
|
+
get description(): RDef["description"] {
|
|
43
|
+
return this.relDef.description;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* True if the object of the relation definition schema is a primitive type.
|
|
48
|
+
* In this case the relation is called an "attribute".
|
|
49
|
+
*/
|
|
50
|
+
get final(): RDef["final"] {
|
|
51
|
+
return this.relDef.final;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The list of options set for this relation definition schema.
|
|
56
|
+
* The returned type will change if this relationd definition schema
|
|
57
|
+
* describes an attribute or a relation.
|
|
58
|
+
*/
|
|
59
|
+
get options(): RDef["options"] {
|
|
60
|
+
return this.relDef.options;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The list of constraints set for this relation definition schema.
|
|
65
|
+
* The returned type will change if this relationd definition schema
|
|
66
|
+
* describes an attribute or a relation.
|
|
67
|
+
*/
|
|
68
|
+
get constraints(): RDef["constraints"] {
|
|
69
|
+
return this.relDef.constraints;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The default value for this relation.
|
|
74
|
+
* It can be used when creating new relations if the user did not enter a value (even if required).
|
|
75
|
+
*/
|
|
76
|
+
get default(): RDef extends { default: infer V } ? V : undefined {
|
|
77
|
+
type Default = RDef extends { default: infer V } ? V : undefined;
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
"default" in this.relDef ? this.relDef.default : undefined
|
|
81
|
+
) as Default;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The cardinality of this relation definition schema.
|
|
86
|
+
*/
|
|
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;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Gets the entity associated to this relation definition schema's subject.
|
|
107
|
+
*
|
|
108
|
+
* @throws InconsistentSchemaError if the relation definition schema's subject is not a valid entity
|
|
109
|
+
*/
|
|
110
|
+
get subject(): IsLooseSchema<E> extends true
|
|
111
|
+
? EntitySchema<E, R, E[number]>
|
|
112
|
+
: EntitySchema<E, R, EntityRawSchemaByType<E, RDef["subject"]>> {
|
|
113
|
+
const subjectSchema = this.schema.getEntity(this.relDef.subject);
|
|
114
|
+
if (subjectSchema === null) {
|
|
115
|
+
throw new InconsistentSchemaError(
|
|
116
|
+
`entity type ${this.relDef.subject} used as subject of relation ${this.type} is not declared`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
// @ts-ignore: Cannot be null as we checked for this above
|
|
120
|
+
return subjectSchema;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Gets the entity associated to this relation definition schema's object.
|
|
125
|
+
*
|
|
126
|
+
* @throws InconsistentSchemaError if the relation definition schema's object is not a valid entity
|
|
127
|
+
*/
|
|
128
|
+
get object(): IsLooseSchema<E> extends true
|
|
129
|
+
? EntitySchema<E, R, E[number]>
|
|
130
|
+
: EntitySchema<E, R, EntityRawSchemaByType<E, RDef["object"]>> {
|
|
131
|
+
const objectSchema = this.schema.getEntity(this.relDef.object);
|
|
132
|
+
if (objectSchema === null) {
|
|
133
|
+
throw new InconsistentSchemaError(
|
|
134
|
+
`entity type ${this.relDef.object} used as object of relation ${this.type} is not declared`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
// @ts-ignore: Cannot be null as we checked for this above
|
|
138
|
+
return objectSchema;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Checks if the relation is required when using the subject or object point of view.
|
|
143
|
+
*
|
|
144
|
+
* @param role The point of view to use
|
|
145
|
+
* @returns
|
|
146
|
+
*/
|
|
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);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { EntityRawSchemaArray } from "../raw/Entities";
|
|
2
|
+
import {
|
|
3
|
+
RelationDefinitionRawSchema,
|
|
4
|
+
RelationDefinitionRawSchemaArray,
|
|
5
|
+
} from "../raw/RelationDefinitions";
|
|
6
|
+
import { RawSchema } from "../raw/Schema";
|
|
7
|
+
import {
|
|
8
|
+
EntityRawSchemaByType,
|
|
9
|
+
IsETypeInStrictSchema,
|
|
10
|
+
IsLooseSchema,
|
|
11
|
+
} from "../raw/Utils";
|
|
12
|
+
import { EntitySchema } from "./EntitySchema";
|
|
13
|
+
import { RelationDefinitionSchema } from "./RelationDefinitionSchema";
|
|
14
|
+
import { RelationDefinitionMatcher, MatchedRelationDefinition } from "./Utils";
|
|
15
|
+
|
|
16
|
+
const rawSchemaKey: unique symbol = Symbol("Indexer of the rawSchema");
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Wrapper around the raw JSON Schema.
|
|
20
|
+
* It is recommended to use this class instead of the raw JSON Schema
|
|
21
|
+
* as it is more robust to schema changes and provides utility functions.
|
|
22
|
+
*/
|
|
23
|
+
export class Schema<
|
|
24
|
+
E extends EntityRawSchemaArray = EntityRawSchemaArray,
|
|
25
|
+
R extends RelationDefinitionRawSchemaArray<E> = RelationDefinitionRawSchemaArray<E>
|
|
26
|
+
> {
|
|
27
|
+
[rawSchemaKey]: RawSchema<E, R>;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Wrapper around the raw JSON Schema.
|
|
31
|
+
* It is recommended to use this class instead of the raw JSON Schema
|
|
32
|
+
* as it is more robust to schema changes and provides utility functions.
|
|
33
|
+
*
|
|
34
|
+
* @param rawSchema The raw JSON schema to create the wrapper from.
|
|
35
|
+
*/
|
|
36
|
+
constructor(rawSchema: RawSchema<E, R>) {
|
|
37
|
+
this[rawSchemaKey] = rawSchema;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Returns the list of entity schemas in the schema using the EntitySchema abstraction class.
|
|
42
|
+
*/
|
|
43
|
+
get entities(): EntitySchema<E, R, E[number]>[] {
|
|
44
|
+
return this[rawSchemaKey].entities.map(
|
|
45
|
+
(eSchema) => new EntitySchema(this, eSchema)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Returns the list of relation definitions schemas in the schema
|
|
51
|
+
* using the RelationDefinitionSchema abstraction class.
|
|
52
|
+
*/
|
|
53
|
+
get relationsDefinitions(): RelationDefinitionSchema<E, R, R[number]>[] {
|
|
54
|
+
return this[rawSchemaKey].relations_definitions.map(
|
|
55
|
+
(rdefSchema) => new RelationDefinitionSchema(this, rdefSchema)
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Returns the entity schema for the given entity type if it exists.
|
|
61
|
+
* When using TypeScript, this method can detect if the given type does not exist
|
|
62
|
+
* in the schema.
|
|
63
|
+
*
|
|
64
|
+
* @param entityType The entity type string
|
|
65
|
+
* @returns A new EntitySchema or null if the type does not exist
|
|
66
|
+
*/
|
|
67
|
+
getEntity<EType extends string>(
|
|
68
|
+
entityType: EType
|
|
69
|
+
): IsLooseSchema<E> extends true
|
|
70
|
+
? EntitySchema<E, R, E[number]> | null
|
|
71
|
+
: IsETypeInStrictSchema<E, EType> extends true
|
|
72
|
+
? EntitySchema<E, R, EntityRawSchemaByType<E, EType>>
|
|
73
|
+
: null {
|
|
74
|
+
const entityRawSchema = this[rawSchemaKey].entities.filter(
|
|
75
|
+
(eSchema) => eSchema.type === entityType
|
|
76
|
+
)[0];
|
|
77
|
+
if (!entityRawSchema) {
|
|
78
|
+
// @ts-ignore: Is only null when the given type is not in the schema.
|
|
79
|
+
// Thus the return type will be (EntitySchema | null)
|
|
80
|
+
// but TypeScript does not understand this
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
// @ts-ignore: see above
|
|
84
|
+
return new EntitySchema<E, R, E[number]>(
|
|
85
|
+
this,
|
|
86
|
+
entityRawSchema as EntityRawSchemaByType<E, EType>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Finds relations definition schemas in the Schema matching the
|
|
92
|
+
* raw partial relation definition schema given.
|
|
93
|
+
*
|
|
94
|
+
* @param matcher Partial raw relation definition schema to match against
|
|
95
|
+
* @returns Array of matched relation definition schema classes
|
|
96
|
+
*/
|
|
97
|
+
matchRelationDefinitions<M extends RelationDefinitionMatcher<E>>(
|
|
98
|
+
matcher: M
|
|
99
|
+
): RelationDefinitionSchema<
|
|
100
|
+
E,
|
|
101
|
+
R,
|
|
102
|
+
MatchedRelationDefinition<E, R, { subject: E[number]["type"] }>
|
|
103
|
+
>[] {
|
|
104
|
+
const matchArray = this[rawSchemaKey].relations_definitions.filter(
|
|
105
|
+
(relDef) => {
|
|
106
|
+
for (const key of Object.keys(
|
|
107
|
+
matcher
|
|
108
|
+
) as (keyof RelationDefinitionRawSchema<E>)[]) {
|
|
109
|
+
if (matcher[key] !== relDef[key]) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
) as MatchedRelationDefinition<
|
|
116
|
+
E,
|
|
117
|
+
R,
|
|
118
|
+
MatchedRelationDefinition<E, R, { subject: E[number]["type"] }>
|
|
119
|
+
>[];
|
|
120
|
+
return matchArray.map((m) => new RelationDefinitionSchema(this, m));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { EntityRawSchemaArray } from "../raw/Entities";
|
|
2
|
+
import {
|
|
3
|
+
Cardinality,
|
|
4
|
+
RelationDefinitionRawSchema,
|
|
5
|
+
RelationDefinitionRawSchemaArray,
|
|
6
|
+
} from "../raw/RelationDefinitions";
|
|
7
|
+
import { Schema } from "./Schema";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Returns the given schema using loose typing.
|
|
11
|
+
* Can be useful when working with generic schemas
|
|
12
|
+
*
|
|
13
|
+
* @param schema The schema to create a loose type for
|
|
14
|
+
* @returns A loosely typed schema
|
|
15
|
+
*/
|
|
16
|
+
export const getLooseSchema = <
|
|
17
|
+
E extends EntityRawSchemaArray = EntityRawSchemaArray,
|
|
18
|
+
R extends RelationDefinitionRawSchemaArray<E> = RelationDefinitionRawSchemaArray<E>
|
|
19
|
+
>(
|
|
20
|
+
schema: Schema<E, R>
|
|
21
|
+
) => {
|
|
22
|
+
return schema as unknown as Schema;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Checks if the given cardinality requires at least one entity to be present
|
|
27
|
+
*
|
|
28
|
+
* @param cardinality The cardinality to check
|
|
29
|
+
* @returns True if the cardinality is 1 or +
|
|
30
|
+
*/
|
|
31
|
+
export function cardinalityRequired(cardinality: Cardinality): boolean {
|
|
32
|
+
return cardinality === "1" || cardinality === "+";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Partial raw relation definition schema type.
|
|
37
|
+
*/
|
|
38
|
+
export type RelationDefinitionMatcher<E extends EntityRawSchemaArray> = Partial<
|
|
39
|
+
RelationDefinitionRawSchema<E>
|
|
40
|
+
>;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Type representing a raw relation definition matched from a partial raw relation definition schema.
|
|
44
|
+
* If it finds a relation definition matching the partial one given, it will return its type.
|
|
45
|
+
* If it cannot find any relation definition matching, it will return the `never` type
|
|
46
|
+
* and TypeScript will give compile errors.
|
|
47
|
+
*/
|
|
48
|
+
export type MatchedRelationDefinition<
|
|
49
|
+
E extends EntityRawSchemaArray,
|
|
50
|
+
R extends RelationDefinitionRawSchemaArray<EntityRawSchemaArray>,
|
|
51
|
+
M extends RelationDefinitionMatcher<E>
|
|
52
|
+
> = R[number] extends infer RDef ? (RDef extends M ? RDef : never) : never;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base type used to describe a constraint.
|
|
3
|
+
*/
|
|
4
|
+
type ConstraintBase<
|
|
5
|
+
T extends string,
|
|
6
|
+
V extends Record<string, unknown> | null
|
|
7
|
+
> = {
|
|
8
|
+
type: T;
|
|
9
|
+
value: V;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* All the possible operators inside a constraint.
|
|
14
|
+
*/
|
|
15
|
+
export type ConstraintOperator = ">" | ">=" | "<" | "<=";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* THe type of a constraint message when one is present.
|
|
19
|
+
*/
|
|
20
|
+
type ConstraintMessage = string | null;
|
|
21
|
+
|
|
22
|
+
export type UniqueConstraint = ConstraintBase<"UniqueConstraint", null>;
|
|
23
|
+
|
|
24
|
+
export type SizeConstraint = ConstraintBase<
|
|
25
|
+
"SizeConstraint",
|
|
26
|
+
{ min: number | null; max: number | null; msg: ConstraintMessage }
|
|
27
|
+
>;
|
|
28
|
+
|
|
29
|
+
export type RegexpConstraint = ConstraintBase<
|
|
30
|
+
"RegexpConstraint",
|
|
31
|
+
{ regexp: string; flags: number; msg: ConstraintMessage }
|
|
32
|
+
>;
|
|
33
|
+
|
|
34
|
+
export type BoundaryConstraint = ConstraintBase<
|
|
35
|
+
"BoundaryConstraint",
|
|
36
|
+
{ boundary: number | null; op: ConstraintOperator; msg: ConstraintMessage }
|
|
37
|
+
>;
|
|
38
|
+
export type IntervalBoundConstraint = ConstraintBase<
|
|
39
|
+
"IntervalBoundConstraint",
|
|
40
|
+
{ minvalue: number | null; maxvalue: number | null; msg: ConstraintMessage }
|
|
41
|
+
>;
|
|
42
|
+
|
|
43
|
+
export type StaticVocabularyConstraint = ConstraintBase<
|
|
44
|
+
"StaticVocabularyConstraint",
|
|
45
|
+
{ values: string[]; msg: ConstraintMessage }
|
|
46
|
+
>;
|
|
47
|
+
|
|
48
|
+
export type FormatConstraint = ConstraintBase<
|
|
49
|
+
"FormatConstraint",
|
|
50
|
+
{
|
|
51
|
+
values: ["text/rest", "text/markdown", "text/html", "text/plain"];
|
|
52
|
+
msg: ConstraintMessage;
|
|
53
|
+
}
|
|
54
|
+
>;
|
|
55
|
+
|
|
56
|
+
export type RQLVocabularyConstraint = ConstraintBase<
|
|
57
|
+
"RQLVocabularyConstraint",
|
|
58
|
+
{ expression: string; mainvars: string[] }
|
|
59
|
+
>;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Type representing all possible constraints for attributes.
|
|
63
|
+
*/
|
|
64
|
+
export type AttributeConstraint = Readonly<
|
|
65
|
+
| UniqueConstraint
|
|
66
|
+
| SizeConstraint
|
|
67
|
+
| RegexpConstraint
|
|
68
|
+
| BoundaryConstraint
|
|
69
|
+
| IntervalBoundConstraint
|
|
70
|
+
| StaticVocabularyConstraint
|
|
71
|
+
| FormatConstraint
|
|
72
|
+
>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Type representing all possible constraints for relations.
|
|
76
|
+
*/
|
|
77
|
+
export type RelationConstraint = Readonly<RQLVocabularyConstraint>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type representing an entity schema.
|
|
3
|
+
*/
|
|
4
|
+
export type EntityRawSchema = {
|
|
5
|
+
type: string;
|
|
6
|
+
final: boolean;
|
|
7
|
+
description: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Type representing a list of entity schemas.
|
|
12
|
+
*/
|
|
13
|
+
export type EntityRawSchemaArray = ReadonlyArray<EntityRawSchema>;
|