Skip to content

Commit cc8753e

Browse files
authored
feat 0.13.0 (#279)
## Refactor * refactor(timestamps): moved existence check to HasTimestamps class * refactor(events): simplified method signatures * refactor(model)!: renamed `create` to `make` * This name hints the behaviour somewhat clearer than before. Previously it might have suggested that some persistence was involved. * refactor(events): removed redundant union type * refactor: move fetch mock file ## Chore * chore: increment version * chore: eslint changes * chore(deps-dev): updated ts eslint ## Fix * fix: allow any values within `handleError` * Some errors may be handled here and recovered from by returning something. Or perhaps an error is expected and no throwing is necessary. * fix(events): added missing listener signature to `has` method * fix(collection): fixed typing issue after typescript update ## Documentation * docs: doc page linking, grammar and typo fixes * docs(collection): fixed typo * docs: add internal inline comments to testing ## Testing * test: updated jest ## Feature * feat(collection): improved `pluck` return type * feat(helpers): add `dataGet` function ## Performance * perf(collection): shortcut return when 0 given as argument
1 parent e3a57ec commit cc8753e

48 files changed

Lines changed: 3530 additions & 7007 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<p align="center">
2-
<img width="400" src="https://raw.githubusercontent.com/upfrontjs/design/main/upfrontjs.png">
2+
<img alt="UpfrontJs logo" width="400" src="https://raw.githubusercontent.com/upfrontjs/design/main/upfrontjs.png">
33
</p>
44

55
![GitHub release (latest SemVer including pre-releases)](https://img.shields.io/github/v/release/upfrontjs/framework?color=%233ac200&include_prereleases&label=latest%20version&sort=semver&style=flat-square)

docs/calliope/api-calls.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ This method should only really be used when mocking the model to look like it ex
163163
```js
164164
import User from '@Models/User';
165165

166-
const user = User.create({ id: 1 });
166+
const user = User.make({ id: 1 });
167167
user.exists; // false
168168
user.setLastSyncedAt().exists; // true
169169
```

docs/calliope/attributes.md

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ This in action will look like:
182182
```js
183183
import User from '@Models/User';
184184

185-
const user = User.create({ someAttribute: 1, name: 'name' });
185+
const user = User.make({ someAttribute: 1, name: 'name' });
186186
user.getAttributes(); // { name: 'name' }
187187
```
188188

@@ -318,7 +318,7 @@ After you have defined your accessors and mutators they'll be automatically call
318318
```js
319319
import User from '@Models/User';
320320

321-
const user = User.create({ title: 'Dr.', fullName: 'John Doe' });
321+
const user = User.make({ title: 'Dr.', fullName: 'John Doe' });
322322
user.fullName; // 'Dr. John Doe'
323323
```
324324

@@ -373,7 +373,7 @@ Just like object literals, models are also iterable using a for of loop. This lo
373373
import User from '@Models/User';
374374
import Shift from '@Models/Shift';
375375

376-
const user = User.create({ title: 'Dr.', shifts: [new Shift] });
376+
const user = User.make({ title: 'Dr.', shifts: [new Shift] });
377377

378378
for (const [item, key] of user) {
379379
// ...
@@ -407,7 +407,7 @@ The `getAttribute` method is what's used for getting attributes from the model.
407407
```js
408408
import User from '@Models/User';
409409

410-
const user = User.create({ name: 'John Doe' });
410+
const user = User.make({ name: 'John Doe' });
411411
user.name; // 'John Doe'
412412
user.getAttribute('name'); // 'John Doe'
413413
```
@@ -429,13 +429,13 @@ The `getAttributes` method returns all the attributes that has been set in an ob
429429
```js
430430
import User from '@Models/User';
431431

432-
const user = User.create({ firstName: 'John', lastName: 'Doe' });
432+
const user = User.make({ firstName: 'John', lastName: 'Doe' });
433433
user.getAttributes(); // { firstName: 'John', lastName: 'Doe' }
434434
```
435435

436436
#### getRawAttributes
437437

438-
The `getRawAttributes` method returns all the attributes similarly to [getAttributes](#getattributes) except is does not use the any value transformation.
438+
The `getRawAttributes` method returns all the attributes similarly to [getAttributes](#getattributes) except is does not use any value transformation.
439439

440440
#### getAttributeKeys
441441

@@ -444,7 +444,7 @@ The `getAttributeKeys` method returns all the attribute keys on the model curren
444444
```js
445445
import User from '@Models/User';
446446

447-
const user = User.create({ firstName: 'John', lastName: 'Doe' });
447+
const user = User.make({ firstName: 'John', lastName: 'Doe' });
448448
user.getAttributeKeys(); // ['firstName', 'lastName']
449449
```
450450

@@ -466,7 +466,7 @@ export default class User extends Model {
466466
import User from '@Models/User';
467467
import Shift from '@Models/Shift';
468468

469-
const user = User.create({ firstName: 'John', lastName: 'Doe' });
469+
const user = User.make({ firstName: 'John', lastName: 'Doe' });
470470
user.property = 1;
471471
user.addRelation('shifts', [new Shift]);
472472

@@ -483,7 +483,7 @@ The `fill` method merges in the given attributes onto the model that are conside
483483
```js
484484
import User from '@Models/User';
485485

486-
const user = User.create({ firstName: 'John', lastName: 'Doe' });
486+
const user = User.make({ firstName: 'John', lastName: 'Doe' });
487487
user.fill({ fistName: 'Jane', title: 'Dr.' }).getAttributes(); // { firstName: 'Jane', lastName: 'Doe', title: 'Dr. }
488488
```
489489

@@ -498,7 +498,7 @@ The `only` method returns only the attributes that match the given key(s).
498498
```js
499499
import User from '@Models/User';
500500

501-
const user = User.create({ firstName: 'John', lastName: 'Doe' });
501+
const user = User.make({ firstName: 'John', lastName: 'Doe' });
502502
user.only('fistName'); // { firstName: 'John' }
503503
```
504504
#### except
@@ -508,7 +508,7 @@ The `except` method returns only the attributes that match does not the given ke
508508
```js
509509
import User from '@Models/User';
510510

511-
const user = User.create({ firstName: 'John', lastName: 'Doe', title: 'Dr.' });
511+
const user = User.make({ firstName: 'John', lastName: 'Doe', title: 'Dr.' });
512512
user.except(['fistName', 'title']); // { lastName: 'Doe' }
513513
```
514514

@@ -519,7 +519,7 @@ The `toJSON` method returns the json representation of the model's attributes an
519519
```js
520520
import User from '@Models/User';
521521

522-
const user = User.create({ name: 'John Doe' });
522+
const user = User.make({ name: 'John Doe' });
523523
user.addRelation('shifts', new Shift({ shiftAttr: 1 })).toJSON(); // {"name":"John Doe","shifts":[{"shiftAttr":1}]}
524524
```
525525

@@ -533,7 +533,7 @@ The `syncOriginal` method set's the original state of the data to the current st
533533
```js
534534
import User from '@Models/User';
535535

536-
const user = User.create({ name: 'John Doe' });
536+
const user = User.make({ name: 'John Doe' });
537537
user.name = 'Jane Doe';
538538
user.getOriginal('name'); // 'John Doe'
539539
user.syncOriginal().getOriginal('name'); // 'Jane Doe'
@@ -546,19 +546,19 @@ The `reset` method will set the attributes to the original values, discarding an
546546
```js
547547
import User from '@Models/User';
548548

549-
const user = User.create({ name: 'John Doe' });
549+
const user = User.make({ name: 'John Doe' });
550550
user.name = 'new name';
551551
user.getChanges(); // { name: 'new name' }
552552
user.reset().getChanges(); // {}
553553
```
554554

555555
#### getOriginal
556556

557-
The `getOriginal` method returns the original value in a resolved format. Meaning it will use the [accessor](#mutatorsaccessors) if defined or it will [cast](#casting) the value if cast defined. The method optionally takes a second argument which the method will default to if the key is not found.
557+
The `getOriginal` method returns the original value in a resolved format. Meaning it will use the [accessor](#mutatorsaccessors) if defined, or it will [cast](#casting) the value if cast defined. The method optionally takes a second argument which the method will default to if the key is not found.
558558
```js
559559
import User from '@Models/User';
560560

561-
const user = User.create({ name: 'John Doe' });
561+
const user = User.make({ name: 'John Doe' });
562562
user.name = 'Jane Doe';
563563
user.getOriginal('name'); // 'John Doe'
564564
user.getOriginal('title', 'Mr.'); // 'Mr.'
@@ -574,7 +574,7 @@ The `getChanges` method returns only the changed data since the model was constr
574574
```js
575575
import User from '@Models/User';
576576

577-
const user = User.create({ name: 'John Doe', title: 'Mr.' });
577+
const user = User.make({ name: 'John Doe', title: 'Mr.' });
578578
user.getChanges(); // {}
579579
user.name = 'Jane Doe';
580580
user.getChanges(); // { name: 'Jane Doe' }
@@ -589,7 +589,7 @@ The `getDeletedAttributes` method returns only the deleted attributes since the
589589
```js
590590
import User from '@Models/User';
591591

592-
const user = User.create({ name: 'John Doe', title: 'Mr.' });
592+
const user = User.make({ name: 'John Doe', title: 'Mr.' });
593593
user.getDeletedAttributes(); // {}
594594
user.deleteAttribute('name').getDeletedAttributes(); // { name: 'John Doe' }
595595
user.deleteAttribute('title').getDeletedAttributes('name'); // { name: 'John Doe' }
@@ -602,7 +602,7 @@ The `getNewAttributes` method returns only the newly added attributes since the
602602
```js
603603
import User from '@Models/User';
604604

605-
const user = User.create({ name: 'John Doe', title: 'Mr.' });
605+
const user = User.make({ name: 'John Doe', title: 'Mr.' });
606606
user.getNewAttributes(); // {}
607607
user.setAttribute('attr', 1).getNewAttributes(); // { attr: 1 }
608608
user.setAttribute('attr2', 2).getNewAttributes('attr'); // { attr: 1 }
@@ -614,7 +614,7 @@ The `hasChanges` method determines whether any changes have occurred since const
614614
```js
615615
import User from '@Models/User';
616616

617-
const user = User.create({ name: 'John Doe', title: 'Mr.' });
617+
const user = User.make({ name: 'John Doe', title: 'Mr.' });
618618
user.hasChanges(); // false
619619
user.name = 'Jane Doe';
620620
user.hasChanges(); // true
@@ -631,11 +631,11 @@ The `isDirty` method is an alias of the [hasChanges](#haschanges) method.
631631

632632
#### isClean
633633

634-
The `isClean` method determines whether the attributes matches with the original attributes since the model constructing. Optionally it can take a key argument in which case it only inspect the given attribute's state.
634+
The `isClean` method determines whether the attributes match with the original attributes since the model constructing. Optionally it can take a key argument in which case it only inspect the given attribute's state.
635635
```js
636636
import User from '@Models/User';
637637

638-
const user = User.create({ name: 'John Doe', title: 'Mr.' });
638+
const user = User.make({ name: 'John Doe', title: 'Mr.' });
639639
user.isClean(); // true
640640
user.name = 'Jane Doe';
641641
user.isClean(); // false

docs/calliope/model-collection.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Model Collection
22

3-
ModelCollection is a sub class of the [Collection](../helpers/collection.md), therefore all methods are inherited. The following methods have been updated to use either the model's [is](./readme.md#is) method, or the [primary key](./readme.md#getkey) of the model for comparison between models. `unique`, `hasDuplicates`, `duplicates`, `diff`, `only`, `except`, `intersect`, `delete`, `union`, `includes`. The signature of the before mentioned methods has not changed. In addition, the ModelCollection ensures that only [Models](./readme.md) are included in the collection. On top of the collection's methods couple of others has been added that are only relevant to model values.
3+
ModelCollection is a subclass of the [Collection](../helpers/collection.md), therefore all methods are inherited. The following methods have been updated to use either the model's [is](./readme.md#is) method, or the [primary key](./readme.md#getkey) of the model for comparison between models. `unique`, `hasDuplicates`, `duplicates`, `diff`, `only`, `except`, `intersect`, `delete`, `union`, `includes`. The signature of the before mentioned methods has not changed. In addition, the ModelCollection ensures that only [Models](./readme.md) are included in the collection. On top of the collection's methods couple of others has been added that are only relevant to model values.
44

55
## Methods
66

docs/calliope/query-building.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ User.orderBy('column', 'desc');
338338

339339
#### orderByDesc
340340

341-
The `orderByDesc` method indicates to the backend to order the returned records by the given column in a descending order.
341+
The `orderByDesc` method indicates to the backend to order the returned records by the given column in descending order.
342342

343343
```js
344344
import User from '@Models/User';

docs/calliope/readme.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import User from '@Models/User';
5151

5252
User.find(1);
5353
// or
54-
User.create({ my: attributes });
54+
User.make({ my: attributes });
5555
// etc...
5656
```
5757

@@ -97,7 +97,7 @@ export default class User extends Model {
9797
#### keyType
9898

9999
The `keyType` is a getter that identifies what the type is of your [primaryKey](#primarykey). Its value has to be either `'string'` or `'number'` with `'number'` being the default value.
100-
You should update this value to `'string'` if you're using a uuid or some custom string for the primary key as this is used when in the [Factory](../testing.md#factories) and [exists](#exists) logic.
100+
You should update this value to `'string'` if you're using a UUID or some custom string for the primary key as this is used when in the [Factory](../testing/readme.md#factories) and [exists](#exists) logic.
101101

102102
```js
103103
// User.ts
@@ -128,9 +128,9 @@ The `is` method compares the given model with the current model based on the [ge
128128
import User from '@Models/User';
129129
import Shift from '@Models/Shift';
130130

131-
const user = User.create({ id: 1 });
132-
const user2 = User.create({ id: 2 });
133-
const shift = Shift.create({ id: 1 });
131+
const user = User.make({ id: 1 });
132+
const user2 = User.make({ id: 2 });
133+
const shift = Shift.make({ id: 1 });
134134

135135
user.is(user); // true
136136
user.is(user2); // false
@@ -175,7 +175,7 @@ The `create` method instantiates your model while setting up attributes and rela
175175
```ts
176176
import User from '@Models/User';
177177

178-
const user = User.create({ name: 'User Name' }); // User
178+
const user = User.make({ name: 'User Name' }); // User
179179
```
180180
::: warning
181181
Constructing a new class like `new User({...})` is **not** acceptable. This will not overwrite your class fields with default values if the same key has been passed in due to how JavaScript first constructs the parent class and only then the subclasses. However, you can still use it to call instance methods. Furthermore, it will not cause unexpected results if using it with the [setAttribute](./attributes.md#setattribute) method or call methods that under the hood uses the [setAttribute](./attributes.md#setattribute).
@@ -187,8 +187,8 @@ When creating an instance and passing in another instance of the model:
187187
import User from '@Models/User';
188188
import Shift from '@Models/Shift';
189189

190-
const user = User.create({ name: 'John Doe' });
191-
const newUser = User.create(user);
190+
const user = User.make({ name: 'John Doe' });
191+
const newUser = User.make(user);
192192
```
193193
It will clone the [raw attributes](./attributes#getrawattributes) and the [relationships](./relationships.md#getrelations) of the model.
194194
:::
@@ -230,7 +230,7 @@ userClone.myKey === 1; // true
230230
#### factory
231231
<Badge text="static" type="warning"/>
232232

233-
The `factory` is a method that returns a [Factory](../testing.md#factorybuilder) instance. Optionally it takes a number argument which is a shorthand for the [times](../testing.md#times) method.
233+
The `factory` is a method that returns a [Factory](../testing/readme.md#factorybuilder) instance. Optionally it takes a number argument which is a shorthand for the [times](../testing/readme.md#times)' method.
234234

235235
```js
236236
import User from '@Models/User';
@@ -253,7 +253,7 @@ const users = await User.all(); // ModelCollection[User, ...]
253253
#### save
254254
<Badge text="async" type="warning"/>
255255

256-
The `save` method will update or save your model based on whether the model [exists](#exists) or not. If the model exists it will send a `PATCH` request containing the changes, and the optionally passed in attributes. If the model does not exists it will send a `POST` request. The method returns the same current user updated with the response data if any.
256+
The `save` method will update or save your model based on whether the model [exists](#exists) or not. If the model exists it will send a `PATCH` request containing the changes, and the optionally passed in attributes. If the model does not exist it will send a `POST` request. The method returns the same current user updated with the response data if any.
257257

258258
#### update
259259
<Badge text="async" type="warning"/>

docs/calliope/relationships.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Then you may query as:
3232
```js
3333
import User from '@Models/User';
3434

35-
const user = User.create({ id: 1 });
35+
const user = User.make({ id: 1 });
3636
const shiftsWithColleagues = await user.$shifts().with('colleagues').get(); // ModelCollection
3737

3838
await user.load('contract');
@@ -233,11 +233,11 @@ The `addRelations` method adds the relation onto the current model. It accepts t
233233
import User from '@Models/User';
234234
import Contract from '@Models/Contract';
235235

236-
const user = User.create({ id: 1 });
236+
const user = User.make({ id: 1 });
237237
user.addRelation('shifts', { id: 1 });
238238
user.shifts; // ModelCollection[Shift]
239239

240-
user.addRelation('$contract', Contract.create({ id: 1, user_id: 1 }));
240+
user.addRelation('$contract', Contract.make({ id: 1, user_id: 1 }));
241241
user.contract; // Contract
242242
```
243243

@@ -256,7 +256,7 @@ The `removeRelation` method removes the given relation from the model.
256256
```js
257257
import User from '@Models/User';
258258

259-
const user = User.create({ contract: { id: 1 } });
259+
const user = User.make({ contract: { id: 1 } });
260260
user.relationLoaded('contract'); // true
261261
user.removeRelation('contract').relationLoaded('$contract'); // false
262262
```
@@ -268,7 +268,7 @@ The `relationLoaded` method determines whether the given relation has been loade
268268
```js
269269
import User from '@Models/User';
270270

271-
const user = User.create({ contract: { id: 1 } });
271+
const user = User.make({ contract: { id: 1 } });
272272
user.relationLoaded('contract'); // true
273273
user.relationLoaded('$shifts'); // false
274274
```
@@ -301,9 +301,9 @@ The `for` method is used for [setting](./api-calls.md#setendpoint) custom endpoi
301301
```js
302302
import User from '@Models/User';
303303

304-
user.for(Team.create({ id: 1 })); // 'teams/1/users'
305-
user.for([Team.create({ id: 1 }), Contract.create({ id: 1 })]); // 'teams/1/contracts/1/users'
306-
user.for([new Team, Contract.create({ id: 1 })]); // 'teams/contracts/1/users'
304+
user.for(Team.make({ id: 1 })); // 'teams/1/users'
305+
user.for([Team.make({ id: 1 }), Contract.make({ id: 1 })]); // 'teams/1/contracts/1/users'
306+
user.for([new Team, Contract.make({ id: 1 })]); // 'teams/contracts/1/users'
307307
user.for([Team, Contract]); // teams/contracts/users
308308
```
309309

docs/calliope/timestamps.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ Timestamps are a feature of the model used for tracking changes on your entities
88

99
#### createdAt
1010

11-
The `createdAt` is a static property on the model. The default value is `'createdAt'`. You may over ride this if the expected timestamp attribute is named differently.
11+
The `createdAt` is a static property on the model. The default value is `'createdAt'`. You may override this if the expected timestamp attribute is named differently.
1212
The letter casing is no concern here as [getCreatedAtName](#getcreatedatname) will update it to the correct casing.
1313

1414
#### updatedAt
1515

16-
The `updatedAt` is a static property on the model. The default value is `'updatedAt'`. You may over ride this if the expected timestamp attribute is named differently.
16+
The `updatedAt` is a static property on the model. The default value is `'updatedAt'`. You may override this if the expected timestamp attribute is named differently.
1717
The letter casing is no concern here as [getUpdatedAtName](#getupdatedatname) will update it to the correct casing.
1818

1919
#### timestamps
@@ -54,7 +54,7 @@ The `freshTimestamps` method sends `GET` request [selecting](./query-building.md
5454

5555
#### deletedAt
5656

57-
The `deletedAt` is a static property on the model. The default value is `'deletedAt'`. You may over ride this if the expected timestamp attribute is named differently.
57+
The `deletedAt` is a static property on the model. The default value is `'deletedAt'`. You may override this if the expected timestamp attribute is named differently.
5858
The letter casing is no concern here as [getDeletedAtName](#getdeletedatname) will update it to the correct casing.
5959

6060
#### softDeletes

docs/helpers/collection.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ collection.dump().take(2); // Collection[1, 2]
412412
When all items in the collections are objects, then you may order them using the `orderBy` method. The method takes one or more objects describing how the collection should be ordered. The object has two properties:
413413

414414
- `property` - the name of the property you want to order by OR a method that accepts the collection item and returns the nested value.
415-
- `direction` - possible values are `asc`, `desc` respective to weather it should be in ascending or descending order.
415+
- `direction` - possible values are `asc`, `desc` respective to whether it should be in ascending or descending order.
416416

417417
```js
418418
const elements = [

docs/helpers/global-config.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ This is a `string` that the [model's endpoint](../calliope/api-calls.md#endpoint
145145

146146
#### randomDataGenerator
147147

148-
This value if set, it will be available for consuming in your [Factories](../testing.md#factories) under the member key [random](../testing.md#random).
148+
This value if set, it will be available for consuming in your [Factories](../testing/readme.md#factories) under the member key [random](../testing/readme.md#random).
149149

150150
#### requestMiddleware
151151

0 commit comments

Comments
 (0)