frozen_record 0.21.1 → 0.22.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.
- checksums.yaml +4 -4
- data/README.md +0 -2
- data/benchmark/querying +34 -0
- data/frozen_record.gemspec +0 -2
- data/lib/frozen_record/backends/yaml.rb +2 -0
- data/lib/frozen_record/base.rb +6 -3
- data/lib/frozen_record/index.rb +4 -5
- data/lib/frozen_record/scope.rb +61 -7
- data/lib/frozen_record/version.rb +1 -1
- data/spec/frozen_record_spec.rb +26 -0
- data/spec/scope_spec.rb +16 -2
- data/spec/spec_helper.rb +0 -10
- metadata +3 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bfb835436fc605e43a6b928ae9e8149ec80f726dd0650801c3e1e2e4d46dba1d
|
4
|
+
data.tar.gz: 1b2d08e68b018cb8a0c18e68420dab5930c51c3cf42c559c841eb340b0b0226d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d7ae3739cc1a172d8a54e1f87513b307db69c937522032fbcf845a4f11141f7e373739f79c98e15216f6ce17ac4a0410cc6f72033b9a9cbb31ec260e650ea6c
|
7
|
+
data.tar.gz: 9f88ee2a8186533cbd8482704d2e02bc275e73af310b24801b7cebb37320ab6297038b3efa6368ea9ce0122de7aaaa56f1180fed4c9eefe1dc5de059e35ccbd0
|
data/README.md
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# FrozenRecord
|
2
2
|
|
3
3
|
[](http://travis-ci.org/byroot/frozen_record)
|
4
|
-
[](https://codeclimate.com/github/byroot/frozen_record)
|
5
|
-
[](https://coveralls.io/r/byroot/frozen_record)
|
6
4
|
[](http://badge.fury.io/rb/frozen_record)
|
7
5
|
|
8
6
|
ActiveRecord-like interface for **read only** access to static data files.
|
data/benchmark/querying
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative 'setup'
|
5
|
+
|
6
|
+
records = FrozenRecord::Backends::Yaml.load(Country.file_path)
|
7
|
+
large_records = 100.times.flat_map do |i|
|
8
|
+
records.map do |record|
|
9
|
+
new_record = record.dup
|
10
|
+
new_record['id'] += 10 * i
|
11
|
+
new_record['name'] += i.to_s
|
12
|
+
new_record
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
File.write('/tmp/frozen-record-bench-countries.yml', YAML.dump(large_records))
|
17
|
+
|
18
|
+
class LargeCountry < Country
|
19
|
+
class << self
|
20
|
+
def file_path
|
21
|
+
'/tmp/frozen-record-bench-countries.yml'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
puts "=== simple scalar match ==="
|
27
|
+
Benchmark.ips do |x|
|
28
|
+
x.report('simple') { LargeCountry.nato.size }
|
29
|
+
end
|
30
|
+
|
31
|
+
puts "=== range match ==="
|
32
|
+
Benchmark.ips do |x|
|
33
|
+
x.report('range') { LargeCountry.where(density: 100...200).size }
|
34
|
+
end
|
data/frozen_record.gemspec
CHANGED
data/lib/frozen_record/base.rb
CHANGED
@@ -83,8 +83,9 @@ module FrozenRecord
|
|
83
83
|
store[:scope] = scope
|
84
84
|
end
|
85
85
|
|
86
|
-
delegate :find, :find_by_id, :find_by, :find_by!, :where, :first, :first!, :last, :last!,
|
87
|
-
:minimum, :maximum, :average, :sum, :count,
|
86
|
+
delegate :each, :find, :find_each, :find_by_id, :find_by, :find_by!, :where, :first, :first!, :last, :last!,
|
87
|
+
:pluck, :ids, :order, :limit, :offset, :minimum, :maximum, :average, :sum, :count,
|
88
|
+
to: :current_scope
|
88
89
|
|
89
90
|
def file_path
|
90
91
|
raise ArgumentError, "You must define `#{name}.base_path`" unless base_path
|
@@ -200,7 +201,9 @@ module FrozenRecord
|
|
200
201
|
def list_attributes(records)
|
201
202
|
attributes = Set.new
|
202
203
|
records.each do |record|
|
203
|
-
|
204
|
+
record.each_key do |key|
|
205
|
+
attributes.add(key)
|
206
|
+
end
|
204
207
|
end
|
205
208
|
attributes
|
206
209
|
end
|
data/lib/frozen_record/index.rb
CHANGED
@@ -19,12 +19,11 @@ module FrozenRecord
|
|
19
19
|
false
|
20
20
|
end
|
21
21
|
|
22
|
-
def query(
|
23
|
-
|
24
|
-
|
25
|
-
lookup_multi(value)
|
22
|
+
def query(matcher)
|
23
|
+
if matcher.ranged?
|
24
|
+
lookup_multi(matcher.value)
|
26
25
|
else
|
27
|
-
lookup(value)
|
26
|
+
lookup(matcher.value)
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
data/lib/frozen_record/scope.rb
CHANGED
@@ -9,6 +9,7 @@ module FrozenRecord
|
|
9
9
|
].to_set
|
10
10
|
|
11
11
|
delegate :first, :last, :length, :collect, :map, :each, :all?, :include?, :to_ary, :to_json, :as_json, :count, to: :to_a
|
12
|
+
alias_method :find_each, :each
|
12
13
|
if defined? ActiveModel::Serializers::Xml
|
13
14
|
delegate :to_xml, to: :to_a
|
14
15
|
end
|
@@ -187,8 +188,8 @@ module FrozenRecord
|
|
187
188
|
end
|
188
189
|
|
189
190
|
records.select do |record|
|
190
|
-
unindexed_where_values.all? { |attr,
|
191
|
-
!@where_not_values.any? { |attr,
|
191
|
+
unindexed_where_values.all? { |attr, matcher| matcher.match?(record[attr]) } &&
|
192
|
+
!@where_not_values.any? { |attr, matcher| matcher.match?(record[attr]) }
|
192
193
|
end
|
193
194
|
end
|
194
195
|
|
@@ -238,12 +239,12 @@ module FrozenRecord
|
|
238
239
|
end
|
239
240
|
|
240
241
|
def where!(criterias)
|
241
|
-
@where_values += criterias.map { |k, v| [k.to_s, v] }
|
242
|
+
@where_values += criterias.map { |k, v| [k.to_s, Matcher.for(v)] }
|
242
243
|
self
|
243
244
|
end
|
244
245
|
|
245
246
|
def where_not!(criterias)
|
246
|
-
@where_not_values += criterias.map { |k, v| [k.to_s, v] }
|
247
|
+
@where_not_values += criterias.map { |k, v| [k.to_s, Matcher.for(v)] }
|
247
248
|
self
|
248
249
|
end
|
249
250
|
|
@@ -266,9 +267,62 @@ module FrozenRecord
|
|
266
267
|
|
267
268
|
private
|
268
269
|
|
269
|
-
|
270
|
-
|
271
|
-
|
270
|
+
class Matcher
|
271
|
+
class << self
|
272
|
+
def for(value)
|
273
|
+
case value
|
274
|
+
when Array
|
275
|
+
IncludeMatcher.new(value)
|
276
|
+
when Range
|
277
|
+
CoverMatcher.new(value)
|
278
|
+
else
|
279
|
+
new(value)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
attr_reader :value
|
285
|
+
|
286
|
+
def hash
|
287
|
+
self.class.hash ^ value.hash
|
288
|
+
end
|
289
|
+
|
290
|
+
def initialize(value)
|
291
|
+
@value = value
|
292
|
+
end
|
293
|
+
|
294
|
+
def ranged?
|
295
|
+
false
|
296
|
+
end
|
297
|
+
|
298
|
+
def match?(other)
|
299
|
+
@value == other
|
300
|
+
end
|
301
|
+
|
302
|
+
def ==(other)
|
303
|
+
self.class == other.class && value == other.value
|
304
|
+
end
|
305
|
+
alias_method :eql?, :==
|
306
|
+
end
|
307
|
+
|
308
|
+
class IncludeMatcher < Matcher
|
309
|
+
def ranged?
|
310
|
+
true
|
311
|
+
end
|
312
|
+
|
313
|
+
def match?(other)
|
314
|
+
@value.include?(other)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
class CoverMatcher < Matcher
|
319
|
+
def ranged?
|
320
|
+
true
|
321
|
+
end
|
322
|
+
|
323
|
+
def match?(other)
|
324
|
+
@value.cover?(other)
|
325
|
+
end
|
272
326
|
end
|
273
327
|
end
|
274
328
|
end
|
data/spec/frozen_record_spec.rb
CHANGED
@@ -90,6 +90,32 @@ RSpec.shared_examples 'main' do
|
|
90
90
|
|
91
91
|
end
|
92
92
|
|
93
|
+
describe '.each' do
|
94
|
+
|
95
|
+
it 'yields the records one by one' do
|
96
|
+
count = 0
|
97
|
+
Country.each do |country|
|
98
|
+
expect(country).to be_a Country
|
99
|
+
count += 1
|
100
|
+
end
|
101
|
+
expect(count).to be == Country.count
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '.find_each' do
|
107
|
+
|
108
|
+
it 'yields the records one by one' do
|
109
|
+
count = 0
|
110
|
+
Country.find_each do |country|
|
111
|
+
expect(country).to be_a Country
|
112
|
+
count += 1
|
113
|
+
end
|
114
|
+
expect(count).to be == Country.count
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
93
119
|
describe '.memsize' do
|
94
120
|
|
95
121
|
it 'retuns the records memory footprint' do
|
data/spec/scope_spec.rb
CHANGED
@@ -180,6 +180,20 @@ describe 'querying' do
|
|
180
180
|
|
181
181
|
end
|
182
182
|
|
183
|
+
describe '.find_each' do
|
184
|
+
|
185
|
+
it 'yields the records one by one' do
|
186
|
+
scope = Country.where(name: 'France')
|
187
|
+
count = 0
|
188
|
+
scope.find_each do |country|
|
189
|
+
expect(country).to be_a Country
|
190
|
+
count += 1
|
191
|
+
end
|
192
|
+
expect(count).to be == 1
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
183
197
|
describe '.where' do
|
184
198
|
|
185
199
|
it 'returns the records that match given criterias' do
|
@@ -445,8 +459,8 @@ describe 'querying' do
|
|
445
459
|
it 'returns true when the same scope has be rechained' do
|
446
460
|
scope_a = Country.nato.republics.nato.republics
|
447
461
|
scope_b = Country.republics.nato
|
448
|
-
expect(scope_a.instance_variable_get(:@where_values)).to be == [['nato', true], ['king', nil], ['nato', true], ['king', nil]]
|
449
|
-
expect(scope_b.instance_variable_get(:@where_values)).to be == [['king', nil], ['nato', true]]
|
462
|
+
expect(scope_a.instance_variable_get(:@where_values).map { |k, v| [k, v.value] }).to be == [['nato', true], ['king', nil], ['nato', true], ['king', nil]]
|
463
|
+
expect(scope_b.instance_variable_get(:@where_values).map { |k, v| [k, v.value] }).to be == [['king', nil], ['nato', true]]
|
450
464
|
expect(scope_a).to be == scope_b
|
451
465
|
end
|
452
466
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,16 +2,6 @@ lib = File.expand_path('../lib', __FILE__)
|
|
2
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
3
|
|
4
4
|
minimal = ENV['MINIMAL'] == 'true'
|
5
|
-
|
6
|
-
require 'pry'
|
7
|
-
require 'simplecov'
|
8
|
-
require 'coveralls'
|
9
|
-
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
10
|
-
SimpleCov::Formatter::HTMLFormatter,
|
11
|
-
Coveralls::SimpleCov::Formatter
|
12
|
-
]
|
13
|
-
SimpleCov.start
|
14
|
-
|
15
5
|
require 'objspace'
|
16
6
|
|
17
7
|
if minimal
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: frozen_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.22.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean Boussier
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-04-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -66,34 +66,6 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: pry
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: coveralls
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
69
|
description:
|
98
70
|
email:
|
99
71
|
- jean.boussier@gmail.com
|
@@ -110,6 +82,7 @@ files:
|
|
110
82
|
- Rakefile
|
111
83
|
- benchmark/attribute-read
|
112
84
|
- benchmark/memory-usage
|
85
|
+
- benchmark/querying
|
113
86
|
- benchmark/setup.rb
|
114
87
|
- frozen_record.gemspec
|
115
88
|
- lib/frozen_record.rb
|