@jwerre/vellum 1.1.1 → 1.3.0-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 +6 -0
- package/dist/Collection.svelte.d.ts +60 -0
- package/dist/Collection.svelte.js +63 -0
- package/dist/Model.svelte.d.ts +38 -0
- package/dist/Model.svelte.js +65 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -243,6 +243,7 @@ There is a working example of Vellum in the `routes` directory. To run it, clone
|
|
|
243
243
|
- [add](#add)
|
|
244
244
|
- [Parameters](#parameters-11)
|
|
245
245
|
- [Examples](#examples-17)
|
|
246
|
+
- [sort](#sort)
|
|
246
247
|
- [reset](#reset)
|
|
247
248
|
- [Parameters](#parameters-12)
|
|
248
249
|
- [Examples](#examples-18)
|
|
@@ -863,6 +864,11 @@ collection.add(existingUser);
|
|
|
863
864
|
|
|
864
865
|
Returns **any** The model instance that was added to the collection
|
|
865
866
|
|
|
867
|
+
#### sort
|
|
868
|
+
|
|
869
|
+
Sorts the collection using the comparator if one is defined.
|
|
870
|
+
Called automatically when items are added to the collection.
|
|
871
|
+
|
|
866
872
|
#### reset
|
|
867
873
|
|
|
868
874
|
Resets the collection with new data, replacing all existing items.
|
|
@@ -33,6 +33,46 @@ export declare abstract class Collection<M extends Model<T>, T extends object> {
|
|
|
33
33
|
};
|
|
34
34
|
/** Returns the API endpoint URL for this collection */
|
|
35
35
|
abstract endpoint(): string;
|
|
36
|
+
/**
|
|
37
|
+
* Optional comparator for sorting the collection.
|
|
38
|
+
*
|
|
39
|
+
* By default, there is no comparator for a collection. If you define a comparator,
|
|
40
|
+
* it will be used to sort the collection any time a model is added.
|
|
41
|
+
*
|
|
42
|
+
* A comparator can be defined in three ways:
|
|
43
|
+
*
|
|
44
|
+
* 1. **sortBy** - Pass a function that takes a single model argument and returns
|
|
45
|
+
* a numeric or string value by which the model should be ordered relative to others.
|
|
46
|
+
*
|
|
47
|
+
* 2. **sort** - Pass a comparator function that takes two model arguments and returns
|
|
48
|
+
* -1 if the first model should come before the second, 0 if they are of the same
|
|
49
|
+
* rank, and 1 if the first model should come after.
|
|
50
|
+
*
|
|
51
|
+
* 3. **attribute name** - Pass a string indicating the attribute to sort by.
|
|
52
|
+
*
|
|
53
|
+
* Note: The implementation depends on the arity of your comparator function to
|
|
54
|
+
* determine between sortBy (1 argument) and sort (2 arguments) styles, so be
|
|
55
|
+
* careful if your comparator function is bound.
|
|
56
|
+
*
|
|
57
|
+
* @returns A comparator function, string attribute name, or undefined for no sorting
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* // Sort by attribute name
|
|
61
|
+
* comparator = () => 'createdAt';
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* // Sort using sortBy (single argument)
|
|
65
|
+
* comparator = () => (model: UserModel) => model.get('age');
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* // Sort using sort comparator (two arguments)
|
|
69
|
+
* comparator = () => (a: UserModel, b: UserModel) => {
|
|
70
|
+
* if (a.get('priority') < b.get('priority')) return -1;
|
|
71
|
+
* if (a.get('priority') > b.get('priority')) return 1;
|
|
72
|
+
* return 0;
|
|
73
|
+
* };
|
|
74
|
+
*/
|
|
75
|
+
comparator?(): string | ((model: M) => string | number) | ((a: M, b: M) => number) | undefined;
|
|
36
76
|
/**
|
|
37
77
|
* Creates a new Collection instance.
|
|
38
78
|
*
|
|
@@ -66,6 +106,26 @@ export declare abstract class Collection<M extends Model<T>, T extends object> {
|
|
|
66
106
|
* collection.add(existingUser);
|
|
67
107
|
*/
|
|
68
108
|
add(data: T | M): M;
|
|
109
|
+
/**
|
|
110
|
+
* Sorts the collection using the comparator if one is defined.
|
|
111
|
+
*
|
|
112
|
+
* This method is called automatically when items are added to the collection via `add()` or `reset()`.
|
|
113
|
+
* You can also call it manually to re-sort the collection after modifying model attributes.
|
|
114
|
+
*
|
|
115
|
+
* The sorting behavior depends on the type of comparator defined:
|
|
116
|
+
*
|
|
117
|
+
* - **String attribute**: Sorts by the specified model attribute in ascending order
|
|
118
|
+
* - **sortBy function** (1 argument): Sorts by the return value of the function in ascending order
|
|
119
|
+
* - **sort function** (2 arguments): Uses a custom comparator that returns -1, 0, or 1
|
|
120
|
+
*
|
|
121
|
+
* If no comparator is defined or the comparator returns undefined, no sorting is performed.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* // Manual sorting after updating a model
|
|
125
|
+
* user.set('priority', 5);
|
|
126
|
+
* collection.sort();
|
|
127
|
+
*/
|
|
128
|
+
sort(): void;
|
|
69
129
|
/**
|
|
70
130
|
* Resets the collection with new data, replacing all existing items.
|
|
71
131
|
*
|
|
@@ -65,8 +65,70 @@ export class Collection {
|
|
|
65
65
|
add(data) {
|
|
66
66
|
const instance = data instanceof Model ? data : new this.model(data);
|
|
67
67
|
this.items.push(instance);
|
|
68
|
+
this.sort();
|
|
68
69
|
return instance;
|
|
69
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Sorts the collection using the comparator if one is defined.
|
|
73
|
+
*
|
|
74
|
+
* This method is called automatically when items are added to the collection via `add()` or `reset()`.
|
|
75
|
+
* You can also call it manually to re-sort the collection after modifying model attributes.
|
|
76
|
+
*
|
|
77
|
+
* The sorting behavior depends on the type of comparator defined:
|
|
78
|
+
*
|
|
79
|
+
* - **String attribute**: Sorts by the specified model attribute in ascending order
|
|
80
|
+
* - **sortBy function** (1 argument): Sorts by the return value of the function in ascending order
|
|
81
|
+
* - **sort function** (2 arguments): Uses a custom comparator that returns -1, 0, or 1
|
|
82
|
+
*
|
|
83
|
+
* If no comparator is defined or the comparator returns undefined, no sorting is performed.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* // Manual sorting after updating a model
|
|
87
|
+
* user.set('priority', 5);
|
|
88
|
+
* collection.sort();
|
|
89
|
+
*/
|
|
90
|
+
sort() {
|
|
91
|
+
if (!this.comparator) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const comparator = this.comparator();
|
|
95
|
+
if (!comparator) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// String attribute name
|
|
99
|
+
if (typeof comparator === 'string') {
|
|
100
|
+
const attr = comparator;
|
|
101
|
+
this.items.sort((a, b) => {
|
|
102
|
+
const aVal = a.get(attr);
|
|
103
|
+
const bVal = b.get(attr);
|
|
104
|
+
if (aVal < bVal)
|
|
105
|
+
return -1;
|
|
106
|
+
if (aVal > bVal)
|
|
107
|
+
return 1;
|
|
108
|
+
return 0;
|
|
109
|
+
});
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
// Function comparator - check arity
|
|
113
|
+
if (comparator.length === 1) {
|
|
114
|
+
// sortBy function (single argument)
|
|
115
|
+
const sortByFn = comparator;
|
|
116
|
+
this.items.sort((a, b) => {
|
|
117
|
+
const aVal = sortByFn(a);
|
|
118
|
+
const bVal = sortByFn(b);
|
|
119
|
+
if (aVal < bVal)
|
|
120
|
+
return -1;
|
|
121
|
+
if (aVal > bVal)
|
|
122
|
+
return 1;
|
|
123
|
+
return 0;
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
// sort function (two arguments)
|
|
128
|
+
const sortFn = comparator;
|
|
129
|
+
this.items.sort(sortFn);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
70
132
|
/**
|
|
71
133
|
* Resets the collection with new data, replacing all existing items.
|
|
72
134
|
*
|
|
@@ -81,6 +143,7 @@ export class Collection {
|
|
|
81
143
|
*/
|
|
82
144
|
reset(data) {
|
|
83
145
|
this.items = data.map((attrs) => new this.model(attrs));
|
|
146
|
+
this.sort();
|
|
84
147
|
}
|
|
85
148
|
/**
|
|
86
149
|
* Finds the first item in the collection that matches the given query.
|
package/dist/Model.svelte.d.ts
CHANGED
|
@@ -106,6 +106,44 @@ export declare abstract class Model<T extends object> {
|
|
|
106
106
|
* @returns {ValidationError || undefined} An instance of ValidationError if validation failed, otherwise undefined
|
|
107
107
|
*/
|
|
108
108
|
get validationError(): ValidationError | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* Gets the hash of attributes that have changed since the last set call.
|
|
111
|
+
* This is a readonly accessor - the changed object cannot be modified directly.
|
|
112
|
+
*
|
|
113
|
+
* @returns {Partial<T>} An object containing all attributes that have changed
|
|
114
|
+
*/
|
|
115
|
+
get changed(): Partial<T>;
|
|
116
|
+
/**
|
|
117
|
+
* Gets the hash of previous attribute values before they were changed.
|
|
118
|
+
* This is a readonly accessor - the previous object cannot be modified directly.
|
|
119
|
+
*
|
|
120
|
+
* @returns {Partial<T>} An object containing the previous values of changed attributes
|
|
121
|
+
*/
|
|
122
|
+
get previous(): Partial<T>;
|
|
123
|
+
/**
|
|
124
|
+
* Determines if attributes have changed since the last set call.
|
|
125
|
+
*
|
|
126
|
+
* This method checks whether any attributes were modified in the most recent
|
|
127
|
+
* set operation. When called without arguments, it returns true if any attributes
|
|
128
|
+
* have changed. When called with a specific attribute key, it returns true only
|
|
129
|
+
* if that particular attribute was changed.
|
|
130
|
+
*
|
|
131
|
+
* @param {keyof T} [attr] - Optional attribute key to check for changes
|
|
132
|
+
* @returns {boolean} True if attributes have changed, false otherwise
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* // Check if any attributes changed
|
|
136
|
+
* const user = new User({ name: 'John', email: 'john@example.com' });
|
|
137
|
+
* user.set('name', 'Jane');
|
|
138
|
+
* user.hasChanged(); // Returns true
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* // Check if a specific attribute changed
|
|
142
|
+
* user.set('name', 'Jane');
|
|
143
|
+
* user.hasChanged('name'); // Returns true
|
|
144
|
+
* user.hasChanged('email'); // Returns false
|
|
145
|
+
*/
|
|
146
|
+
hasChanged(attr?: keyof T): boolean;
|
|
109
147
|
/**
|
|
110
148
|
* Provides default attribute values for new model instances.
|
|
111
149
|
*
|
package/dist/Model.svelte.js
CHANGED
|
@@ -52,6 +52,16 @@ export class Model {
|
|
|
52
52
|
* This property contains the error returned by the validate method.
|
|
53
53
|
*/
|
|
54
54
|
#validationError = $state();
|
|
55
|
+
/**
|
|
56
|
+
* Internal hash containing all attributes that have changed since the last set call.
|
|
57
|
+
* This property tracks which attributes have been modified and their new values.
|
|
58
|
+
*/
|
|
59
|
+
#changed = {};
|
|
60
|
+
/**
|
|
61
|
+
* Internal hash containing the previous values of attributes before they were changed.
|
|
62
|
+
* This property stores the original values of attributes from before the last set call.
|
|
63
|
+
*/
|
|
64
|
+
#previous = {};
|
|
55
65
|
/**
|
|
56
66
|
* The name of the attribute that serves as the unique identifier for this model instance.
|
|
57
67
|
*
|
|
@@ -92,6 +102,53 @@ export class Model {
|
|
|
92
102
|
get validationError() {
|
|
93
103
|
return this.#validationError;
|
|
94
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Gets the hash of attributes that have changed since the last set call.
|
|
107
|
+
* This is a readonly accessor - the changed object cannot be modified directly.
|
|
108
|
+
*
|
|
109
|
+
* @returns {Partial<T>} An object containing all attributes that have changed
|
|
110
|
+
*/
|
|
111
|
+
get changed() {
|
|
112
|
+
return this.#changed;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Gets the hash of previous attribute values before they were changed.
|
|
116
|
+
* This is a readonly accessor - the previous object cannot be modified directly.
|
|
117
|
+
*
|
|
118
|
+
* @returns {Partial<T>} An object containing the previous values of changed attributes
|
|
119
|
+
*/
|
|
120
|
+
get previous() {
|
|
121
|
+
return this.#previous;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Determines if attributes have changed since the last set call.
|
|
125
|
+
*
|
|
126
|
+
* This method checks whether any attributes were modified in the most recent
|
|
127
|
+
* set operation. When called without arguments, it returns true if any attributes
|
|
128
|
+
* have changed. When called with a specific attribute key, it returns true only
|
|
129
|
+
* if that particular attribute was changed.
|
|
130
|
+
*
|
|
131
|
+
* @param {keyof T} [attr] - Optional attribute key to check for changes
|
|
132
|
+
* @returns {boolean} True if attributes have changed, false otherwise
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* // Check if any attributes changed
|
|
136
|
+
* const user = new User({ name: 'John', email: 'john@example.com' });
|
|
137
|
+
* user.set('name', 'Jane');
|
|
138
|
+
* user.hasChanged(); // Returns true
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* // Check if a specific attribute changed
|
|
142
|
+
* user.set('name', 'Jane');
|
|
143
|
+
* user.hasChanged('name'); // Returns true
|
|
144
|
+
* user.hasChanged('email'); // Returns false
|
|
145
|
+
*/
|
|
146
|
+
hasChanged(attr) {
|
|
147
|
+
if (attr !== undefined) {
|
|
148
|
+
return attr in this.#changed;
|
|
149
|
+
}
|
|
150
|
+
return Object.keys(this.#changed).length > 0;
|
|
151
|
+
}
|
|
95
152
|
/**
|
|
96
153
|
* Provides default attribute values for new model instances.
|
|
97
154
|
*
|
|
@@ -158,6 +215,14 @@ export class Model {
|
|
|
158
215
|
if (opts?.validate && !this.#doValidation({ ...this.#attributes, ...attrs }, opts)) {
|
|
159
216
|
return false;
|
|
160
217
|
}
|
|
218
|
+
// Store previous values and record new changes
|
|
219
|
+
this.#previous = {};
|
|
220
|
+
for (const key in attrs) {
|
|
221
|
+
if (key in this.#attributes) {
|
|
222
|
+
this.#previous[key] = this.#attributes[key];
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
this.#changed = attrs;
|
|
161
226
|
Object.assign(this.#attributes, attrs);
|
|
162
227
|
return true;
|
|
163
228
|
}
|