Skip to content

Commit a94b0c4

Browse files
committed
Rewrite package
1 parent 2c50a45 commit a94b0c4

26 files changed

+5927
-15477
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
node_modules
2+
dist

.prettierignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
11
dist
2-
package-lock.json
3-
CHANGELOG.md

CHANGELOG.md

Lines changed: 84 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,46 +7,115 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### ⚠️ Breaking Changes
11+
12+
- Rewrite TypeScript support to allow Intellisense based on JSON:API resource schema. For example:
13+
14+
```ts
15+
type UsersSchema = {
16+
type: 'users';
17+
id: string;
18+
attributes: {
19+
name: string;
20+
};
21+
relationships: {
22+
dog: { data?: { type: 'dogs'; id: string } | null };
23+
};
24+
};
25+
26+
class User extends Model<UsersSchema> {}
27+
```
28+
29+
To type related resources, you can provide a collection of all models as the second generic.
30+
31+
```ts
32+
type DogsSchema = {
33+
// ...
34+
};
35+
36+
type Schemas = {
37+
users: User;
38+
dogs: Dog;
39+
};
40+
41+
class User extends Model<UsersSchema, Schemas> {}
42+
class Dog extends Model<DogsSchema, Schemas> {}
43+
```
44+
45+
- The `Store` now returns proxied `Model` instances to implement field getters, instead of `Model` depending on `Store` and defining getters for present fields.
46+
47+
- Remove the `Query` helper. Use [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) instead.
48+
49+
- Remove `Model` attribute casting functionality. Define getters instead:
50+
51+
```ts
52+
class User extends Model<UserSchema> {
53+
get createdAtDate() {
54+
return new Date(this.createdAt);
55+
}
56+
}
57+
```
58+
59+
- Remove the `Model.getAttribute()` and `Model.getRelationship()` methods.
60+
- Remove CJS and IIFE exports. Package is now only exported as an ES module.
61+
1062
## [0.1.0-beta.8] - 2022-06-05
63+
1164
### Added
12-
- Support model type inference:
13-
```ts
14-
const store = new Store({ users: User });
15-
store.find('users', '1') // User
16-
```
65+
66+
- Support model type inference:
67+
68+
```ts
69+
const store = new Store({ users: User });
70+
store.find('users', '1'); // User
71+
```
1772

1873
### Removed
19-
- Remove the `Store.model` method. Models must now be defined when the Store is constructed.
74+
75+
- Remove the `Store.model` method. Models must now be defined when the Store is constructed.
2076

2177
## [0.1.0-beta.7] - 2021-09-01
78+
2279
### Fixed
23-
- Fix regression with attribute casting not handling dates correctly, and add more sophisticated handling of primitives, constructables, and callables.
80+
81+
- Fix regression with attribute casting not handling dates correctly, and add more sophisticated handling of primitives, constructables, and callables.
2482

2583
## [0.1.0-beta.6] - 2021-09-01
84+
2685
### Fixed
27-
- Fix attribute cast type definition and invoke as function rather than with `new`.
86+
87+
- Fix attribute cast type definition and invoke as function rather than with `new`.
2888

2989
## [0.1.0-beta.5] - 2021-08-31
90+
3091
### Added
31-
- Query: add `append`, `set`, and `delete` methods.
32-
- Export useful JSON:API types: `JsonApiDocument`, `JsonApiIdentifier`, `JsonApiResource`, `JsonApiRelationships`, and `JsonApiRelationship`.
92+
93+
- Query: add `append`, `set`, and `delete` methods.
94+
- Export useful JSON:API types: `JsonApiDocument`, `JsonApiIdentifier`, `JsonApiResource`, `JsonApiRelationships`, and `JsonApiRelationship`.
3395

3496
### Removed
35-
- Query: remove `push` method.
97+
98+
- Query: remove `push` method.
3699

37100
## [0.1.0-beta.4] - 2021-05-26
101+
38102
### Fixed
39-
- Fix casts not working correctly.
103+
104+
- Fix casts not working correctly.
40105

41106
## [0.1.0-beta.3] - 2021-05-26
107+
42108
### Added
43-
- Added ability to define typecasts for attributes on custom models.
109+
110+
- Added ability to define typecasts for attributes on custom models.
44111

45112
### Changed
46-
- Change compilation target to `es2017` for `Object.entries` support.
113+
114+
- Change compilation target to `es2017` for `Object.entries` support.
47115

48116
## [0.1.0-beta.2] - 2021-01-17
49-
- Initial release
117+
118+
- Initial release
50119

