lurch 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +4 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +29 -0
  6. data/.travis.yml +7 -0
  7. data/CHANGELOG.md +12 -0
  8. data/Gemfile +2 -0
  9. data/LICENSE.md +9 -0
  10. data/README.md +229 -0
  11. data/Rakefile +12 -0
  12. data/TODO.md +22 -0
  13. data/lib/lurch/changeset.rb +32 -0
  14. data/lib/lurch/client.rb +92 -0
  15. data/lib/lurch/collection.rb +111 -0
  16. data/lib/lurch/configuration.rb +14 -0
  17. data/lib/lurch/error.rb +13 -0
  18. data/lib/lurch/errors/bad_request.rb +6 -0
  19. data/lib/lurch/errors/conflict.rb +6 -0
  20. data/lib/lurch/errors/forbidden.rb +6 -0
  21. data/lib/lurch/errors/json_api_error.rb +29 -0
  22. data/lib/lurch/errors/not_found.rb +6 -0
  23. data/lib/lurch/errors/not_loaded.rb +13 -0
  24. data/lib/lurch/errors/relationship_not_loaded.rb +9 -0
  25. data/lib/lurch/errors/resource_not_loaded.rb +9 -0
  26. data/lib/lurch/errors/server_error.rb +6 -0
  27. data/lib/lurch/errors/unauthorized.rb +6 -0
  28. data/lib/lurch/errors/unprocessable_entity.rb +6 -0
  29. data/lib/lurch/inflector.rb +60 -0
  30. data/lib/lurch/logger.rb +7 -0
  31. data/lib/lurch/middleware/json_api_request.rb +22 -0
  32. data/lib/lurch/middleware/json_api_response.rb +24 -0
  33. data/lib/lurch/paginator.rb +71 -0
  34. data/lib/lurch/payload_builder.rb +43 -0
  35. data/lib/lurch/query.rb +143 -0
  36. data/lib/lurch/query_builder.rb +26 -0
  37. data/lib/lurch/railtie.rb +9 -0
  38. data/lib/lurch/relationship/has_many.rb +17 -0
  39. data/lib/lurch/relationship/has_one.rb +21 -0
  40. data/lib/lurch/relationship/linked.rb +40 -0
  41. data/lib/lurch/relationship.rb +26 -0
  42. data/lib/lurch/resource.rb +82 -0
  43. data/lib/lurch/store.rb +149 -0
  44. data/lib/lurch/store_configuration.rb +27 -0
  45. data/lib/lurch/stored_resource.rb +63 -0
  46. data/lib/lurch/uri_builder.rb +32 -0
  47. data/lib/lurch/version.rb +3 -0
  48. data/lib/lurch.rb +65 -0
  49. data/lurch.gemspec +26 -0
  50. data/lurch.gif +0 -0
  51. data/test/helpers/lurch_test.rb +40 -0
  52. data/test/helpers/response_factory.rb +193 -0
  53. data/test/lurch/test_configuration.rb +20 -0
  54. data/test/lurch/test_create_resources.rb +55 -0
  55. data/test/lurch/test_delete_resources.rb +27 -0
  56. data/test/lurch/test_errors.rb +29 -0
  57. data/test/lurch/test_fetch_relationships.rb +50 -0
  58. data/test/lurch/test_fetch_resources.rb +77 -0
  59. data/test/lurch/test_inflector.rb +13 -0
  60. data/test/lurch/test_paginated_collections.rb +125 -0
  61. data/test/lurch/test_queries.rb +104 -0
  62. data/test/lurch/test_relationship.rb +17 -0
  63. data/test/lurch/test_resource.rb +34 -0
  64. data/test/lurch/test_update_relationships.rb +53 -0
  65. data/test/lurch/test_update_resources.rb +56 -0
  66. data/test/test_helper.rb +15 -0
  67. metadata +235 -0
