chassis_repo 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|