@acodeninja/persist 2.2.1 → 2.2.2
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/.deepsource.toml +10 -0
- package/package.json +1 -1
- package/src/Persist.js +3 -1
- package/src/Query.js +37 -16
- package/src/SchemaCompiler.js +68 -17
- package/src/engine/Engine.js +203 -36
- package/src/engine/FileEngine.js +118 -32
- package/src/engine/HTTPEngine.js +148 -26
- package/src/engine/S3Engine.js +131 -33
- package/src/type/Model.js +137 -22
- package/src/type/Type.js +42 -8
- package/src/type/complex/ArrayType.js +54 -1
- package/src/type/complex/CustomType.js +35 -1
- package/src/type/resolved/ResolvedType.js +39 -1
- package/src/type/resolved/SlugType.js +41 -1
- package/src/type/simple/BooleanType.js +16 -1
- package/src/type/simple/DateType.js +28 -1
- package/src/type/simple/NumberType.js +16 -1
- package/src/type/simple/SimpleType.js +11 -1
- package/src/type/simple/StringType.js +16 -1
package/src/engine/S3Engine.js
CHANGED
@@ -1,49 +1,107 @@
|
|
1
1
|
import Engine, {EngineError, MissConfiguredError} from './Engine.js';
|
2
2
|
import {GetObjectCommand, PutObjectCommand} from '@aws-sdk/client-s3';
|
3
3
|
|
4
|
+
/**
|
5
|
+
* Represents an error specific to the S3 engine operations.
|
6
|
+
* @class S3EngineError
|
7
|
+
* @extends EngineError
|
8
|
+
*/
|
4
9
|
class S3EngineError extends EngineError {}
|
5
10
|
|
11
|
+
/**
|
12
|
+
* Error indicating a failure when putting an object to S3.
|
13
|
+
* @class FailedPutS3EngineError
|
14
|
+
* @extends S3EngineError
|
15
|
+
*/
|
6
16
|
class FailedPutS3EngineError extends S3EngineError {}
|
7
17
|
|
8
|
-
|
18
|
+
/**
|
19
|
+
* S3Engine is an extension of the Engine class that provides methods for interacting with AWS S3.
|
20
|
+
* It allows for storing, retrieving, and managing model data in an S3 bucket.
|
21
|
+
*
|
22
|
+
* @class S3Engine
|
23
|
+
* @extends Engine
|
24
|
+
*/
|
25
|
+
class S3Engine extends Engine {
|
26
|
+
/**
|
27
|
+
* Configures the S3 engine with additional options.
|
28
|
+
*
|
29
|
+
* @param {Object} configuration - Configuration object.
|
30
|
+
* @param {S3Client} [configuration.client] - An S3 client used to process operations.
|
31
|
+
* @param {string} [configuration.bucket] - The S3 bucket to perform operations against.
|
32
|
+
* @param {string?} [configuration.prefix] - The optional prefix in the bucket to perform operations against.
|
33
|
+
* @returns {Object} The configured settings for the HTTP engine.
|
34
|
+
*/
|
35
|
+
static configure(configuration = {}) {
|
36
|
+
return super.configure(configuration);
|
37
|
+
}
|
38
|
+
|
39
|
+
/**
|
40
|
+
* Validates the S3 engine configuration to ensure necessary parameters (bucket and client) are present.
|
41
|
+
* Throws an error if the configuration is invalid.
|
42
|
+
*
|
43
|
+
* @throws {MissConfiguredError} Thrown when the configuration is missing required parameters.
|
44
|
+
*/
|
9
45
|
static checkConfiguration() {
|
10
46
|
if (
|
11
|
-
!this.
|
12
|
-
!this.
|
13
|
-
) throw new MissConfiguredError(this.
|
47
|
+
!this.configuration?.bucket ||
|
48
|
+
!this.configuration?.client
|
49
|
+
) throw new MissConfiguredError(this.configuration);
|
14
50
|
}
|
15
51
|
|
52
|
+
/**
|
53
|
+
* Retrieves an object from S3 by its ID.
|
54
|
+
*
|
55
|
+
* @param {string} id - The ID of the object to retrieve.
|
56
|
+
* @returns {Promise<Object>} The parsed JSON object retrieved from S3.
|
57
|
+
*
|
58
|
+
* @throws {Error} Thrown if there is an issue with the S3 client request.
|
59
|
+
*/
|
16
60
|
static async getById(id) {
|
17
|
-
const objectPath = [this.
|
61
|
+
const objectPath = [this.configuration.prefix, `${id}.json`].join('/');
|
18
62
|
|
19
|
-
const data = await this.
|
20
|
-
Bucket: this.
|
63
|
+
const data = await this.configuration.client.send(new GetObjectCommand({
|
64
|
+
Bucket: this.configuration.bucket,
|
21
65
|
Key: objectPath,
|
22
66
|
}));
|
23
67
|
|
24
68
|
return JSON.parse(await data.Body.transformToString());
|
25
69
|
}
|
26
70
|
|
71
|
+
/**
|
72
|
+
* Puts (uploads) a model object to S3.
|
73
|
+
*
|
74
|
+
* @param {Model} model - The model object to upload.
|
75
|
+
* @returns {Promise<void>}
|
76
|
+
*
|
77
|
+
* @throws {FailedPutS3EngineError} Thrown if there is an error during the S3 PutObject operation.
|
78
|
+
*/
|
27
79
|
static async putModel(model) {
|
28
|
-
const Key = [this.
|
80
|
+
const Key = [this.configuration.prefix, `${model.id}.json`].join('/');
|
29
81
|
|
30
82
|
try {
|
31
|
-
await this.
|
83
|
+
await this.configuration.client.send(new PutObjectCommand({
|
32
84
|
Key,
|
33
85
|
Body: JSON.stringify(model.toData()),
|
34
|
-
Bucket: this.
|
86
|
+
Bucket: this.configuration.bucket,
|
35
87
|
ContentType: 'application/json',
|
36
88
|
}));
|
37
89
|
} catch (error) {
|
38
|
-
throw new FailedPutS3EngineError(`Failed to put s3://${this.
|
90
|
+
throw new FailedPutS3EngineError(`Failed to put s3://${this.configuration.bucket}/${Key}`, error);
|
39
91
|
}
|
40
92
|
}
|
41
93
|
|
42
|
-
|
94
|
+
/**
|
95
|
+
* Retrieves the index object from S3 at the specified location.
|
96
|
+
*
|
97
|
+
* @param {Model.constructor?} model - The model in the bucket where the index is stored.
|
98
|
+
* @returns {Promise<Object>} The parsed index object.
|
99
|
+
*/
|
100
|
+
static async getIndex(model) {
|
43
101
|
try {
|
44
|
-
const data = await this.
|
45
|
-
Key: [this.
|
46
|
-
Bucket: this.
|
102
|
+
const data = await this.configuration.client.send(new GetObjectCommand({
|
103
|
+
Key: [this.configuration.prefix, model?.toString(), '_index.json'].filter(e => Boolean(e)).join('/'),
|
104
|
+
Bucket: this.configuration.bucket,
|
47
105
|
}));
|
48
106
|
|
49
107
|
return JSON.parse(await data.Body.transformToString());
|
@@ -52,17 +110,25 @@ export default class S3Engine extends Engine {
|
|
52
110
|
}
|
53
111
|
}
|
54
112
|
|
113
|
+
/**
|
114
|
+
* Puts (uploads) an index object to S3.
|
115
|
+
*
|
116
|
+
* @param {Object} index - The index data to upload, organized by location.
|
117
|
+
* @returns {Promise<void>}
|
118
|
+
*
|
119
|
+
* @throws {FailedPutS3EngineError} Thrown if there is an error during the S3 PutObject operation.
|
120
|
+
*/
|
55
121
|
static async putIndex(index) {
|
56
122
|
const processIndex = async (location, models) => {
|
57
123
|
const modelIndex = Object.fromEntries(models.map(m => [m.id, m.toIndexData()]));
|
58
|
-
const Key = [this.
|
124
|
+
const Key = [this.configuration.prefix, location, '_index.json'].filter(e => Boolean(e)).join('/');
|
59
125
|
|
60
126
|
const currentIndex = await this.getIndex(location);
|
61
127
|
|
62
128
|
try {
|
63
|
-
await this.
|
129
|
+
await this.configuration.client.send(new PutObjectCommand({
|
64
130
|
Key,
|
65
|
-
Bucket: this.
|
131
|
+
Bucket: this.configuration.bucket,
|
66
132
|
ContentType: 'application/json',
|
67
133
|
Body: JSON.stringify({
|
68
134
|
...currentIndex,
|
@@ -70,7 +136,7 @@ export default class S3Engine extends Engine {
|
|
70
136
|
}),
|
71
137
|
}));
|
72
138
|
} catch (error) {
|
73
|
-
throw new FailedPutS3EngineError(`Failed to put s3://${this.
|
139
|
+
throw new FailedPutS3EngineError(`Failed to put s3://${this.configuration.bucket}/${Key}`, error);
|
74
140
|
}
|
75
141
|
};
|
76
142
|
|
@@ -81,50 +147,82 @@ export default class S3Engine extends Engine {
|
|
81
147
|
await processIndex(null, Object.values(index).flat());
|
82
148
|
}
|
83
149
|
|
150
|
+
/**
|
151
|
+
* Retrieves the compiled search index for a specific model from S3.
|
152
|
+
*
|
153
|
+
* @param {Model.constructor} model - The model whose search index to retrieve.
|
154
|
+
* @returns {Promise<Object>} The compiled search index.
|
155
|
+
*/
|
84
156
|
static async getSearchIndexCompiled(model) {
|
85
|
-
return await this.
|
86
|
-
Key: [this.
|
87
|
-
Bucket: this.
|
157
|
+
return await this.configuration.client.send(new GetObjectCommand({
|
158
|
+
Key: [this.configuration.prefix, model.name, '_search_index.json'].join('/'),
|
159
|
+
Bucket: this.configuration.bucket,
|
88
160
|
})).then(data => data.Body.transformToString())
|
89
161
|
.then(JSON.parse);
|
90
162
|
}
|
91
163
|
|
164
|
+
/**
|
165
|
+
* Retrieves the raw (uncompiled) search index for a specific model from S3.
|
166
|
+
*
|
167
|
+
* @param {Model.constructor} model - The model whose raw search index to retrieve.
|
168
|
+
* @returns {Promise<Object>} The raw search index, or an empty object if not found.
|
169
|
+
*/
|
92
170
|
static async getSearchIndexRaw(model) {
|
93
|
-
return await this.
|
94
|
-
Key: [this.
|
95
|
-
Bucket: this.
|
171
|
+
return await this.configuration.client.send(new GetObjectCommand({
|
172
|
+
Key: [this.configuration.prefix, model.toString(), '_search_index_raw.json'].join('/'),
|
173
|
+
Bucket: this.configuration.bucket,
|
96
174
|
})).then(data => data.Body.transformToString())
|
97
175
|
.then(JSON.parse)
|
98
176
|
.catch(() => ({}));
|
99
177
|
}
|
100
178
|
|
179
|
+
/**
|
180
|
+
* Puts (uploads) a compiled search index for a specific model to S3.
|
181
|
+
*
|
182
|
+
* @param {Model.constructor} model - The model whose compiled search index to upload.
|
183
|
+
* @param {Object} compiledIndex - The compiled search index data.
|
184
|
+
* @returns {Promise<void>}
|
185
|
+
*
|
186
|
+
* @throws {FailedPutS3EngineError} Thrown if there is an error during the S3 PutObject operation.
|
187
|
+
*/
|
101
188
|
static async putSearchIndexCompiled(model, compiledIndex) {
|
102
|
-
const Key = [this.
|
189
|
+
const Key = [this.configuration.prefix, model.toString(), '_search_index.json'].join('/');
|
103
190
|
|
104
191
|
try {
|
105
|
-
await this.
|
192
|
+
await this.configuration.client.send(new PutObjectCommand({
|
106
193
|
Key,
|
107
194
|
Body: JSON.stringify(compiledIndex),
|
108
|
-
Bucket: this.
|
195
|
+
Bucket: this.configuration.bucket,
|
109
196
|
ContentType: 'application/json',
|
110
197
|
}));
|
111
198
|
} catch (error) {
|
112
|
-
throw new FailedPutS3EngineError(`Failed to put s3://${this.
|
199
|
+
throw new FailedPutS3EngineError(`Failed to put s3://${this.configuration.bucket}/${Key}`, error);
|
113
200
|
}
|
114
201
|
}
|
115
202
|
|
203
|
+
/**
|
204
|
+
* Puts (uploads) a raw search index for a specific model to S3.
|
205
|
+
*
|
206
|
+
* @param {Model.constructor} model - The model whose raw search index to upload.
|
207
|
+
* @param {Object} rawIndex - The raw search index data.
|
208
|
+
* @returns {Promise<void>}
|
209
|
+
*
|
210
|
+
* @throws {FailedPutS3EngineError} Thrown if there is an error during the S3 PutObject operation.
|
211
|
+
*/
|
116
212
|
static async putSearchIndexRaw(model, rawIndex) {
|
117
|
-
const Key = [this.
|
213
|
+
const Key = [this.configuration.prefix, model.toString(), '_search_index_raw.json'].join('/');
|
118
214
|
|
119
215
|
try {
|
120
|
-
await this.
|
216
|
+
await this.configuration.client.send(new PutObjectCommand({
|
121
217
|
Key,
|
122
218
|
Body: JSON.stringify(rawIndex),
|
123
|
-
Bucket: this.
|
219
|
+
Bucket: this.configuration.bucket,
|
124
220
|
ContentType: 'application/json',
|
125
221
|
}));
|
126
222
|
} catch (error) {
|
127
|
-
throw new FailedPutS3EngineError(`Failed to put s3://${this.
|
223
|
+
throw new FailedPutS3EngineError(`Failed to put s3://${this.configuration.bucket}/${Key}`, error);
|
128
224
|
}
|
129
225
|
}
|
130
226
|
}
|
227
|
+
|
228
|
+
export default S3Engine;
|
package/src/type/Model.js
CHANGED
@@ -5,10 +5,32 @@ import {monotonicFactory} from 'ulid';
|
|
5
5
|
|
6
6
|
const createID = monotonicFactory();
|
7
7
|
|
8
|
-
|
8
|
+
/**
|
9
|
+
* @class Model
|
10
|
+
*/
|
11
|
+
class Model {
|
12
|
+
/**
|
13
|
+
* Represents the model's ID field, defined as a required string.
|
14
|
+
*
|
15
|
+
* @type {StringType.required.constructor}
|
16
|
+
* @static
|
17
|
+
*/
|
9
18
|
static id = StringType.required;
|
19
|
+
|
20
|
+
/**
|
21
|
+
* Tracks whether the model is required in a schema.
|
22
|
+
*
|
23
|
+
* @type {boolean}
|
24
|
+
* @static
|
25
|
+
* @private
|
26
|
+
*/
|
10
27
|
static _required = false;
|
11
28
|
|
29
|
+
/**
|
30
|
+
* Creates a new instance of the model, initializing properties based on the provided data.
|
31
|
+
*
|
32
|
+
* @param {Object} [data={}] - The initial data to populate the model instance.
|
33
|
+
*/
|
12
34
|
constructor(data = {}) {
|
13
35
|
this.id = `${this.constructor.name}/${createID()}`;
|
14
36
|
|
@@ -26,7 +48,13 @@ export default class Model {
|
|
26
48
|
}
|
27
49
|
}
|
28
50
|
|
29
|
-
|
51
|
+
/**
|
52
|
+
* Serializes the model instance into an object, optionally retaining complex types.
|
53
|
+
*
|
54
|
+
* @param {boolean} [simple=true] - Determines whether to format the output using only JSON serialisable types.
|
55
|
+
* @returns {Object} - A serialized representation of the model.
|
56
|
+
*/
|
57
|
+
toData(simple = true) {
|
30
58
|
const model = {...this};
|
31
59
|
|
32
60
|
for (const [name, property] of Object.entries(this.constructor)) {
|
@@ -35,23 +63,70 @@ export default class Model {
|
|
35
63
|
}
|
36
64
|
}
|
37
65
|
|
38
|
-
return JSON.parse(
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
66
|
+
return JSON.parse(
|
67
|
+
JSON.stringify(model, (key, value) => {
|
68
|
+
if (key && this.constructor.isModel(value)) {
|
69
|
+
return {id: value.id};
|
70
|
+
}
|
71
|
+
return value;
|
72
|
+
}),
|
73
|
+
(key, value) => {
|
74
|
+
if (!simple) {
|
75
|
+
if (this.constructor[key]) {
|
76
|
+
if (this.constructor[key].name.endsWith('DateType')) {
|
77
|
+
return new Date(value);
|
78
|
+
}
|
79
|
+
|
80
|
+
if (this.constructor[key].name.endsWith('ArrayOf(Date)Type')) {
|
81
|
+
return value.map(d => new Date(d));
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
return value;
|
87
|
+
},
|
88
|
+
);
|
44
89
|
}
|
45
90
|
|
91
|
+
/**
|
92
|
+
* Validates the current model instance against the defined schema.
|
93
|
+
*
|
94
|
+
* @returns {boolean} - Returns `true` if validation succeeds.
|
95
|
+
* @throws {ValidationError} - Throws this error if validation fails.
|
96
|
+
*/
|
46
97
|
validate() {
|
47
98
|
return SchemaCompiler.compile(this.constructor).validate(this);
|
48
99
|
}
|
49
100
|
|
101
|
+
/**
|
102
|
+
* Extracts data from the model based on the indexed properties defined in the class.
|
103
|
+
*
|
104
|
+
* @returns {Object} - A representation of the model's indexed data.
|
105
|
+
*/
|
50
106
|
toIndexData() {
|
51
|
-
|
52
|
-
|
107
|
+
return this._extractData(this.constructor.indexedProperties());
|
108
|
+
}
|
109
|
+
|
110
|
+
/**
|
111
|
+
* Extracts data from the model based on the search properties defined in the class.
|
112
|
+
*
|
113
|
+
* @returns {Object} - A representation of the model's search data.
|
114
|
+
*/
|
115
|
+
toSearchData() {
|
116
|
+
return this._extractData(this.constructor.searchProperties());
|
117
|
+
}
|
53
118
|
|
54
|
-
|
119
|
+
/**
|
120
|
+
* Extracts specific data fields from the model based on a set of keys.
|
121
|
+
*
|
122
|
+
* @param {Array<string>} keys - The keys to extract from the model.
|
123
|
+
* @returns {Object} - The extracted data.
|
124
|
+
* @private
|
125
|
+
*/
|
126
|
+
_extractData(keys) {
|
127
|
+
const output = {id: this.id};
|
128
|
+
|
129
|
+
for (const key of keys) {
|
55
130
|
if (_.has(this, key)) {
|
56
131
|
_.set(output, key, _.get(this, key));
|
57
132
|
}
|
@@ -75,20 +150,22 @@ export default class Model {
|
|
75
150
|
return output;
|
76
151
|
}
|
77
152
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
return indexData;
|
86
|
-
}
|
87
|
-
|
153
|
+
/**
|
154
|
+
* Returns the name of the model as a string.
|
155
|
+
*
|
156
|
+
* @returns {string} - The name of the model class.
|
157
|
+
* @static
|
158
|
+
*/
|
88
159
|
static toString() {
|
89
|
-
return this
|
160
|
+
return this.name;
|
90
161
|
}
|
91
162
|
|
163
|
+
/**
|
164
|
+
* Returns a new required version of the current model class.
|
165
|
+
*
|
166
|
+
* @returns {this} - A required model subclass.
|
167
|
+
* @static
|
168
|
+
*/
|
92
169
|
static get required() {
|
93
170
|
class Required extends this {
|
94
171
|
static _required = true;
|
@@ -99,14 +176,35 @@ export default class Model {
|
|
99
176
|
return Required;
|
100
177
|
}
|
101
178
|
|
179
|
+
/**
|
180
|
+
* Returns a list of properties that are indexed.
|
181
|
+
*
|
182
|
+
* @returns {Array<string>} - The indexed properties.
|
183
|
+
* @abstract
|
184
|
+
* @static
|
185
|
+
*/
|
102
186
|
static indexedProperties() {
|
103
187
|
return [];
|
104
188
|
}
|
105
189
|
|
190
|
+
/**
|
191
|
+
* Returns a list of properties used for search.
|
192
|
+
*
|
193
|
+
* @returns {Array<string>} - The search properties.
|
194
|
+
* @abstract
|
195
|
+
* @static
|
196
|
+
*/
|
106
197
|
static searchProperties() {
|
107
198
|
return [];
|
108
199
|
}
|
109
200
|
|
201
|
+
/**
|
202
|
+
* Creates a model instance from raw data.
|
203
|
+
*
|
204
|
+
* @param {Object} data - The data to populate the model instance with.
|
205
|
+
* @returns {Model} - The populated model instance.
|
206
|
+
* @static
|
207
|
+
*/
|
110
208
|
static fromData(data) {
|
111
209
|
const model = new this();
|
112
210
|
|
@@ -129,6 +227,13 @@ export default class Model {
|
|
129
227
|
return model;
|
130
228
|
}
|
131
229
|
|
230
|
+
/**
|
231
|
+
* Determines if a given object is a model instance.
|
232
|
+
*
|
233
|
+
* @param {Object} possibleModel - The object to check.
|
234
|
+
* @returns {boolean} - Returns `true` if the object is a model instance.
|
235
|
+
* @static
|
236
|
+
*/
|
132
237
|
static isModel(possibleModel) {
|
133
238
|
return (
|
134
239
|
possibleModel?.prototype instanceof Model ||
|
@@ -136,9 +241,17 @@ export default class Model {
|
|
136
241
|
);
|
137
242
|
}
|
138
243
|
|
244
|
+
/**
|
245
|
+
* Determines if a given object is a dry model (a simplified object with an ID).
|
246
|
+
*
|
247
|
+
* @param {Object} possibleDryModel - The object to check.
|
248
|
+
* @returns {boolean} - Returns `true` if the object is a valid dry model.
|
249
|
+
* @static
|
250
|
+
*/
|
139
251
|
static isDryModel(possibleDryModel) {
|
140
252
|
try {
|
141
253
|
return (
|
254
|
+
!this.isModel(possibleDryModel) &&
|
142
255
|
Object.keys(possibleDryModel).includes('id') &&
|
143
256
|
!!possibleDryModel.id.match(/[A-Za-z]+\/[A-Z0-9]+/)
|
144
257
|
);
|
@@ -147,3 +260,5 @@ export default class Model {
|
|
147
260
|
}
|
148
261
|
}
|
149
262
|
}
|
263
|
+
|
264
|
+
export default Model;
|
package/src/type/Type.js
CHANGED
@@ -1,33 +1,67 @@
|
|
1
1
|
/**
|
2
|
+
* Base class for all data types.
|
3
|
+
*
|
4
|
+
* The `Type` class is a foundational class used to define various data types.
|
5
|
+
* It contains common properties and methods that are inherited by more specific types like strings, numbers, and booleans.
|
6
|
+
*
|
2
7
|
* @class Type
|
3
|
-
* @property {string} _type
|
4
|
-
* @property {boolean} _required
|
5
|
-
* @property {boolean} _resolved
|
6
|
-
* @property {map?} _properties
|
7
|
-
* @property {map?} _items
|
8
|
-
* @property {map?} _schema
|
9
8
|
*/
|
10
|
-
|
9
|
+
class Type {
|
10
|
+
/**
|
11
|
+
* @static
|
12
|
+
* @property {boolean} _required - Indicates if the type is required. Default is `false`.
|
13
|
+
*/
|
11
14
|
static _required = false;
|
15
|
+
|
16
|
+
/**
|
17
|
+
* @static
|
18
|
+
* @property {boolean} _resolved - Indicates if the type has been resolved. Default is `false`.
|
19
|
+
*/
|
12
20
|
static _resolved = false;
|
21
|
+
|
22
|
+
/**
|
23
|
+
* @static
|
24
|
+
* @property {*} _properties - Properties for defining schemas. Default is `undefined`.
|
25
|
+
*/
|
13
26
|
static _properties = undefined;
|
27
|
+
|
28
|
+
/**
|
29
|
+
* @static
|
30
|
+
* @property {*} _items - Represents items in array types or collections. Default is `undefined`.
|
31
|
+
*/
|
14
32
|
static _items = undefined;
|
33
|
+
|
34
|
+
/**
|
35
|
+
* @static
|
36
|
+
* @property {*} _schema - The schema definition for the type. Default is `undefined`.
|
37
|
+
*/
|
15
38
|
static _schema = undefined;
|
16
39
|
|
40
|
+
/**
|
41
|
+
* Converts the class name to a string, removing the "Type" suffix.
|
42
|
+
*
|
43
|
+
* @returns {string} The name of the type without the "Type" suffix.
|
44
|
+
*/
|
17
45
|
static toString() {
|
18
46
|
return this.name?.replace(/Type$/, '');
|
19
47
|
}
|
20
48
|
|
21
49
|
/**
|
22
|
-
*
|
50
|
+
* Returns a version of the type marked as required.
|
51
|
+
*
|
52
|
+
* @type {Type}
|
53
|
+
* @returns {Type} A subclass of the current type with `_required` set to `true`.
|
23
54
|
*/
|
24
55
|
static get required() {
|
25
56
|
class Required extends this {
|
26
57
|
static _required = true;
|
27
58
|
}
|
28
59
|
|
60
|
+
// Define the class name as "Required<OriginalTypeName>"
|
29
61
|
Object.defineProperty(Required, 'name', {value: `Required${this.toString()}Type`});
|
30
62
|
|
31
63
|
return Required;
|
32
64
|
}
|
33
65
|
}
|
66
|
+
|
67
|
+
export default Type;
|
@@ -1,19 +1,70 @@
|
|
1
1
|
import Type from '../Type.js';
|
2
2
|
|
3
|
-
|
3
|
+
/**
|
4
|
+
* Represents an array type definition, allowing the specification of an array of a certain type.
|
5
|
+
* This class is used to create type definitions for arrays that can be validated and used in schemas.
|
6
|
+
*
|
7
|
+
* @class ArrayType
|
8
|
+
*/
|
9
|
+
class ArrayType {
|
10
|
+
/**
|
11
|
+
* Creates a new type definition for an array of the specified type.
|
12
|
+
*
|
13
|
+
* The `of` method defines an array where the items must be of the specified type. It returns a
|
14
|
+
* class representing this array type, which can further be marked as required using the `required` getter.
|
15
|
+
*
|
16
|
+
* @param {Type} type - The type of the items that the array will contain.
|
17
|
+
* @returns {Type} A new class representing an array of the specified type.
|
18
|
+
*
|
19
|
+
* @example
|
20
|
+
* const arrayOfStrings = ArrayType.of(StringType);
|
21
|
+
* const requiredArrayOfNumbers = ArrayType.of(NumberType).required;
|
22
|
+
*/
|
4
23
|
static of(type) {
|
24
|
+
/**
|
25
|
+
* @class ArrayOf
|
26
|
+
* @extends Type
|
27
|
+
* Represents an array of a specific type.
|
28
|
+
*/
|
5
29
|
class ArrayOf extends Type {
|
30
|
+
/** @type {string} The data type, which is 'array' */
|
6
31
|
static _type = 'array';
|
32
|
+
|
33
|
+
/** @type {Type} The type of items contained in the array */
|
7
34
|
static _items = type;
|
8
35
|
|
36
|
+
/**
|
37
|
+
* Returns the string representation of the array type.
|
38
|
+
*
|
39
|
+
* @returns {string} The string representation of the array type.
|
40
|
+
*/
|
9
41
|
static toString() {
|
10
42
|
return `ArrayOf(${type.toString()})`;
|
11
43
|
}
|
12
44
|
|
45
|
+
/**
|
46
|
+
* Marks the array type as required.
|
47
|
+
*
|
48
|
+
* @returns {Type} A new class representing a required array of the specified type.
|
49
|
+
*
|
50
|
+
* @example
|
51
|
+
* const requiredArrayOfStrings = ArrayType.of(StringType).required;
|
52
|
+
*/
|
13
53
|
static get required() {
|
54
|
+
/**
|
55
|
+
* @class RequiredArrayOf
|
56
|
+
* @extends ArrayOf
|
57
|
+
* Represents a required array of a specific type.
|
58
|
+
*/
|
14
59
|
class Required extends this {
|
60
|
+
/** @type {boolean} Indicates that the array is required */
|
15
61
|
static _required = true;
|
16
62
|
|
63
|
+
/**
|
64
|
+
* Returns the string representation of the required array type.
|
65
|
+
*
|
66
|
+
* @returns {string} The string representation of the required array type.
|
67
|
+
*/
|
17
68
|
static toString() {
|
18
69
|
return `RequiredArrayOf(${type})`;
|
19
70
|
}
|
@@ -30,3 +81,5 @@ export default class ArrayType {
|
|
30
81
|
return ArrayOf;
|
31
82
|
}
|
32
83
|
}
|
84
|
+
|
85
|
+
export default ArrayType;
|