lurch 0.1.0

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.
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"