Skip to content

Commit cc66b3c

Browse files
authored
Update attributes (#28)
1 parent 593800c commit cc66b3c

File tree

18 files changed

+338
-144
lines changed

18 files changed

+338
-144
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Added
9+
- Resource attributes update
10+
811
## [0.2.0] - 2019-03-01
912
### Added
1013
- Improved ResourceController error handling

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
- [x] Fetching single resources
88
- [x] Creating resources
99
- [x] Deleting resources
10-
- [ ] Updating resource's attributes
11-
- [ ] Updating resource's relationships
10+
- [x] Updating resource's attributes
11+
- [x] Updating resource's relationships
1212
- [ ] Updating relationships
1313
- [ ] Asynchronous processing
1414
- [ ] Optional check for `Content-Type` header in incoming responses
@@ -19,8 +19,8 @@
1919
- [x] Fetching single resources
2020
- [x] Creating resources
2121
- [x] Deleting resources
22-
- [ ] Updating resource's attributes
23-
- [ ] Updating resource's relationships
22+
- [x] Updating resource's attributes
23+
- [x] Updating resource's relationships
2424
- [ ] Updating relationships
2525
- [ ] Inclusion of related resources
2626
- [ ] Sparse fieldsets

example/cars_server.dart

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,29 @@ void main() async {
1616
SimpleServer createServer() {
1717
final models = ModelDAO();
1818
[
19-
Model('1', 'Roadster'),
20-
Model('2', 'Model S'),
21-
Model('3', 'Model X'),
22-
Model('4', 'Model 3'),
19+
Model('1')..name = 'Roadster',
20+
Model('2')..name = 'Model S',
21+
Model('3')..name = 'Model X',
22+
Model('4')..name = 'Model 3',
2323
].forEach(models.insert);
2424

2525
final cities = CityDAO();
2626
[
27-
City('1', 'Munich'),
28-
City('2', 'Palo Alto'),
29-
City('3', 'Ingolstadt'),
27+
City('1')..name = 'Munich',
28+
City('2')..name = 'Palo Alto',
29+
City('3')..name = 'Ingolstadt',
3030
].forEach(cities.insert);
3131

3232
final companies = CompanyDAO();
3333
[
34-
Company('1', 'Tesla', headquarters: '2', models: ['1', '2', '3', '4']),
35-
Company('2', 'BMW', headquarters: '1'),
36-
Company('3', 'Audi'),
34+
Company('1')
35+
..name = 'Tesla'
36+
..headquarters = '2'
37+
..models.addAll(['1', '2', '3', '4']),
38+
Company('2')
39+
..name = 'BMW'
40+
..headquarters = '1',
41+
Company('3')..name = 'Audi',
3742
].forEach(companies.insert);
3843

3944
return SimpleServer(CarsController(

example/cars_server/controller.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,18 @@ class CarsController implements ResourceController {
7171
}
7272
return null;
7373
}
74+
75+
@override
76+
Future<Resource> updateResource(String type, String id, Resource resource,
77+
JsonApiHttpRequest request) async {
78+
if (resource.type != type) {
79+
throw ResourceControllerException(409,
80+
title: 'Type mismatch',
81+
detail: 'Resource type does not match the endpoint');
82+
}
83+
if (dao[type].fetchById(id) == null) {
84+
throw ResourceControllerException(404, detail: 'Resource not found');
85+
}
86+
return dao[type].update(id, resource);
87+
}
7488
}

example/cars_server/dao.dart

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ abstract class DAO<T> {
2424
_collection.remove(id);
2525
return 0;
2626
}
27+
28+
Resource update(String id, Resource resource) {
29+
throw UnimplementedError();
30+
}
2731
}
2832

2933
class ModelDAO extends DAO<Model> {
@@ -33,7 +37,13 @@ class ModelDAO extends DAO<Model> {
3337
void insert(Model model) => _collection[model.id] = model;
3438

3539
Model create(Resource r) {
36-
return Model(r.id, r.attributes['name']);
40+
return Model(r.id)..name = r.attributes['name'];
41+
}
42+
43+
@override
44+
Resource update(String id, Resource resource) {
45+
_collection[id].name = resource.attributes['name'];
46+
return null;
3747
}
3848
}
3949

@@ -44,14 +54,16 @@ class CityDAO extends DAO<City> {
4454
void insert(City city) => _collection[city.id] = city;
4555

4656
City create(Resource r) {
47-
return City(r.id, r.attributes['name']);
57+
return City(r.id)..name = r.attributes['name'];
4858
}
4959
}
5060

5161
class CompanyDAO extends DAO<Company> {
5262
Resource toResource(Company company) =>
5363
Resource('companies', company.id, attributes: {
54-
'name': company.name
64+
'name': company.name,
65+
'nasdaq': company.nasdaq,
66+
'updatedAt': company.updatedAt.toIso8601String()
5567
}, toOne: {
5668
'hq': company.headquarters == null
5769
? null
@@ -60,10 +72,15 @@ class CompanyDAO extends DAO<Company> {
6072
'models': company.models.map((_) => Identifier('models', _)).toList()
6173
});
6274

63-
void insert(Company company) => _collection[company.id] = company;
75+
void insert(Company company) {
76+
company.updatedAt = DateTime.now();
77+
_collection[company.id] = company;
78+
}
6479

6580
Company create(Resource r) {
66-
return Company(r.id, r.attributes['name']);
81+
return Company(r.id)
82+
..name = r.attributes['name']
83+
..updatedAt = DateTime.now();
6784
}
6885

6986
@override
@@ -74,4 +91,25 @@ class CompanyDAO extends DAO<Company> {
7491
_collection.remove(id);
7592
return deps;
7693
}
94+
95+
@override
96+
Resource update(String id, Resource resource) {
97+
// TODO: What is Resource type or id is changed?
98+
final company = _collection[id];
99+
if (resource.attributes.containsKey('name')) {
100+
company.name = resource.attributes['name'];
101+
}
102+
if (resource.attributes.containsKey('nasdaq')) {
103+
company.nasdaq = resource.attributes['nasdaq'];
104+
}
105+
if (resource.toOne.containsKey('hq')) {
106+
company.headquarters = resource.toOne['hq'].id;
107+
}
108+
if (resource.toMany.containsKey('models')) {
109+
company.models.clear();
110+
company.models.addAll(resource.toMany['models'].map((_) => _.id));
111+
}
112+
company.updatedAt = DateTime.now();
113+
return toResource(company);
114+
}
77115
}

example/cars_server/model.dart

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
class Company {
22
final String id;
3-
final String headquarters;
4-
final List<String> models;
3+
String headquarters;
4+
final models = <String>[];
5+
6+
/// Company name
57
String name;
68

7-
Company(this.id, this.name, {this.headquarters, this.models = const []});
9+
/// NASDAQ symbol
10+
String nasdaq;
11+
12+
DateTime updatedAt = DateTime.now();
13+
14+
Company(this.id);
815
}
916

1017
class City {
1118
final String id;
1219
String name;
1320

14-
City(this.id, this.name);
21+
City(this.id);
1522
}
1623

1724
class Model {
1825
final String id;
1926
String name;
2027

21-
Model(this.id, this.name);
28+
Model(this.id);
2229
}

lib/client.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1+
export 'package:json_api/document.dart';
12
export 'package:json_api/src/client/client.dart';
2-
export 'package:json_api/src/document.dart';
File renamed without changes.

lib/src/client/client.dart

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,16 @@ class JsonApiClient {
6161

6262
/// Creates a new resource. The resource will be added to a collection
6363
/// according to its type.
64+
///
65+
/// https://jsonapi.org/format/#crud-creating
6466
Future<Response<ResourceDocument>> createResource(Uri uri, Resource resource,
6567
{Map<String, String> headers}) =>
6668
_post(ResourceDocument.fromJson, uri,
6769
ResourceDocument(ResourceObject.fromResource(resource)), headers);
6870

6971
/// Deletes the resource.
72+
///
73+
/// https://jsonapi.org/format/#crud-deleting
7074
Future<Response<MetaDocument>> deleteResource(Uri uri,
7175
{Map<String, String> headers}) =>
7276
_delete(MetaDocument.fromJson, uri, headers);
@@ -76,15 +80,14 @@ class JsonApiClient {
7680
// {Map<String, String> headers}) =>
7781
// _post(ToMany.fromJson, uri,
7882
// ToMany(identifiers.map(IdentifierObject.fromIdentifier)), headers);
79-
//
80-
// Future<Response<ResourceDocument>> updateResource(Uri uri, Resource resource,
81-
// {Map<String, String> headers}) async =>
82-
// _patch(
83-
// ResourceDocument.fromJson,
84-
// uri,
85-
// ResourceDocument(ResourceObject(resource.type, resource.id,
86-
// attributes: resource.attributes)),
87-
// headers);
83+
84+
/// Updates the resource via PATCH request.
85+
///
86+
/// https://jsonapi.org/format/#crud-updating
87+
Future<Response<ResourceDocument>> updateResource(Uri uri, Resource resource,
88+
{Map<String, String> headers}) async =>
89+
_patch(ResourceDocument.fromJson, uri,
90+
ResourceDocument(ResourceObject.fromResource(resource)), headers);
8891

8992
Future<Response<D>> _get<D extends Document>(
9093
ResponseParser<D> parse, uri, Map<String, String> headers) =>
@@ -117,18 +120,18 @@ class JsonApiClient {
117120
'Content-Type': contentType,
118121
})));
119122

120-
// Future<Response<D>> _patch<D extends Document>(ResponseParser<D> parse, uri,
121-
// Document document, Map<String, String> headers) =>
122-
// _call(
123-
// parse,
124-
// (_) => _.patch(uri,
125-
// body: json.encode(document),
126-
// headers: {}
127-
// ..addAll(headers ?? {})
128-
// ..addAll({
129-
// 'Accept': contentType,
130-
// 'Content-Type': contentType,
131-
// })));
123+
Future<Response<D>> _patch<D extends Document>(ResponseParser<D> parse, uri,
124+
Document document, Map<String, String> headers) =>
125+
_call(
126+
parse,
127+
(_) => _.patch(uri,
128+
body: json.encode(document),
129+
headers: {}
130+
..addAll(headers ?? {})
131+
..addAll({
132+
'Accept': contentType,
133+
'Content-Type': contentType,
134+
})));
132135

133136
Future<Response<D>> _call<D extends Document>(ResponseParser<D> parse,
134137
Future<http.Response> fn(http.Client client)) async {

lib/src/server/json_api_controller.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,7 @@ abstract class JsonApiController {
2222

2323
Future<ServerResponse> deleteResource(
2424
String type, String id, JsonApiHttpRequest request);
25+
26+
Future<ServerResponse> updateResource(
27+
String type, String id, JsonApiHttpRequest request);
2528
}

0 commit comments

Comments
 (0)