@@ -0,0 +1,27 @@
1
+ require_relative "../test_helper"
2
+
3
+ class TestDeleteResources < Minitest::Test
4
+ include LurchTest
5
+
6
+ def test_delete_existing_resource_from_server_using_store
7
+ stub_get("#{person_type}/1", @response_factory.person_response("1", "Alice"))
8
+ delete_stub = stub_delete("#{person_type}/1", @response_factory.no_content_response)
9
+
10
+ person = @store.from(:people).find("1")
11
+ response = @store.delete(person)
12
+
13
+ assert_requested delete_stub
14
+ assert response
15
+ end
16
+
17
+ def test_delete_existing_resource_from_server_using_query
18
+ stub_get("#{person_type}/1", @response_factory.person_response("1", "Alice"))
19
+ delete_stub = stub_delete("#{person_type}/1", @response_factory.no_content_response)
20
+
21
+ person = @store.from(:people).find("1")
22
+ response = @store.from(:people).delete(person)
23
+
24
+ assert_requested delete_stub
25
+ assert response
26
+ end
27
+ end
@@ -0,0 +1,29 @@
1
+ require_relative "../test_helper"
2
+
3
+ class TestErrors < Minitest::Test
4
+ include LurchTest
5
+
6
+ def test_401
7
+ stub_get("#{person_type}/1", @response_factory.unauthorized_response)
8
+ err = assert_raises(Lurch::Errors::Unauthorized) { @store.from(:people).find("1") }
9
+ assert_equal "401: Unauthorized", err.message
10
+ end
11
+
12
+ def test_403
13
+ stub_get("#{person_type}/1", @response_factory.forbidden_response)
14
+ err = assert_raises(Lurch::Errors::Forbidden) { @store.from(:people).find("1") }
15
+ assert_equal "403: Forbidden", err.message
16
+ end
17
+
18
+ def test_404
19
+ stub_get("#{person_type}/999", @response_factory.not_found_response)
20
+ err = assert_raises(Lurch::Errors::NotFound) { @store.from(:people).find("999") }
21
+ assert_equal "404: Not Found", err.message
22
+ end
23
+
24
+ def test_500
25
+ stub_get("#{person_type}/1", @response_factory.server_error_response)
26
+ err = assert_raises(Lurch::Errors::ServerError) { @store.from(:people).find("1") }
27
+ assert_equal "500: Internal Server Error", err.message
28
+ end
29
+ end
@@ -0,0 +1,50 @@
1
+ require_relative "../test_helper"
2
+
3
+ class TestFetchRelationships < Minitest::Test
4
+ include LurchTest
5
+
6
+ def test_fetch_linked_has_one_relationship_from_server
7
+ stub_get("#{phone_number_type}/1", @response_factory.phone_number_response("1", "Cell", "111-222-3344"))
8
+ stub_get("#{phone_number_type}/1/contact", @response_factory.person_response("1", "Alice"))
9
+
10
+ phone_number = @store.from(:phone_numbers).find("1")
11
+
12
+ assert_kind_of Lurch::Relationship::Linked, phone_number.contact
13
+ assert phone_number.contact.inspect
14
+ assert_raises(Lurch::Errors::RelationshipNotLoaded) { phone_number.contact.name }
15
+ err = assert_raises(Lurch::Errors::RelationshipNotLoaded) { phone_number.contact.respond_to?(:name) }
16
+ assert_equal "Relationship (contact) not loaded, try calling #fetch first.", err.message
17
+
18
+ phone_number.contact.fetch
19
+ person = phone_number.contact
20
+
21
+ assert_kind_of Lurch::Resource, person
22
+ assert_kind_of Lurch::Relationship::Linked, phone_number.relationships[:contact]
23
+ assert_raises(NoMethodError) { phone_number.relationships[:contact].name }
24
+ refute phone_number.relationships[:contact].respond_to?(:name)
25
+ assert_equal "Alice", person.name
26
+ end
27
+
28
+ def test_fetch_linked_has_many_relationship_from_server
29
+ stub_get("#{person_type}/1", @response_factory.person_response("1", "Alice"))
30
+ stub_get(
31
+ "#{person_type}/1/#{@inflector.encode_key(:phone_numbers)}",
32
+ @response_factory.phone_numbers_response(["1", "Cell", "111-222-3344"], ["2", "Home", "222-111-3344"])
33
+ )
34
+
35
+ person = @store.from(:people).find("1")
36
+
37
+ assert_kind_of Lurch::Relationship::Linked, person.phone_numbers
38
+ assert_equal false, person.phone_numbers.loaded?
39
+ assert person.phone_numbers.inspect
40
+
41
+ person.phone_numbers.fetch
42
+ phone_numbers = person.phone_numbers
43
+
44
+ assert_kind_of Lurch::Collection, phone_numbers
45
+ assert_equal true, person.phone_numbers.loaded?
46
+ assert_kind_of Lurch::Relationship::Linked, person.relationships[:phone_numbers]
47
+ assert_equal 2, phone_numbers.size
48
+ assert_equal "Cell", phone_numbers.first.name
49
+ end
50
+ end
@@ -0,0 +1,77 @@
1
+ require_relative "../test_helper"
2
+
3
+ class TestFetchResources < Minitest::Test
4
+ include LurchTest
5
+
6
+ def test_fetch_resource_from_server
7
+ stub_get("#{person_type}/1", @response_factory.person_response("1", "Alice"))
8
+
9
+ person = @store.from(:people).find("1")
10
+
11
+ assert_equal "Alice", person.name
12
+ assert person.inspect
13
+ end
14
+
15
+ def test_fetch_resource_collection_from_server
16
+ stub_get(person_type, @response_factory.people_response(["1", "Alice"], ["2", "Bob"]))
17
+
18
+ people = @store.from(:people).all
19
+
20
+ assert_kind_of Lurch::Collection, people
21
+ assert_equal 2, people.size
22
+ assert_equal ["Alice", "Bob"], people.map(&:name)
23
+ assert people.inspect
24
+ end
25
+
26
+ def test_fetch_already_fetched_resource_from_store
27
+ stub = stub_get("#{person_type}/1", @response_factory.person_response("1", "Alice"))
28
+
29
+ @store.from(:people).find("1")
30
+
31
+ remove_request_stub(stub)
32
+
33
+ assert @store.from(:people).find("1")
34
+ end
35
+
36
+ def test_fetch_resource_from_server_that_includes_has_one_relationship
37
+ stub_get("#{phone_number_type}/1", @response_factory.phone_number_response("1", "Cell", "111-222-3344", ["1", "Alice"]))
38
+
39
+ phone_number = @store.from(:phone_numbers).find("1")
40
+
41
+ assert_kind_of Lurch::Relationship::HasOne, phone_number.relationships[:contact]
42
+ assert phone_number.relationships[:contact].inspect
43
+ assert_kind_of Lurch::Resource, phone_number.contact
44
+ assert_equal "Alice", phone_number.contact.name
45
+ end
46
+
47
+ def test_fetch_resource_from_server_that_includes_has_many_relationship
48
+ stub_get("#{person_type}/1", @response_factory.person_response("1", "Alice", [["1", "Cell", "1112223344"], ["2", "Home", "2221113344"]]))
49
+
50
+ person = @store.from(:people).find("1")
51
+
52
+ assert_kind_of Lurch::Relationship::HasMany, person.relationships[:phone_numbers]
53
+ assert person.relationships[:phone_numbers].inspect
54
+ assert_kind_of Array, person.phone_numbers
55
+ assert_equal "Cell", person.phone_numbers.first.name
56
+ end
57
+
58
+ def test_fetch_resource_that_includes_resource_identifiers_only
59
+ stub_get("#{person_type}/1", @response_factory.person_response("1", "Alice", [["1"]], include_phone_numbers: false))
60
+
61
+ person = @store.from(:people).find("1")
62
+ phone_number = person.phone_numbers.first
63
+
64
+ assert_equal "1", phone_number.id
65
+ refute phone_number.loaded?
66
+ assert phone_number.inspect
67
+ err = assert_raises(Lurch::Errors::ResourceNotLoaded) { phone_number.name }
68
+ assert_equal "Resource (PhoneNumber) not loaded, try calling #fetch first.", err.message
69
+
70
+ stub_get("#{phone_number_type}/1", @response_factory.phone_number_response("1", "Cell", "111-222-3344"))
71
+
72
+ phone_number.fetch
73
+
74
+ assert phone_number.loaded?
75
+ assert_equal "Cell", phone_number.name
76
+ end
77
+ end
@@ -0,0 +1,13 @@
1
+ require_relative "../test_helper"
2
+
3
+ class TestInflector < Minitest::Test
4
+ include LurchTest
5
+
6
+ def test_bad_inflector
7
+ err = assert_raises(ArgumentError) { Lurch::Inflector.new(:foo, :pluralize) }
8
+ assert_equal "Invalid inflection mode: foo", err.message
9
+
10
+ err = assert_raises(ArgumentError) { Lurch::Inflector.new(:dasherize, :bar) }
11
+ assert_equal "Invalid types mode: bar", err.message
12
+ end
13
+ end
@@ -0,0 +1,125 @@
1
+ require_relative "../test_helper"
2
+
3
+ class TestPaginatedCollections < Minitest::Test
4
+ include LurchTest
5
+
6
+ def test_fetch_paginated_resource_collection_from_server
7
+ stub_get(person_type, @response_factory.paginated_people_response(10, 1, 2))
8
+
9
+ people = @store.from(:people).all
10
+
11
+ assert_kind_of Lurch::Collection, people
12
+ assert_equal 20, people.size
13
+ assert_equal 10, people.page_size
14
+ assert_equal 2, people.page_count
15
+ end
16
+
17
+ def test_fetch_next_page_of_paginated_resource_collection_from_server
18
+ stub_get(person_type, @response_factory.paginated_people_response(10, 1, 2))
19
+
20
+ people = @store.from(:people).all
21
+
22
+ assert people.next?
23
+
24
+ page2_stub = stub_get("#{person_type}?page[number]=2&page[size]=10", @response_factory.paginated_people_response(10, 2, 2))
25
+
26
+ people.next_collection
27
+
28
+ assert_requested page2_stub
29
+ end
30
+
31
+ def test_fetch_previous_page_of_paginated_resource_collection_from_server
32
+ stub_get("#{person_type}?page[number]=2&page[size]=10", @response_factory.paginated_people_response(10, 2, 2))
33
+
34
+ people = @store.from(:people).page(number: 2, size: 10).all
35
+
36
+ assert people.prev?
37
+
38
+ page1_stub = stub_get("#{person_type}?page[number]=1&page[size]=10", @response_factory.paginated_people_response(10, 1, 2))
39
+
40
+ people.prev_collection
41
+
42
+ assert_requested page1_stub
43
+ end
44
+
45
+ def test_fetch_first_page_of_paginated_resource_collection_from_server
46
+ stub_get("#{person_type}?page[number]=2&page[size]=10", @response_factory.paginated_people_response(10, 2, 2))
47
+
48
+ people = @store.from(:people).page(number: 2, size: 10).all
49
+
50
+ assert people.first?
51
+
52
+ page1_stub = stub_get("#{person_type}?page[number]=1&page[size]=10", @response_factory.paginated_people_response(10, 1, 2))
53
+
54
+ people.first_collection
55
+
56
+ assert_requested page1_stub
57
+ end
58
+
59
+ def test_fetch_last_page_of_paginated_resource_collection_from_server
60
+ stub_get(person_type, @response_factory.paginated_people_response(10, 1, 2))
61
+
62
+ people = @store.from(:people).all
63
+
64
+ assert people.last?
65
+
66
+ page2_stub = stub_get("#{person_type}?page[number]=2&page[size]=10", @response_factory.paginated_people_response(10, 2, 2))
67
+
68
+ people.last_collection
69
+
70
+ assert_requested page2_stub
71
+ end
72
+
73
+ def test_enumerate_paginated_collection_by_resource
74
+ page1_stub = stub_get(person_type, @response_factory.paginated_people_response(10, 1, 3))
75
+ page2_stub = stub_get("#{person_type}?page[number]=2&page[size]=10", @response_factory.paginated_people_response(10, 2, 3))
76
+ page3_stub = stub_get("#{person_type}?page[number]=3&page[size]=10", @response_factory.paginated_people_response(10, 3, 3))
77
+
78
+ people = @store.from(:people).all
79
+ names = people.map(&:name)
80
+
81
+ assert_kind_of Array, names
82
+ assert names.size == 30
83
+ assert names.first == "Person1"
84
+ assert names.last == "Person30"
85
+
86
+ assert_requested page1_stub
87
+ assert_requested page2_stub
88
+ assert_requested page3_stub
89
+ end
90
+
91
+ def test_enumerate_paginated_collection_by_page
92
+ page1_stub = stub_get(person_type, @response_factory.paginated_people_response(10, 1, 3))
93
+ page2_stub = stub_get("#{person_type}?page[number]=2&page[size]=10", @response_factory.paginated_people_response(10, 2, 3))
94
+ page3_stub = stub_get("#{person_type}?page[number]=3&page[size]=10", @response_factory.paginated_people_response(10, 3, 3))
95
+
96
+ people = @store.from(:people).all
97
+
98
+ people.each_page do |page|
99
+ assert_kind_of Array, page
100
+ assert page.size == 10
101
+ end
102
+
103
+ assert_requested page1_stub
104
+ assert_requested page2_stub
105
+ assert_requested page3_stub
106
+ end
107
+
108
+ def test_lazy_enumeration
109
+ page1_stub = stub_get(person_type, @response_factory.paginated_people_response(10, 1, 3))
110
+ page2_stub = stub_get("#{person_type}?page[number]=2&page[size]=10", @response_factory.paginated_people_response(10, 2, 3))
111
+ page3_stub = stub_get("#{person_type}?page[number]=3&page[size]=10", @response_factory.paginated_people_response(10, 3, 3))
112
+
113
+ people = @store.from(:people).all
114
+ names = people.lazy.map(&:name).first(20)
115
+
116
+ assert_kind_of Array, names
117
+ assert names.size == 20
118
+ assert names.first == "Person1"
119
+ assert names.last == "Person20"
120
+
121
+ assert_requested page1_stub
122
+ assert_requested page2_stub
123
+ assert_not_requested page3_stub
124
+ end
125
+ end
@@ -0,0 +1,104 @@
1
+ require_relative "../test_helper"
2
+
3
+ class TestQueries < Minitest::Test
4
+ include LurchTest
5
+
6
+ def test_filter
7
+ stub = stub_get(
8
+ "#{person_type}?filter[name]=Alice&filter[foo][]=bar&filter[foo][]=baz",
9
+ @response_factory.no_content_response
10
+ )
11
+
12
+ @store
13
+ .from(:people)
14
+ .filter(name: "Alice", foo: ["bar", "baz"])
15
+ .all
16
+
17
+ assert_requested(stub)
18
+ end
19
+
20
+ def test_include
21
+ stub = stub_get(
22
+ "#{person_type}?include=#{@inflector.encode_key(:phone_numbers)},friends,friends.#{@inflector.encode_key(:phone_numbers)}",
23
+ @response_factory.no_content_response
24
+ )
25
+
26
+ @store
27
+ .from(:people)
28
+ .include(:phone_numbers, :friends, "friends.phone_numbers")
29
+ .all
30
+
31
+ assert_requested(stub)
32
+ end
33
+
34
+ def test_fields
35
+ stub = stub_get(
36
+ "#{person_type}?fields[#{person_type}]=name&fields[#{phone_number_type}]=name,number",
37
+ @response_factory.no_content_response
38
+ )
39
+
40
+ @store
41
+ .from(:people)
42
+ .fields([:name])
43
+ .fields(:phone_number, [:name, :number])
44
+ .all
45
+
46
+ assert_requested(stub)
47
+ end
48
+
49
+ def test_sort
50
+ stub = stub_get(
51
+ "#{person_type}?sort=name,-foo,bar",
52
+ @response_factory.no_content_response
53
+ )
54
+
55
+ @store
56
+ .from(:people)
57
+ .sort(:name, {foo: :desc}, {bar: :asc})
58
+ .all
59
+
60
+ assert_requested(stub)
61
+ end
62
+
63
+ def test_bad_sort
64
+ assert_raises ArgumentError do
65
+ @store.from(:people).sort(foo: :bar).all
66
+ end
67
+ end
68
+
69
+ def test_page
70
+ stub = stub_get(
71
+ "#{person_type}?page[number]=12&page[size]=50",
72
+ @response_factory.no_content_response
73
+ )
74
+
75
+ @store
76
+ .from(:people)
77
+ .page(number: 12, size: 50)
78
+ .all
79
+
80
+ assert_requested(stub)
81
+ end
82
+
83
+ def test_all
84
+ stub = stub_get(
85
+ "#{person_type}?filter[name]=Alice&filter[foo][]=bar&filter[foo][]=baz&include=#{@inflector.encode_key(:phone_numbers)},friends,friends.#{@inflector.encode_key(:phone_numbers)}&fields[#{person_type}]=name&fields[#{phone_number_type}]=name,number&sort=name,-foo,bar&page[number]=12&page[size]=50",
86
+ @response_factory.no_content_response
87
+ )
88
+
89
+ query = @store
90
+ .from(:people)
91
+ .filter(name: "Alice", foo: ["bar", "baz"])
92
+ .include(:phone_numbers, :friends, "friends.phone_numbers")
93
+ .fields([:name])
94
+ .fields(:phone_number, [:name, :number])
95
+ .sort(:name, {foo: :desc}, {bar: :asc})
96
+ .page(number: 12, size: 50)
97
+
98
+ assert query.inspect
99
+
100
+ query.all
101
+
102
+ assert_requested(stub)
103
+ end
104
+ end
@@ -0,0 +1,17 @@
1
+ require_relative "../test_helper"
2
+
3
+ class TestRelationship < Minitest::Test
4
+ include LurchTest
5
+
6
+ def test_bad_relationship_document
7
+ err = assert_raises(ArgumentError) { Lurch::Relationship.from_document(nil, nil, {}) }
8
+ assert_equal "Invalid relationship document", err.message
9
+ end
10
+
11
+ def test_nil_has_one_relationship
12
+ rel = Lurch::Relationship::HasOne.new(nil, nil, {data: nil})
13
+
14
+ assert rel.loaded?
15
+ assert_nil rel.data
16
+ end
17
+ end
@@ -0,0 +1,34 @@
1
+ require_relative "../test_helper"
2
+
3
+ class TestResource < Minitest::Test
4
+ include LurchTest
5
+
6
+ def test_resource_equality
7
+ stub_get("#{person_type}/1", @response_factory.person_response("1", "Alice"))
8
+ stub_get("#{person_type}/2", @response_factory.person_response("2", "Bob"))
9
+
10
+ person1 = @store.from(:people).find("1")
11
+ person1_again = @store.from(:people).find("1")
12
+ person2 = @store.from(:people).find("2")
13
+
14
+ assert person1 == person1_again
15
+ assert person1.eql? person1_again
16
+ refute person1.equal? person1_again
17
+ refute person1 == person2
18
+ refute person1.eql? person2
19
+ refute person1.equal? person2
20
+ end
21
+
22
+ def test_resource_attribute_getters
23
+ stub_get("#{person_type}/1", @response_factory.person_response("1", "Alice"))
24
+
25
+ person = @store.from(:people).find("1")
26
+
27
+ assert person.name == "Alice"
28
+ assert person[:name] == "Alice"
29
+ assert person.respond_to?(:name)
30
+
31
+ refute person.respond_to?(:foo)
32
+ assert_raises(NoMethodError) { person.foo }
33
+ end
34
+ end
@@ -0,0 +1,53 @@
1
+ require_relative "../test_helper"
2
+
3
+ class TestUpdateRelationships < Minitest::Test
4
+ include LurchTest
5
+
6
+ def test_add_resources_to_has_many_relationship
7
+ stub_get("#{person_type}/1", @response_factory.person_response("1", "Alice"))
8
+ stub_get("#{phone_number_type}/1", @response_factory.phone_number_response("1", "Cell", "111-222-3344"))
9
+ stub_post("#{person_type}/1/relationships/#{@inflector.encode_key(:phone_numbers)}", @response_factory.no_content_response)
10
+
11
+ person = @store.from(:people).find("1")
12
+ phone_number = @store.from(:phone_numbers).find("1")
13
+ response = @store.add_related(person, :phone_numbers, [phone_number])
14
+
15
+ assert_requested :post, "#{@url}/#{person_type}/1/relationships/#{@inflector.encode_key(:phone_numbers)}", body: "{\"data\":[{\"id\":\"1\",\"type\":\"#{phone_number_type}\"}]}"
16
+ assert response
17
+ end
18
+
19
+ def test_remove_resources_from_has_many_relationship
20
+ stub_get("#{person_type}/1", @response_factory.person_response("1", "Alice"))
21
+ stub_get("#{person_type}/1/#{@inflector.encode_key(:phone_numbers)}", @response_factory.phone_numbers_response(["1", "Cell", "111-222-3344"]))
22
+ stub_delete("#{person_type}/1/relationships/#{@inflector.encode_key(:phone_numbers)}", @response_factory.no_content_response)
23
+
24
+ person = @store.from(:people).find("1")
25
+ phone_number = person.phone_numbers.fetch.first
26
+ response = @store.remove_related(person, :phone_numbers, [phone_number])
27
+
28
+ assert_requested :delete, "#{@url}/#{person_type}/1/relationships/#{@inflector.encode_key(:phone_numbers)}", body: "{\"data\":[{\"id\":\"1\",\"type\":\"#{phone_number_type}\"}]}"
29
+ assert response
30
+ end
31
+
32
+ def test_replace_resources_for_has_many_relationship
33
+ stub_get("#{person_type}/1", @response_factory.person_response("1", "Alice"))
34
+ stub_patch("#{person_type}/1/relationships/#{@inflector.encode_key(:phone_numbers)}", @response_factory.no_content_response)
35
+
36
+ person = @store.from(:people).find("1")
37
+ response = @store.update_related(person, :phone_numbers, [])
38
+
39
+ assert_requested :patch, "#{@url}/#{person_type}/1/relationships/#{@inflector.encode_key(:phone_numbers)}", body: '{"data":[]}'
40
+ assert response
41
+ end
42
+
43
+ def test_replace_resource_for_has_one_relationship
44
+ stub_get("#{phone_number_type}/1", @response_factory.phone_number_response("1", "Cell", "111-222-3344"))
45
+ stub_patch("#{phone_number_type}/1/relationships/contact", @response_factory.no_content_response)
46
+
47
+ phone_number = @store.from(:phone_numbers).find("1")
48
+ response = @store.update_related(phone_number, :contact, nil)
49
+
50
+ assert_requested :patch, "#{@url}/#{phone_number_type}/1/relationships/contact", body: '{"data":null}'
51
+ assert response
52
+ end
53
+ end
@@ -0,0 +1,56 @@
1
+ require_relative "../test_helper"
2
+
3
+ class TestUpdateResources < Minitest::Test
4
+ include LurchTest
5
+
6
+ def test_update_existing_resource_on_server_using_store
7
+ stub_get("#{person_type}/2", @response_factory.person_response("2", "Bob"))
8
+ stub_patch("#{person_type}/2", @response_factory.person_response("2", "Robert"))
9
+
10
+ person = @store.from(:people).find("2")
11
+
12
+ assert_equal "Bob", person.name
13
+
14
+ changeset = Lurch::Changeset.new(person, name: "Robert")
15
+ @store.save(changeset)
16
+
17
+ assert changeset.inspect
18
+ assert_requested :patch, "#{@url}/#{person_type}/2", body: "{\"data\":{\"id\":\"2\",\"type\":\"#{person_type}\",\"attributes\":{\"name\":\"Robert\"}}}"
19
+ assert_equal "Robert", person.name
20
+ end
21
+
22
+ def test_update_existing_resource_on_server_using_query
23
+ stub_get("#{person_type}/2", @response_factory.person_response("2", "Bob"))
24
+ stub_patch("#{person_type}/2", @response_factory.person_response("2", "Robert"))
25
+
26
+ person = @store.from(:people).find("2")
27
+
28
+ assert_equal "Bob", person.name
29
+
30
+ changeset = Lurch::Changeset.new(person)
31
+ changeset.set(:name, "Robert")
32
+ @store.to(:people).save(changeset)
33
+
34
+ assert_requested :patch, "#{@url}/#{person_type}/2", body: "{\"data\":{\"id\":\"2\",\"type\":\"#{person_type}\",\"attributes\":{\"name\":\"Robert\"}}}"
35
+ assert_equal "Robert", person.name
36
+ end
37
+
38
+ def test_validation_errors_when_updating_existing_resource
39
+ stub_get("#{person_type}/2", @response_factory.person_response("2", "Bob"))
40
+ stub_patch("#{person_type}/2", @response_factory.unprocessable_entity_response("name - can't be blank"))
41
+
42
+ person = @store.from(:people).find("2")
43
+
44
+ assert_equal "Bob", person.name
45
+
46
+ changeset = Lurch::Changeset.new(person, name: "")
47
+
48
+ err = assert_raises(Lurch::Errors::UnprocessableEntity) { @store.save(changeset) }
49
+ assert_equal "422: name - can't be blank", err.message
50
+ assert_equal 422, changeset.errors.first.status
51
+ assert_equal "name - can't be blank", changeset.errors.first.detail
52
+
53
+ assert_requested :patch, "#{@url}/#{person_type}/2", body: "{\"data\":{\"id\":\"2\",\"type\":\"#{person_type}\",\"attributes\":{\"name\":\"\"}}}"
54
+ assert_equal "Bob", person.name
55
+ end
56
+ end
@@ -0,0 +1,15 @@
1
+ require "pry"
2
+ require "simplecov"
3
+ require "codecov"
4
+ require "webmock/minitest"
5
+
6
+ require_relative "helpers/lurch_test"
7
+ require_relative "helpers/response_factory"
8
+
9
+ SimpleCov.formatter = SimpleCov::Formatter::Codecov
10
+ SimpleCov.start do
11
+ add_filter "/test/"
12
+ end
13
+
14
+ require "minitest/autorun"
15
+ require "lurch"