51120
[Unreleased]: https://github.com/tobyzerner/json-api-models/compare/v0.1.0-beta.8...HEAD
52121
[0.1.0-beta.8]: https://github.com/tobyzerner/json-api-models/compare/v0.1.0-beta.7...v0.1.0-beta.8

README.md

Lines changed: 62 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ const models = new Store();
1818
// Sync a JSON:API response document to the store
1919
models.sync({
2020
data: {
21-
type: 'humans',
21+
type: 'users',
2222
id: '1',
2323
attributes: { name: 'Toby' },
2424
relationships: {
25-
dog: { data: { type: 'dogs', id: '1' } },
25+
pet: { data: { type: 'dogs', id: '1' } },
2626
},
2727
},
2828
included: [
@@ -35,20 +35,22 @@ models.sync({
3535
});
3636

3737
// Resource data is transformed into easy-to-consume models
38-
const human = models.find('humans', '1');
39-
human.name; // Toby
40-
human.dog; // { type: 'dogs', id: '1', name: 'Rosie' }
38+
const user = models.find('users', '1');
39+
user.name; // Toby
40+
user.pet; // { type: 'dogs', id: '1', name: 'Rosie' }
4141
```
4242

4343
### Syncing JSON:API Data
4444

45-
Use the `sync` method to load your JSON:API response document into the store. Both the primary `data` and any `included` resources will be synced. The return value will be a model, or an array of models, corresponding to the primary data.
45+
Use the `sync` method to load your JSON:API response document into the store. Both the primary `data` and any `included`
46+
resources will be synced. The return value will be a model, or an array of models, corresponding to the primary data.
4647

4748
```ts
4849
const model = models.sync(document);
4950
```
5051

51-
If any of the synced resources already exist within the store, the new data will be **merged** into the old model. The model instance will not change so references to it throughout your application will remain intact.
52+
If any of the synced resources already exist within the store, the new data will be **merged** into the old model. The
53+
model instance will not change so references to it throughout your application will remain intact.
5254

5355
You can also sync an individual resource using the `syncResource` method:
5456

@@ -62,12 +64,13 @@ const model = models.syncResource({
6264

6365
### Retrieving Models
6466

65-
Specific models can be retrieved from the store using the `find` method. Pass it a type and an ID, a resource identifier object, or an array of resource identifier objects:
67+
Specific models can be retrieved from the store using the `find` method. Pass it a type and an ID, a resource identifier
68+
object, or an array of resource identifier objects:
6669

6770
```ts
68-
const model = models.find('users', '1');
69-
const model = models.find({ type: 'users', id: '1' });
70-
const models = models.find([
71+
const user = models.find('users', '1');
72+
const user = models.find({ type: 'users', id: '1' });
73+
const users = models.find([
7174
{ type: 'users', id: '1' },
7275
{ type: 'users', id: '2' },
7376
]);
@@ -76,45 +79,47 @@ const models = models.find([
7679
Retrieve all of the models of a given type using the `findAll` method:
7780

7881
```ts
79-
const models = models.findAll('users');
82+
const users = models.findAll('users');
8083
```
8184

8285
### Working with Models
8386

84-
Models are a _superset_ of JSON:API resource objects, meaning they contain all of the members you would expect (`type`, `id`, `attributes`, `relationships`, `meta`, `links`) plus some additional functionality.
87+
Models are a _superset_ of JSON:API resource objects, meaning they contain all of the members you would
88+
expect (`type`, `id`, `attributes`, `relationships`, `meta`, `links`) plus some additional functionality.
8589

86-
Getters are automatically defined for all fields, allowing you to easily access their contents. Relationship fields are automatically resolved to their related models (if present within the store):
90+
Getters are automatically defined for all fields, allowing you to easily access their contents. Relationship fields are
91+
automatically resolved to their related models (if present within the store):
8792

8893
```ts
8994
model.name; // => model.attributes.name
90-
model.dog; // => models.find(model.relationships.dog.data)
95+
model.pet; // => models.find(model.relationships.pet.data)
9196
```
9297

93-
To easily retrieve a resource identifier object for the model, the `identifier` method is available. This is useful when constructing relationships in JSON:API request documents.
98+
To easily retrieve a resource identifier object for the model, the `identifier` method is available. This is useful when
99+
constructing relationships in JSON:API request documents.
94100

95101
```ts
96102
model.identifier(); // { type: 'users', id: '1' }
97103
```
98104

99105
### Forgetting Models
100106

101-
Remove a model from the store using the `forget` method, which accepts a resource identifier object. This means you can pass a model directly into it:
107+
Remove a model from the store using the `forget` method, which accepts a resource identifier object. This means you can
108+
pass a model directly into it:
102109

103110
```ts
104111
models.forget(user);
105112
```
106113

107114
### Custom Models
108115

109-
You can define custom model classes to add your own functionality. Custom models must extend the `Model` base class. This is useful if you wish to add any custom getters or methods to models for a specific resource type, and also to define types for each resource field:
116+
You can define custom model classes to add your own functionality. Custom models must extend the `Model` base class.
117+
This is useful if you wish to add any custom getters or methods to models for a specific resource type:
110118

111119
```ts
112120
import { Model } from 'json-api-models';
113121

114-
class User extends Model<'users'> {
115-
public declare name: string;
116-
public declare age: number;
117-
122+
class User extends Model {
118123
get firstName() {
119124
return this.name.split(' ')[0];
120125
}
@@ -129,24 +134,45 @@ const models = new Store({
129134
});
130135
```
131136

132-
#### Attribute Casts
137+
### TypeScript
133138

134-
You can define typecasts for attributes on your custom models:
139+
For TypeScript autocompletion of model attributes and relationships, provide the raw JSON:API resource schema when defining your models.
135140

136141
```ts
137-
class User extends Model<'users'> {
138-
public declare name: string;
139-
public declare createdAt: Date;
140-
141-
protected casts = {
142-
createdAt: Date,
142+
type UsersSchema = {
143+
type: 'users';
144+
id: string;
145+
attributes: {
146+
name: string;
143147
};
144-
}
148+
relationships: {
149+
dog: { data?: { type: 'dogs'; id: string } | null };
150+
};
151+
};
152+
153+
class User extends Model<UsersSchema> {}
154+
```
155+
156+
To type related resources, you can provide a collection of all models as the second generic.
157+
158+
```ts
159+
type DogsSchema = {
160+
// ...
161+
};
162+
163+
type Schemas = {
164+
users: User;
165+
dogs: Dog;
166+
};
167+
168+
class User extends Model<UsersSchema, Schemas> {}
169+
class Dog extends Model<DogsSchema, Schemas> {}
145170
```
146171

147172
### API Consumption Tips
148173

149-
This library is completely unopinionated about how you interact with your JSON:API server. It merely gives you an easy way to work with the resulting JSON:API data. An example integration with `fetch` is demonstrated below:
174+
This library is completely unopinionated about how you interact with your JSON:API server. It merely gives you an easy
175+
way to work with the resulting JSON:API data. An example integration with `fetch` is demonstrated below:
150176

151177
```ts
152178
const models = new Store();
@@ -169,7 +195,7 @@ function api(url, options = {}) {
169195
const data = models.sync(document);
170196
return { response, document, data };
171197
}
172-
}
198+
},
173199
);
174200
}
175201

@@ -178,7 +204,9 @@ api('users/1').then(({ data }) => {
178204
});
179205
```
180206

181-
When constructing API requests, remember that JSON:API resource objects contain `links` that can be used instead of rebuilding the URL. Also, models contain an `identifier` method that can be used to spread the `type` and `id` members into the document `data` (required by the specification). Here is an example of a request to update a resource:
207+
When constructing API requests, remember that JSON:API resource objects contain `links` that can be used instead of
208+
rebuilding the URL. Also, models contain an `identifier` method that can be used to spread the `type` and `id` members
209+
into the document `data` (required by the specification). Here is an example of a request to update a resource:
182210

183211
```ts
184212
const user = models.find('users', '1');
@@ -194,29 +222,6 @@ api(user.links.self, {
194222
});
195223
```
196224

197-
### Building Queries
198-
199-
Building query strings for your JSON:API requests can be tedious, and sometimes they may need to be constructed dynamically with merge logic for certain parameters. The `Query` class takes care of this:
200-
201-
```ts
202-
import { Query } from 'json-api-models';
203-
204-
const query = new Query({
205-
include: 'foo',
206-
'fields[users]': 'name',
207-
});
208-
209-
query.append('include', 'bar');
210-
query.append('fields[users]', 'age');
211-
212-
query.toString(); // include=foo,bar&fields[users]=name,age
213-
214-
query.delete('fields[users]');
215-
query.set('include', 'replaced');
216-
217-
query.toString(); // include=replaced
218-
```
219-
220225
## Contributing
221226

222227
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

dist/index.cjs.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

dist/index.d.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

dist/index.es.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)