@acodeninja/persist 3.0.0-next.9 → 3.0.1-next.1
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/README.md +60 -4
- package/docs/code-quirks.md +14 -14
- package/docs/defining-models.md +61 -0
- package/docs/http.openapi.yml +138 -0
- package/docs/{model-property-types.md → model-properties.md} +76 -43
- package/docs/models-as-properties.md +46 -46
- package/docs/search-queries.md +11 -13
- package/docs/storage-engines.md +19 -35
- package/docs/structured-queries.md +59 -48
- package/docs/transactions.md +6 -7
- package/exports/storage/http.js +3 -0
- package/exports/storage/s3.js +3 -0
- package/jest.config.cjs +8 -12
- package/package.json +2 -2
- package/src/Connection.js +750 -0
- package/src/Persist.js +29 -30
- package/src/Schema.js +175 -0
- package/src/{Query.js → data/FindIndex.js} +40 -24
- package/src/{type → data}/Model.js +95 -55
- package/src/data/Property.js +21 -0
- package/src/data/SearchIndex.js +106 -0
- package/src/{type/complex → data/properties}/ArrayType.js +5 -3
- package/src/{type/simple → data/properties}/BooleanType.js +3 -3
- package/src/{type/complex → data/properties}/CustomType.js +5 -5
- package/src/{type/simple → data/properties}/DateType.js +4 -4
- package/src/{type/simple → data/properties}/NumberType.js +3 -3
- package/src/{type/resolved → data/properties}/ResolvedType.js +3 -2
- package/src/{type/resolved → data/properties}/SlugType.js +1 -1
- package/src/{type/simple → data/properties}/StringType.js +3 -3
- package/src/{type → data/properties}/Type.js +13 -3
- package/src/engine/storage/HTTPStorageEngine.js +149 -253
- package/src/engine/storage/S3StorageEngine.js +108 -195
- package/src/engine/storage/StorageEngine.js +131 -549
- package/exports/engine/storage/file.js +0 -3
- package/exports/engine/storage/http.js +0 -3
- package/exports/engine/storage/s3.js +0 -3
- package/src/SchemaCompiler.js +0 -196
- package/src/Transactions.js +0 -145
- package/src/engine/StorageEngine.js +0 -472
- package/src/engine/storage/FileStorageEngine.js +0 -213
- package/src/type/index.js +0 -32
@@ -0,0 +1,106 @@
|
|
1
|
+
import lunr from 'lunr';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Represents a single search result with the associated model instance and its relevance score.
|
5
|
+
*
|
6
|
+
* @class SearchResult
|
7
|
+
*/
|
8
|
+
export class SearchResult {
|
9
|
+
constructor(model, score) {
|
10
|
+
this.model = model;
|
11
|
+
this.score = score;
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
/**
|
16
|
+
* A full-text search index wrapper using Lunr.js for a given model.
|
17
|
+
* Supports indexing and querying model data.
|
18
|
+
*
|
19
|
+
* @class SearchIndex
|
20
|
+
*/
|
21
|
+
export default class SearchIndex {
|
22
|
+
#index;
|
23
|
+
#model;
|
24
|
+
#compiledIndex;
|
25
|
+
|
26
|
+
/**
|
27
|
+
* Initializes the search index for the provided model.
|
28
|
+
*
|
29
|
+
* @param {Model} model - The model definition to use for indexing.
|
30
|
+
* @param {Object.<string, Object>} index - A dictionary of model data, keyed by ID.
|
31
|
+
* @throws {NoIndexAvailableSearchIndexError} If the model has no searchable properties.
|
32
|
+
*/
|
33
|
+
constructor(model, index) {
|
34
|
+
this.#index = index;
|
35
|
+
this.#model = model;
|
36
|
+
if (model.searchProperties().length === 0) {
|
37
|
+
throw new NoIndexAvailableSearchIndexError(this.#model);
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
/**
|
42
|
+
* Performs a search query on the compiled Lunr index.
|
43
|
+
*
|
44
|
+
* @param {string} query - The search string.
|
45
|
+
* @return {Array<SearchResult>} An array of search results with model instances and scores.
|
46
|
+
*/
|
47
|
+
search(query) {
|
48
|
+
return this.searchIndex
|
49
|
+
.search(query)
|
50
|
+
.map(doc => new SearchResult(this.#model.fromData(this.#index[doc.ref]), doc.score));
|
51
|
+
}
|
52
|
+
|
53
|
+
/**
|
54
|
+
* Lazily compiles and returns the Lunr index instance.
|
55
|
+
*
|
56
|
+
* @return {lunr.Index} The compiled Lunr index.
|
57
|
+
*/
|
58
|
+
get searchIndex() {
|
59
|
+
return this.#compiledIndex ?? this.#compileIndex();
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* Compiles the Lunr index using the model's search properties.
|
64
|
+
*
|
65
|
+
* @return {lunr.Index} The compiled Lunr index.
|
66
|
+
* @private
|
67
|
+
*/
|
68
|
+
#compileIndex() {
|
69
|
+
const model = this.#model;
|
70
|
+
const index = this.#index;
|
71
|
+
this.#compiledIndex = lunr(function () {
|
72
|
+
this.ref('id');
|
73
|
+
|
74
|
+
for (const field of model.searchProperties()) {
|
75
|
+
this.field(field);
|
76
|
+
}
|
77
|
+
|
78
|
+
Object.values(index).forEach(function (doc) {
|
79
|
+
this.add(doc);
|
80
|
+
}, this);
|
81
|
+
});
|
82
|
+
|
83
|
+
return this.#compiledIndex;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
/**
|
88
|
+
* Base error class for search index-related exceptions.
|
89
|
+
*
|
90
|
+
* @class SearchIndexError
|
91
|
+
* @extends {Error}
|
92
|
+
*/
|
93
|
+
export class SearchIndexError extends Error {
|
94
|
+
}
|
95
|
+
|
96
|
+
/**
|
97
|
+
* Thrown when a model does not have any properties defined for indexing.
|
98
|
+
*
|
99
|
+
* @class NoIndexAvailableSearchIndexError
|
100
|
+
* @extends {SearchIndexError}
|
101
|
+
*/
|
102
|
+
export class NoIndexAvailableSearchIndexError extends SearchIndexError {
|
103
|
+
constructor(model) {
|
104
|
+
super(`The model ${model.name} has no search properties`);
|
105
|
+
}
|
106
|
+
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import Type from '
|
1
|
+
import Type from './Type.js';
|
2
2
|
|
3
3
|
/**
|
4
4
|
* Represents an array type definition, allowing the specification of an array of a certain type.
|
@@ -51,12 +51,14 @@ class ArrayType {
|
|
51
51
|
* const requiredArrayOfStrings = ArrayType.of(StringType).required;
|
52
52
|
*/
|
53
53
|
static get required() {
|
54
|
+
const ThisType = this;
|
55
|
+
|
54
56
|
/**
|
55
57
|
* @class RequiredArrayOf
|
56
58
|
* @extends ArrayOf
|
57
59
|
* Represents a required array of a specific type.
|
58
60
|
*/
|
59
|
-
class Required extends
|
61
|
+
class Required extends ThisType {
|
60
62
|
/** @type {boolean} Indicates that the array is required */
|
61
63
|
static _required = true;
|
62
64
|
|
@@ -70,7 +72,7 @@ class ArrayType {
|
|
70
72
|
}
|
71
73
|
}
|
72
74
|
|
73
|
-
Object.defineProperty(Required, 'name', {value: `Required${
|
75
|
+
Object.defineProperty(Required, 'name', {value: `Required${ThisType.name}`});
|
74
76
|
|
75
77
|
return Required;
|
76
78
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import Type from '
|
1
|
+
import Type from './Type.js';
|
2
2
|
|
3
3
|
/**
|
4
4
|
* Class representing a boolean type.
|
@@ -15,9 +15,9 @@ class BooleanType extends Type {
|
|
15
15
|
* @static
|
16
16
|
* @property {string} _type - The type identifier for BooleanType, set to `'boolean'`.
|
17
17
|
*/
|
18
|
-
|
18
|
+
BooleanType._type = 'boolean';
|
19
19
|
|
20
|
-
Object.defineProperty(
|
20
|
+
Object.defineProperty(BooleanType, 'name', {value: 'Boolean'});
|
21
21
|
}
|
22
22
|
}
|
23
23
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import Type from '
|
1
|
+
import Type from './Type.js';
|
2
2
|
import ajv from 'ajv';
|
3
3
|
|
4
4
|
/**
|
@@ -37,12 +37,12 @@ class CustomType {
|
|
37
37
|
class Custom extends Type {
|
38
38
|
static {
|
39
39
|
/** @type {string} The data type, which is 'object' */
|
40
|
-
|
40
|
+
Custom._type = 'object';
|
41
41
|
|
42
42
|
/** @type {Object} The JSON schema that defines the structure and validation rules */
|
43
|
-
|
43
|
+
Custom._schema = schema;
|
44
44
|
|
45
|
-
Object.defineProperty(
|
45
|
+
Object.defineProperty(Custom, 'name', {value: 'Custom'});
|
46
46
|
}
|
47
47
|
}
|
48
48
|
|
@@ -50,7 +50,7 @@ class CustomType {
|
|
50
50
|
}
|
51
51
|
|
52
52
|
static {
|
53
|
-
Object.defineProperty(
|
53
|
+
Object.defineProperty(CustomType, 'name', {value: 'Custom'});
|
54
54
|
}
|
55
55
|
}
|
56
56
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import Type from '
|
1
|
+
import Type from './Type.js';
|
2
2
|
|
3
3
|
/**
|
4
4
|
* Class representing a date type with ISO date-time format.
|
@@ -15,15 +15,15 @@ class DateType extends Type {
|
|
15
15
|
* @static
|
16
16
|
* @property {string} _type - The type identifier for DateType, set to `'string'`.
|
17
17
|
*/
|
18
|
-
|
18
|
+
DateType._type = 'string';
|
19
19
|
|
20
20
|
/**
|
21
21
|
* @static
|
22
22
|
* @property {string} _format - The format for DateType, set to `'iso-date-time'`.
|
23
23
|
*/
|
24
|
-
|
24
|
+
DateType._format = 'iso-date-time';
|
25
25
|
|
26
|
-
Object.defineProperty(
|
26
|
+
Object.defineProperty(DateType, 'name', {value: 'Date'});
|
27
27
|
}
|
28
28
|
|
29
29
|
/**
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import Type from '
|
1
|
+
import Type from './Type.js';
|
2
2
|
|
3
3
|
/**
|
4
4
|
* Class representing a number type.
|
@@ -15,9 +15,9 @@ class NumberType extends Type {
|
|
15
15
|
* @static
|
16
16
|
* @property {string} _type - The type identifier for NumberType, set to `'number'`.
|
17
17
|
*/
|
18
|
-
|
18
|
+
NumberType._type = 'number';
|
19
19
|
|
20
|
-
Object.defineProperty(
|
20
|
+
Object.defineProperty(NumberType, 'name', {value: 'Number'});
|
21
21
|
}
|
22
22
|
}
|
23
23
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import Type from '
|
1
|
+
import Type from './Type.js';
|
2
2
|
|
3
3
|
/**
|
4
4
|
* Class representing a resolved type.
|
@@ -39,6 +39,7 @@ class ResolvedType extends Type {
|
|
39
39
|
* @returns {ResolvedType} A subclass of `ResolvedType` customized for the provided property.
|
40
40
|
*/
|
41
41
|
static of(property) {
|
42
|
+
const that = this;
|
42
43
|
class ResolvedTypeOf extends ResolvedType {
|
43
44
|
/**
|
44
45
|
* Converts the resolved type to a string, displaying the resolved property.
|
@@ -46,7 +47,7 @@ class ResolvedType extends Type {
|
|
46
47
|
* @returns {string} A string representing the resolved type, including the property.
|
47
48
|
*/
|
48
49
|
static toString() {
|
49
|
-
return
|
50
|
+
return `${that.toString()}Of(${property})`;
|
50
51
|
}
|
51
52
|
}
|
52
53
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import Type from '
|
1
|
+
import Type from './Type.js';
|
2
2
|
|
3
3
|
/**
|
4
4
|
* Class representing a string type.
|
@@ -15,9 +15,9 @@ class StringType extends Type {
|
|
15
15
|
* @static
|
16
16
|
* @property {string} _type - The type identifier for the string type.
|
17
17
|
*/
|
18
|
-
|
18
|
+
StringType._type = 'string';
|
19
19
|
|
20
|
-
Object.defineProperty(
|
20
|
+
Object.defineProperty(StringType, 'name', {value: 'String'});
|
21
21
|
}
|
22
22
|
}
|
23
23
|
|
@@ -53,18 +53,28 @@ class Type {
|
|
53
53
|
* @returns {Type} A subclass of the current type with `_required` set to `true`.
|
54
54
|
*/
|
55
55
|
static get required() {
|
56
|
-
|
56
|
+
const ThisType = this;
|
57
|
+
|
58
|
+
/**
|
59
|
+
* A subclass of the current type with the `_required` flag set to `true`.
|
60
|
+
* Used to indicate that the property is required during validation or schema generation.
|
61
|
+
*
|
62
|
+
* @class
|
63
|
+
* @extends {Type}
|
64
|
+
* @private
|
65
|
+
*/
|
66
|
+
class Required extends ThisType {
|
57
67
|
static _required = true;
|
58
68
|
}
|
59
69
|
|
60
70
|
// Define the class name as "Required<OriginalTypeName>"
|
61
|
-
Object.defineProperty(Required, 'name', {value: `Required${
|
71
|
+
Object.defineProperty(Required, 'name', {value: `Required${ThisType.name}`});
|
62
72
|
|
63
73
|
return Required;
|
64
74
|
}
|
65
75
|
|
66
76
|
static {
|
67
|
-
Object.defineProperty(
|
77
|
+
Object.defineProperty(Type, 'name', {value: 'Type'});
|
68
78
|
}
|
69
79
|
}
|
70
80
|
|