sequel_mapper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,194 @@
1
+ class SequelMapper::MockSequel
2
+ def initialize(relations)
3
+ @relations = {}
4
+
5
+ relations.each do |table_name|
6
+ @relations[table_name] = Relation.new(self, [])
7
+ end
8
+
9
+ @reads, @writes, @deletes = 0, 0, 0
10
+ end
11
+
12
+ attr_reader :relations
13
+ private :relations
14
+
15
+ def [](table_name)
16
+ @relations.fetch(table_name)
17
+ end
18
+
19
+ def log_read
20
+ @reads += 1
21
+ end
22
+
23
+ def log_write
24
+ @writes += 1
25
+ end
26
+
27
+ def log_delete
28
+ @deletes += 1
29
+ end
30
+
31
+ def read_count
32
+ @reads
33
+ end
34
+
35
+ def write_count
36
+ @writes
37
+ end
38
+
39
+ def delete_count
40
+ @deletes
41
+ end
42
+
43
+ class Query
44
+ def initialize(criteria: {}, order: [], reverse: false, &block)
45
+ if block
46
+ raise NotImplementedError.new("Block filtering not implemented")
47
+ end
48
+
49
+ @criteria = criteria
50
+ @order_columns = order
51
+ @reverse_order = reverse
52
+ end
53
+
54
+ attr_reader :criteria, :order_columns
55
+
56
+ def where(new_criteria, &block)
57
+ self.class.new(
58
+ criteria: criteria.merge(new_criteria),
59
+ order: order,
60
+ reverse: reverse,
61
+ &block
62
+ )
63
+ end
64
+
65
+ def order(columns)
66
+ self.class.new(
67
+ criteria: criteria,
68
+ order: columns,
69
+ )
70
+ end
71
+
72
+ def reverse
73
+ self.class.new(
74
+ criteria: criteria,
75
+ order: order_columns,
76
+ reverse: true,
77
+ )
78
+ end
79
+
80
+ def reverse_order?
81
+ !!@reverse_order
82
+ end
83
+ end
84
+
85
+ class Relation
86
+ include Enumerable
87
+
88
+ def initialize(database, all_rows, applied_query: Query.new)
89
+ @database = database
90
+ @all_rows = all_rows
91
+ @applied_query = applied_query
92
+ end
93
+
94
+ attr_reader :database, :all_rows, :applied_query
95
+ private :database, :all_rows, :applied_query
96
+
97
+ def where(criteria, &block)
98
+ new_with_query(Query.new(criteria: criteria, &block))
99
+ end
100
+
101
+ def order(columns)
102
+ new_with_query(applied_query.order(columns))
103
+ end
104
+
105
+ def reverse
106
+ @applied_query = @applied_query.reverse
107
+ end
108
+
109
+ def to_a
110
+ database.log_read
111
+
112
+ matching_rows
113
+ end
114
+
115
+ def each(&block)
116
+ puts "iterating over #{matching_rows}"
117
+ database.log_read
118
+
119
+ matching_rows.each(&block)
120
+ end
121
+
122
+ def delete
123
+ database.log_delete
124
+
125
+ matching_rows.each do |row_to_delete|
126
+ all_rows.delete(row_to_delete)
127
+ end
128
+ end
129
+
130
+ def insert(new_row)
131
+ database.log_write
132
+
133
+ all_rows.push(new_row)
134
+ end
135
+
136
+ def update(attrs)
137
+ database.log_write
138
+
139
+ # No need to get the rows from the canonical relation as the hashes can
140
+ # just be mutated in plaace.
141
+ matching_rows.each do |row|
142
+ attrs.each do |k, v|
143
+ row[k] = v
144
+ end
145
+ end
146
+ end
147
+
148
+ def empty?
149
+ database.log_read
150
+
151
+ matching_rows.empty?
152
+ end
153
+
154
+ private
155
+
156
+ def matching_rows
157
+ apply_sort(
158
+ equality_filter(all_rows, applied_query.criteria),
159
+ applied_query.order_columns,
160
+ applied_query.reverse_order?,
161
+ )
162
+ end
163
+
164
+ def apply_sort(rows, order_columns, reverse_order)
165
+ sorted_rows = rows.sort_by{ |row|
166
+ order_columns.map { |col| row.fetch(col) }
167
+ }
168
+
169
+ if reverse_order
170
+ sorted_rows.reverse
171
+ else
172
+ sorted_rows
173
+ end
174
+ end
175
+
176
+ def equality_filter(rows, criteria)
177
+ rows.select { |row|
178
+ criteria.all? { |k, v|
179
+ if v.is_a?(Enumerable)
180
+ v.include?(row.fetch(k))
181
+ else
182
+ row.fetch(k) == v
183
+ end
184
+ }
185
+ }
186
+ end
187
+
188
+ private
189
+
190
+ def new_with_query(query)
191
+ self.class.new(database, all_rows, applied_query: query)
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,29 @@
1
+ class QueryCounter
2
+ def initialize
3
+ reset
4
+ end
5
+
6
+ def read_count
7
+ @info.count { |query|
8
+ /\A\([0-9\.]+s\) SELECT/i === query
9
+ }
10
+ end
11
+
12
+ def info(message)
13
+ @info.push(message)
14
+ end
15
+
16
+ def error(message)
17
+ @error.push(message)
18
+ end
19
+
20
+ def warn(message)
21
+ @warn.push(message)
22
+ end
23
+
24
+ def reset
25
+ @info = []
26
+ @error = []
27
+ @warn = []
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,167 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sequel_mapper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Stephen Best
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.10.1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.10.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pg
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.17.1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.17.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: sequel
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '4.16'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '4.16'
97
+ description: ''
98
+ email:
99
+ - bestie@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".ruby-version"
107
+ - Gemfile
108
+ - Gemfile.lock
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - TODO.md
113
+ - lib/sequel_mapper.rb
114
+ - lib/sequel_mapper/association_proxy.rb
115
+ - lib/sequel_mapper/belongs_to_association_proxy.rb
116
+ - lib/sequel_mapper/graph.rb
117
+ - lib/sequel_mapper/queryable_association_proxy.rb
118
+ - lib/sequel_mapper/struct_factory.rb
119
+ - lib/sequel_mapper/version.rb
120
+ - sequel_mapper.gemspec
121
+ - spec/graph_persistence_spec.rb
122
+ - spec/graph_traversal_spec.rb
123
+ - spec/ordered_association_spec.rb
124
+ - spec/proxying_spec.rb
125
+ - spec/querying_spec.rb
126
+ - spec/sequel_mapper/association_proxy_spec.rb
127
+ - spec/sequel_mapper/belongs_to_association_proxy_spec.rb
128
+ - spec/spec_helper.rb
129
+ - spec/support/graph_fixture.rb
130
+ - spec/support/mock_sequel.rb
131
+ - spec/support/query_counter.rb
132
+ homepage: https://github.com/bestie/sequel_mapper
133
+ licenses:
134
+ - MIT
135
+ metadata: {}
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubyforge_project:
152
+ rubygems_version: 2.2.2
153
+ signing_key:
154
+ specification_version: 4
155
+ summary: A data mapper built on top of the Sequel database toolkit
156
+ test_files:
157
+ - spec/graph_persistence_spec.rb
158
+ - spec/graph_traversal_spec.rb
159
+ - spec/ordered_association_spec.rb
160
+ - spec/proxying_spec.rb
161
+ - spec/querying_spec.rb
162
+ - spec/sequel_mapper/association_proxy_spec.rb
163
+ - spec/sequel_mapper/belongs_to_association_proxy_spec.rb
164
+ - spec/spec_helper.rb
165
+ - spec/support/graph_fixture.rb
166
+ - spec/support/mock_sequel.rb
167
+ - spec/support/query_counter.rb