chassis_repo 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.
- data/.gitignore +47 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +42 -0
- data/LICENSE.txt +22 -0
- data/README.md +118 -0
- data/Rakefile +34 -0
- data/chassis_repo.gemspec +33 -0
- data/examples/maglev_repo.rb +56 -0
- data/examples/repo.rb +40 -0
- data/lib/chassis.rb +34 -0
- data/lib/chassis/array_utils.rb +8 -0
- data/lib/chassis/core_ext/array.rb +5 -0
- data/lib/chassis/core_ext/hash.rb +5 -0
- data/lib/chassis/core_ext/string.rb +13 -0
- data/lib/chassis/delegate.rb +29 -0
- data/lib/chassis/error.rb +7 -0
- data/lib/chassis/hash_utils.rb +16 -0
- data/lib/chassis/initializable.rb +3 -0
- data/lib/chassis/logger.rb +8 -0
- data/lib/chassis/persistence.rb +84 -0
- data/lib/chassis/repo.rb +71 -0
- data/lib/chassis/repo/base_repo.rb +99 -0
- data/lib/chassis/repo/delegation.rb +82 -0
- data/lib/chassis/repo/maglev_repo.rb +51 -0
- data/lib/chassis/repo/memory_repo.rb +7 -0
- data/lib/chassis/repo/null_repo.rb +64 -0
- data/lib/chassis/repo/record_map.rb +44 -0
- data/lib/chassis/string_utils.rb +50 -0
- data/lib/chassis/version.rb +3 -0
- data/test/array_utils_test.rb +23 -0
- data/test/chassis_test.rb +7 -0
- data/test/core_ext/array_test.rb +8 -0
- data/test/core_ext/hash_test.rb +8 -0
- data/test/core_ext/string_test.rb +16 -0
- data/test/delegate_test.rb +41 -0
- data/test/error_test.rb +12 -0
- data/test/hash_utils_test.rb +17 -0
- data/test/initializable_test.rb +7 -0
- data/test/logger_test.rb +43 -0
- data/test/persistence_test.rb +112 -0
- data/test/repo/delegation_test.rb +100 -0
- data/test/repo/maglev_repo_test.rb +52 -0
- data/test/repo/memory_repo_test.rb +25 -0
- data/test/repo/null_repo_test.rb +56 -0
- data/test/repo/repo_tests.rb +120 -0
- data/test/repo_test.rb +76 -0
- data/test/string_utils_test.rb +21 -0
- data/test/test_helper.rb +13 -0
- metadata +274 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
class RepoDelegationTest < Minitest::Test
|
4
|
+
class PersonRepo
|
5
|
+
extend Chassis::Repo::Delegation
|
6
|
+
|
7
|
+
def self.obj_class
|
8
|
+
Person
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class SomethingSomething
|
13
|
+
extend Chassis::Repo::Delegation
|
14
|
+
end
|
15
|
+
|
16
|
+
Person = Struct.new :name
|
17
|
+
|
18
|
+
attr_reader :target, :person
|
19
|
+
|
20
|
+
def repo
|
21
|
+
PersonRepo
|
22
|
+
end
|
23
|
+
|
24
|
+
def setup
|
25
|
+
@target = mock
|
26
|
+
@person = Person.new 'ahawkins'
|
27
|
+
Chassis::Repo.stubs(:default).returns(target)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_classes_that_dont_match_on_name_fail_with_a_helpful_error
|
31
|
+
assert_raises Chassis::UnknownObjectClassError do
|
32
|
+
SomethingSomething.object_class
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_find_delegates_to_the_target
|
37
|
+
target.expects(:find).with(Person, 1)
|
38
|
+
repo.find(1)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_delete_delegates_to_the_target
|
42
|
+
target.expects(:delete).with(person)
|
43
|
+
repo.delete(person)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_save_delegates_to_the_target
|
47
|
+
target.expects(:save).with(person)
|
48
|
+
repo.save(person)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_first_delegates_to_the_target
|
52
|
+
target.expects(:first).with(Person)
|
53
|
+
repo.first
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_last_delegates_to_the_target
|
57
|
+
target.expects(:last).with(Person)
|
58
|
+
repo.last
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_all_delegates_to_the_target
|
62
|
+
target.expects(:all).with(Person)
|
63
|
+
repo.all
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_each_delegates_to_the_target
|
67
|
+
target.expects(:each).with(Person)
|
68
|
+
repo.each
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_count_delegates_to_the_target
|
72
|
+
target.expects(:count).with(Person)
|
73
|
+
repo.count
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_query_delegates_to_the_target
|
77
|
+
target.expects(:query).with(Person, :foo)
|
78
|
+
repo.query :foo
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_query_bang__delegates_to_the_target
|
82
|
+
target.expects(:query!).with(Person, :foo)
|
83
|
+
repo.query! :foo
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_graph_query_delegates_to_the_target
|
87
|
+
target.expects(:graph_query).with(Person, :foo)
|
88
|
+
repo.graph_query(:foo)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_sample_delegates_to_the_backend
|
92
|
+
target.expects(:sample).with(Person)
|
93
|
+
repo.sample
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_empty_delegates_to_the_backend
|
97
|
+
target.expects(:empty?).with(Person)
|
98
|
+
repo.empty?
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
require_relative 'repo_tests'
|
3
|
+
|
4
|
+
class MaglevRepoTest < Minitest::Test
|
5
|
+
ROOT_KEY = :chassis_test
|
6
|
+
|
7
|
+
class TestRepo < Chassis::MaglevRepo
|
8
|
+
def query_person_named(klass, selector)
|
9
|
+
all(klass).select do |person|
|
10
|
+
person.name == selector.name
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def graph_query_person_named(klass, selector)
|
15
|
+
all(klass).select do |person|
|
16
|
+
person.name == selector.name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
include RepoTests
|
22
|
+
|
23
|
+
def setup
|
24
|
+
Maglev[ROOT_KEY] = {}
|
25
|
+
Maglev.commit
|
26
|
+
@repo = TestRepo.new Maglev[ROOT_KEY]
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
def teardown
|
31
|
+
Maglev.root.delete ROOT_KEY
|
32
|
+
Maglev.commit
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_map_store_is_committed
|
36
|
+
map = @repo.send :map
|
37
|
+
store = map.send :store
|
38
|
+
refute store.nil?
|
39
|
+
assert store.committed?
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_persistent_crud_operations
|
43
|
+
person = Person.new 'ahawkins'
|
44
|
+
|
45
|
+
refute person.committed?, "brand new custom objects should be transient"
|
46
|
+
repo.create person
|
47
|
+
assert person.committed?, "repo must commit saved objects"
|
48
|
+
|
49
|
+
# repo.delete(person)
|
50
|
+
# refute person.committed?, "repo must delete committed objects"
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
require_relative 'repo_tests'
|
3
|
+
|
4
|
+
class MemoryRepoTest < Minitest::Test
|
5
|
+
class TestRepo < Chassis::MemoryRepo
|
6
|
+
def query_person_named(klass, selector)
|
7
|
+
all(klass).select do |person|
|
8
|
+
person.name == selector.name
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def graph_query_person_named(klass, selector)
|
13
|
+
all(klass).select do |person|
|
14
|
+
person.name == selector.name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
include RepoTests
|
20
|
+
|
21
|
+
def setup
|
22
|
+
@repo = TestRepo.new
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
class NullRepoTest < Minitest::Test
|
4
|
+
Person = Struct.new :name do
|
5
|
+
attr_accessor :id
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :repo
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@repo = Chassis::NullRepo.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_create_sets_the_id
|
15
|
+
person = Person.new 'ahawkins'
|
16
|
+
repo.create person
|
17
|
+
|
18
|
+
assert person.id, "Repo must set the ID after creating"
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_all_returns_an_empty_array
|
22
|
+
assert_equal [], repo.all(Person)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_implements_required_interface
|
26
|
+
assert_respond_to repo, :update
|
27
|
+
assert_respond_to repo, :delete
|
28
|
+
assert_respond_to repo, :find
|
29
|
+
assert_respond_to repo, :all
|
30
|
+
assert_respond_to repo, :count
|
31
|
+
assert_respond_to repo, :first
|
32
|
+
assert_respond_to repo, :last
|
33
|
+
assert_respond_to repo, :sample
|
34
|
+
assert_respond_to repo, :query
|
35
|
+
assert_respond_to repo, :graph_query
|
36
|
+
assert_respond_to repo, :graph_query
|
37
|
+
assert_respond_to repo, :clear
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_query_returns_empty_array
|
41
|
+
assert_equal [ ], repo.query(Person, :selector)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_graph_query_returns_empty_array
|
45
|
+
assert_equal [ ], repo.graph_query(Person, :selector)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_count_returns_no
|
49
|
+
assert_equal 0, repo.count(Person)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_first_and_last_return_nil
|
53
|
+
assert_nil repo.first(Person)
|
54
|
+
assert_nil repo.last(Person)
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module RepoTests
|
2
|
+
Person = Struct.new :name do
|
3
|
+
attr_accessor :id
|
4
|
+
end
|
5
|
+
|
6
|
+
PersonNamed = Struct.new :name
|
7
|
+
PersonFooBarBaz = Class.new
|
8
|
+
|
9
|
+
def repo
|
10
|
+
fail "test class must assign @repo" unless @repo
|
11
|
+
@repo
|
12
|
+
end
|
13
|
+
|
14
|
+
def setup
|
15
|
+
repo.clear
|
16
|
+
repo.initialize_storage
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_crud_operations
|
20
|
+
assert_equal 0, repo.count(Person), "Precondition: there should be no records"
|
21
|
+
|
22
|
+
person = Person.new 'ahawkins'
|
23
|
+
repo.create person
|
24
|
+
|
25
|
+
assert person.id, "repo must set the ID after creating"
|
26
|
+
|
27
|
+
assert_equal 1, repo.count(Person)
|
28
|
+
|
29
|
+
assert_equal person, repo.find(Person, person.id)
|
30
|
+
|
31
|
+
assert_equal [person], repo.all(Person)
|
32
|
+
|
33
|
+
person.name = 'adam'
|
34
|
+
repo.update person
|
35
|
+
assert_equal 'adam', repo.find(Person, person.id).name
|
36
|
+
|
37
|
+
repo.delete(person)
|
38
|
+
|
39
|
+
assert_equal 0, repo.count(Person)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_raises_error_when_no_reecord_exists
|
43
|
+
assert_equal 0, repo.count(Person)
|
44
|
+
|
45
|
+
assert_raises Chassis::RecordNotFoundError do
|
46
|
+
repo.find Person, 1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_first_and_last
|
51
|
+
assert_equal 0, repo.count(Person), "Precondition: there should be no records"
|
52
|
+
|
53
|
+
adam = Person.new 'ahawkins'
|
54
|
+
peter = Person.new 'pepps'
|
55
|
+
|
56
|
+
repo.create adam
|
57
|
+
repo.create peter
|
58
|
+
|
59
|
+
assert_equal adam, repo.first(Person)
|
60
|
+
assert_equal peter, repo.last(Person)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_clear_wipes_data
|
64
|
+
assert_equal 0, repo.count(Person), "Precondition: there should be no records"
|
65
|
+
|
66
|
+
adam = Person.new 'ahawkins'
|
67
|
+
repo.create adam
|
68
|
+
|
69
|
+
refute_empty repo.all(Person)
|
70
|
+
assert_equal 1, repo.count(Person)
|
71
|
+
assert repo.find(Person, adam.id)
|
72
|
+
|
73
|
+
repo.clear
|
74
|
+
|
75
|
+
assert_empty repo.all(Person)
|
76
|
+
assert_equal 0, repo.count(Person)
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_raises_an_error_when_query_not_implemented
|
80
|
+
assert_raises Chassis::QueryNotImplementedError do
|
81
|
+
repo.query Person, PersonFooBarBaz.new
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_uses_query_method_to_implement_queries
|
86
|
+
assert_equal 0, repo.count(Person), "Precondition: there should be no records"
|
87
|
+
|
88
|
+
adam = Person.new 'ahawkins'
|
89
|
+
peter = Person.new 'pepp'
|
90
|
+
|
91
|
+
repo.create adam
|
92
|
+
repo.create peter
|
93
|
+
|
94
|
+
assert_equal 2, repo.count(Person)
|
95
|
+
|
96
|
+
query = repo.query(Person, PersonNamed.new('ahawkins'))
|
97
|
+
refute_empty query
|
98
|
+
assert_equal adam, query.first
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_raises_an_error_when_a_graph_query_is_not_implemented
|
102
|
+
assert_raises Chassis::GraphQueryNotImplementedError do
|
103
|
+
repo.graph_query Person, PersonFooBarBaz.new
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_uses_the_specific_graph_query_method_for_graph_query
|
108
|
+
assert_equal 0, repo.count(Person), "Precondition: there should be no records"
|
109
|
+
|
110
|
+
adam = Person.new 'ahawkins'
|
111
|
+
peter = Person.new 'pepp'
|
112
|
+
|
113
|
+
repo.create adam
|
114
|
+
repo.create peter
|
115
|
+
|
116
|
+
query = repo.query(Person, PersonNamed.new('ahawkins'))
|
117
|
+
refute_empty query
|
118
|
+
assert_equal adam, query.first
|
119
|
+
end
|
120
|
+
end
|
data/test/repo_test.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class RepoTest < Minitest::Test
|
4
|
+
class TestAdapter < Chassis::MemoryRepo
|
5
|
+
def query_test_empty_array_query(klass, q)
|
6
|
+
[ ]
|
7
|
+
end
|
8
|
+
|
9
|
+
def query_test_nil_query(klass, q)
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def query_person_by_name(klass, q)
|
14
|
+
all(klass).find do |record|
|
15
|
+
record.name == q.name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def update(record)
|
20
|
+
record.name = 'updated'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
CustomError = Class.new RuntimeError
|
25
|
+
TestEmptyArrayQuery = Struct.new :foo
|
26
|
+
TestNilQuery = Struct.new :foo
|
27
|
+
PersonByName = Struct.new :name
|
28
|
+
Person = Struct.new :id, :name
|
29
|
+
|
30
|
+
def repo
|
31
|
+
Chassis.repo
|
32
|
+
end
|
33
|
+
|
34
|
+
def setup
|
35
|
+
repo.register :test, TestAdapter.new
|
36
|
+
repo.use :test
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_query_bang_raises_an_exception_if_empty
|
40
|
+
assert_raises Chassis::NoQueryResultError do
|
41
|
+
repo.query! Person, TestEmptyArrayQuery.new(:foo)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_query_bang_raises_an_exception_if_nil
|
46
|
+
assert_raises Chassis::NoQueryResultError do
|
47
|
+
repo.query! Person, TestNilQuery.new(:foo)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_query_bang_can_take_a_block_to_customize_exception
|
52
|
+
assert_raises CustomError do
|
53
|
+
repo.query! Person, TestNilQuery.new(:foo) do |klass, selector|
|
54
|
+
fail CustomError
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_query_bang_works_when_a_non_array_object_is_returned
|
60
|
+
person = Person.new nil, 'ahawkins'
|
61
|
+
repo.save person
|
62
|
+
assert_equal person, repo.query!(Person, PersonByName.new('ahawkins'))
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_save_creates_records_without_ids
|
66
|
+
person = Person.new nil, 'ahawkins'
|
67
|
+
repo.save person
|
68
|
+
assert person.id
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_save_updates_records_otherwise
|
72
|
+
person = Person.new 1, 'ahawkins'
|
73
|
+
repo.save person
|
74
|
+
assert_equal 'updated', person.name
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class StringUtilsTest < Minitest::Test
|
4
|
+
def utils
|
5
|
+
Chassis::StringUtils
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_underscore
|
9
|
+
result = utils.underscore 'FooBar'
|
10
|
+
assert_equal 'foo_bar', result
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_demodulize
|
14
|
+
result = utils.demodulize 'Foo::Bar::Baz'
|
15
|
+
assert_equal 'Baz', result
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_constantize
|
19
|
+
assert_equal utils, utils.constantize('Chassis::StringUtils')
|
20
|
+
end
|
21
|
+
end
|