greyscale_record 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: '04649514246f75d5ecd1d02fba8b1b773744d771'
4
- data.tar.gz: de857e40fabfa2d27622f7f6957eed6b9602b5f3
3
+ metadata.gz: e182b351304fb45824511ff704bae0fb071aea01
4
+ data.tar.gz: 147b67b9aca64b01243585e57cd21d11303a83ca
5
5
  SHA512:
6
- metadata.gz: eb2a45fc827f0e4e1f5ea48bfd0589c1d3e9c73cf605330bc8c50e18188723759425a72d6c88bedf8b9adc9b40c33f086d36fe1b58a923f47e26f87824e95b8f
7
- data.tar.gz: d218efe8bda685f876c4526bc58bdafaaa8b56624901225abe9a3e74c0bccd75a9970579503869837dffc78e335413da269ab0081d0c89b8136868b7c9ced85d
6
+ metadata.gz: fcd11e5ee95ec0f0630e32b65b20c5e9b01af69b2903aeb481b583ed4687de64b350d14b28b6d6e6f9d8c0d67113115715c847a610546a1fa61bb3ce7a36cdf2
7
+ data.tar.gz: da33bc49c25147f838485b784a843bbba247243b2f20c5af1eac74cef47af4cd7af556a5a9541d983fa40d0b8f116e0f39ae4693ca4ae63ea3db11becc58e080
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Greyscale Record
2
2
 
3
- `GreyscaleRecord` is a simple read-only implementation of [YamlRecord](https://github.com/nicotaing/yaml_record). It's designed for users whose data is perfectly static and is stored in a flat file format (e.g. yaml files). It is a clone of [YamlBSides](https://github.com/gaorlov/yaml_b_sides), but is extended to support multiple backend drivers (YAML files, Greyscale API)
3
+ `GreyscaleRecord` is a flat-file ORM, designed for users whose data is perfectly static and is stored in a flat format (e.g. yaml files). It is a clone of [YamlBSides](https://github.com/gaorlov/yaml_b_sides), but is extended to support multiple backend drivers (YAML files, JSON APIs)
4
4
 
5
5
  ## Installation
6
6
 
@@ -46,12 +46,6 @@ Note: `Greyscale Record` expects your class names to match the fixture names (e.
46
46
 
47
47
  Your `Person` class now responds to
48
48
 
49
- ### Query Methods
50
-
51
- * `all` : will give you all of the records in the table
52
- * `first` : wil return the first record in the table
53
- * `find( id )` : will find a single record with the specified yaml key
54
- * `find_by( properties = {} )` : will find all the recored that match all the proerties in the hash
55
49
 
56
50
  ### Indexing
57
51
 
@@ -153,6 +147,82 @@ Associations have some of the standard ActiveRecord options. Namely:
153
147
  #...
154
148
  ```
155
149
 
150
+ ### Query Methods
151
+
152
+ * `all` : will give you all of the records in the table
153
+ * `first` : wil return the first record in the table
154
+ * `find( id )` : will find a single record with the specified yaml key
155
+ * `find_by( properties = {} )` : will find all the recored that match all the proerties in the hash
156
+
157
+ #### Relation methods
158
+
159
+ These act as you would expect them to in ActiveRecord. These can be chained and applied to associations
160
+ * `where( params )` : will return a relation which can be interacted with as if it were the resulting array
161
+ * `and( params )` : identical to `where`, but nicer to read
162
+
163
+ ```ruby
164
+ Person.where( url_slug: "greg" ) #=> [<Person>]
165
+ Person.where( url_slug: "greg", name: "Greg Orlov" ).and( id: "greg") #=> [<Person>]
166
+ Person.where( url_slug: "greg", name: "Greg Orlov" ).where( id: "greg") #=> [<Person>]
167
+ # from the code above
168
+ Person.first.images.where( some_property: "value" )
169
+ ```
170
+
171
+ ### Data Sourcing
172
+
173
+ As mentioned in the summary above, `GreyscaleRecord` can be connected to different data sources. The structure that we use is a `Driver`.
174
+ There is a built in driver to use as an example: Yaml Driver. This is the structure that controls data flow from the original data store,
175
+ such as YAML files or an API, and formats it to be consumed by the internal `GreyscaleRecord::DataStore::Store` object, which expects the
176
+ result set to look roughly like
177
+
178
+ ```
179
+ { table_name: {
180
+ record_id: { attribute: value, ... },
181
+ ...
182
+ },
183
+ ...
184
+ }
185
+ ```
186
+
187
+ `GreyscaleRecord` will populate the id field for you from the record keys.
188
+
189
+ ### Data Patching
190
+
191
+ If you have a data set that you want to temporarily augment, you can apply a [JSON patch](http://jsonpatch.com/) to the data store.
192
+ This will apply the patch within the context of your current thread until it is removed
193
+
194
+ ```ruby
195
+ patch = ::Hana::Patch.new [ { 'op' => 'add', 'path' => '/people/mike', 'value' => { id: "mike", name: "Mike Uchman" } } ]
196
+
197
+ # this will stick around indefinitely in this thread
198
+ data_store.apply_patch patch
199
+
200
+ Person.find( 'mike' ).name # => "Mike Uchman"
201
+ Person.where( id: 'mike' ).first.name #=> "Mike Uchman"
202
+
203
+ # let's go back to the original set
204
+ data_store.remove_patch
205
+
206
+ Person.where( id: "mike" ) #=> []
207
+ ```
208
+
209
+ Or, if you are doing something simple and can fir your code in a single block, you can do:
210
+
211
+ ```ruby
212
+ data_store.with_patch patch do
213
+
214
+ Person.find( 'mike' ).name # => "Mike Uchman"
215
+ Person.where( id: 'mike' ).first.name #=> "Mike Uchman"
216
+
217
+ end
218
+
219
+ Person.where( id: "mike" ) #=> []
220
+ ```
221
+
222
+ __NOTE__: The patch interface that `Store` expects is that of [Hana](https://github.com/tenderlove/hana). You don't have to use it, but it has
223
+ to respond to `patch.apply( doc )`.
224
+
225
+
156
226
  ### Example
157
227
 
158
228
  To use the `People` class from earlier, a fully fleshed out model would look something like:
@@ -198,8 +268,8 @@ The setup is pretty straightforward. Greyscale Record wants a logger and a base
198
268
  ```ruby
199
269
  GreyscaleRecord::logger = Rails.logger
200
270
  # for now this is the only driver
201
- GreyscaleRecord::Base.driver = GreyscaleRecord::Drivers::Yaml
202
- GreyscaleRecord::Drivers::Yaml.root = Rails.root.join 'db', 'fixtures'
271
+ yaml_driver = GreyscaleRecord::Drivers::Yaml.new File.expand_path("./db/fixtures", File.dirname(__FILE__))
272
+ GreyscaleRecord::Base.data_store = GreyscaleRecord::DataStore::Engine.new(yaml_driver)
203
273
 
204
274
 
205
275
  # in development.rb
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # coding: utf-8
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'greyscale_record/version'
@@ -30,5 +30,5 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency "minitest", "~> 5.0"
31
31
  spec.add_development_dependency "simplecov"
32
32
  spec.add_development_dependency "m"
33
-
33
+ spec.add_development_dependency "hana"
34
34
  end
@@ -8,40 +8,20 @@ module GreyscaleRecord
8
8
  include Instanceable
9
9
  include Queriable
10
10
 
11
- class_attribute :data
12
- class_attribute :driver
11
+ class_attribute :data_store
13
12
 
14
13
  class << self
15
14
 
16
15
  def load!
17
- @data = driver.load!(_class_name)
18
- return unless @data
19
-
20
- # let's preemptively index by id so that when we do a find_by id:, or a where id: it won't table scan
21
- idify_data!
22
-
23
- index :id unless GreyscaleRecord.live_reload
16
+ data_store.add_table name
24
17
  end
25
18
 
26
19
  def inherited(subclass)
27
20
  subclass.load!
28
21
  end
29
22
 
30
- protected
31
-
32
- def _class_name
33
- self.name.pluralize.downcase
34
- end
35
-
36
- def idify_data!
37
- @data.each do |k, v|
38
- v[:id] = k
39
- end
40
- end
41
-
42
- def data
43
- load! if GreyscaleRecord.live_reload
44
- @data
23
+ def name
24
+ self.to_s.pluralize.downcase
45
25
  end
46
26
  end
47
27
  end
@@ -5,7 +5,7 @@ module GreyscaleRecord
5
5
  included do
6
6
  class << self
7
7
  def cache_key
8
- @cache_key ||= Digest::SHA256.hexdigest(data.to_json)
8
+ @cache_key ||= Digest::SHA256.hexdigest(all.to_json)
9
9
  end
10
10
  end
11
11
 
@@ -0,0 +1,66 @@
1
+ module GreyscaleRecord
2
+ module DataStore
3
+ class Engine
4
+
5
+ # A data store can only have one driver.
6
+ # It's like a database connection. If you want models to connect to different
7
+ # databases, you have them inherit from different base classes that specify
8
+ # a db to connect to.
9
+
10
+ # Pros:
11
+ # * All the data in your store comes from the same place. Easy to reason about
12
+ # * No chance of data source collisions. Can't populate tables from multiple sources
13
+ # * Cleaner table-adding interface
14
+ # store.add_table( name )
15
+ # vs
16
+ # store.add_table( name, driver )
17
+ # # where does driver get initialized?
18
+ # * Straight forward patching: one complete patch at a time
19
+ # How do you patch across differntly driven tables?
20
+ # Do you need a patch stack?
21
+ # * Depending on how your remote is built, you can pull in all the data at once
22
+ #
23
+ # Cons:
24
+ # * Limiting if you want to have some tables come from YAML and some from remote
25
+ #
26
+ # Yeah. OK.
27
+
28
+ delegate :apply_patch, :remove_patch, :with_patch, :table, to: :store
29
+
30
+ def initialize( driver )
31
+ @driver = driver
32
+ @store = Store.new
33
+ end
34
+
35
+ # Read only store. No writes allowed.
36
+
37
+ def find( options = {} )
38
+ table = store.table( options.delete(:_table) )
39
+ if GreyscaleRecord.live_reload
40
+ load_table!( table )
41
+ end
42
+
43
+ # TODO: this is where all the meat is
44
+ table.find options
45
+ end
46
+
47
+ def add_table( name )
48
+ load_table! name
49
+ end
50
+
51
+ def add_index( name, column )
52
+ store.table( name ).add_index( column )
53
+ end
54
+
55
+ private
56
+
57
+ def store
58
+ @store
59
+ end
60
+
61
+ def load_table!( name )
62
+ store.init_table name, @driver.load!( name )
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,25 @@
1
+ module GreyscaleRecord
2
+ module DataStore
3
+ class Index
4
+ def initialize(field, data)
5
+ @indexed_data = {}
6
+ data.each do |id, datum|
7
+ key = datum[field]
8
+
9
+ # storing key => array of matching ids
10
+ @indexed_data[key] = Array(@indexed_data[key]) + [id]
11
+ end
12
+ end
13
+
14
+ # returns ids
15
+ def find(values)
16
+ # find all the arrays of ids for the values,
17
+ # get rid of nils (value not present),
18
+ # and compact for a single array result
19
+ values.map do |value|
20
+ @indexed_data[value]
21
+ end.compact.flatten
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,72 @@
1
+ module GreyscaleRecord
2
+ module DataStore
3
+ class Store
4
+ def initialize
5
+ @data = {}
6
+ @tables = {}
7
+ end
8
+
9
+ def []( name )
10
+ data[ name ]
11
+ end
12
+
13
+ def table( name )
14
+ unless @tables[name]
15
+ raise GreyscaleRecord::Errors::DataStoreError, "Data Store error: table '#{name}' does not exist"
16
+ end
17
+
18
+ @tables[name]
19
+ end
20
+
21
+ def init_table( name, rows )
22
+ @data[name] = rows
23
+ @tables[name] = Table.new( name, self )
24
+ end
25
+
26
+ def with_patch( patch )
27
+ apply_patch patch
28
+ yield
29
+ remove_patch
30
+ end
31
+
32
+ # This only allows for one patch at a time.
33
+ # Is there ever a case when we would need, like a stack of these things?
34
+ # I don't think so?
35
+
36
+ def apply_patch( patch )
37
+ Thread.current[patch_key] = patched_data patch
38
+ end
39
+
40
+ def remove_patch
41
+ Thread.current[patch_key] = nil
42
+ end
43
+
44
+ def patched?
45
+ Thread.current[patch_key].present?
46
+ end
47
+
48
+ private
49
+
50
+ def patched_data(patch)
51
+ unless patch.respond_to? :apply
52
+ raise GreyscaleRecord::Errors::DataStoreError, "Data Store Error: apply_patch: patch must respond to 'apply(doc)'."
53
+ end
54
+
55
+ patch.apply( @data.deep_dup )
56
+ end
57
+
58
+ def patch_key
59
+ @key ||= "#{object_id}_patch"
60
+ end
61
+
62
+
63
+ def data
64
+ if patched?
65
+ Thread.current[patch_key]
66
+ else
67
+ @data
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,80 @@
1
+ module GreyscaleRecord
2
+ module DataStore
3
+ class Table
4
+
5
+ def initialize(name, store)
6
+ @name = name
7
+ @store = store
8
+
9
+ # initialize the index array for later use
10
+ @indices = {}
11
+
12
+ # generate IDs for the records based on YAML keys
13
+ generate_ids!
14
+
15
+ # preemptively index the IDs
16
+ add_index :id
17
+ end
18
+
19
+ def all
20
+ rows.values
21
+ end
22
+
23
+ def add_index( column )
24
+ return if @store.patched?
25
+ @indices = @indices.merge( { column => Index.new(column, rows) } )
26
+ end
27
+
28
+ def find( params = {} )
29
+ return all if params.empty?
30
+ sets = params.map do | column, values |
31
+ if !patched? && indexed?( column )
32
+ find_in_index column, values
33
+ else
34
+ GreyscaleRecord.logger.warn "You are running a query on #{@name}.#{column} which is not indexed. This will perform a table scan."
35
+ find_in_column column, values
36
+ end
37
+ end
38
+
39
+ sets.inject( sets.first ) do |result, subset|
40
+ result & subset
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def rows
47
+ @store[@name]
48
+ end
49
+
50
+ def patched?
51
+ @store.patched?
52
+ end
53
+
54
+ def indexed?(column)
55
+ @indices[column].present?
56
+ end
57
+
58
+ def find_in_column( column, values )
59
+ rows.values.select do |datum|
60
+ Array( values ).include? datum[ column ]
61
+ end
62
+ end
63
+
64
+ def find_in_index( column, values )
65
+ keys = @indices[column].find( Array( values ) )
66
+
67
+ keys.map do |id|
68
+ rows[id]
69
+ end
70
+ end
71
+
72
+ def generate_ids!
73
+ # init IDs
74
+ rows.each do |k, v|
75
+ v[:id] = k
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,8 @@
1
+ module GreyscaleRecord
2
+ module DataStore
3
+ autoload :Engine, 'greyscale_record/data_store/engine'
4
+ autoload :Index, 'greyscale_record/data_store/index'
5
+ autoload :Store, 'greyscale_record/data_store/store'
6
+ autoload :Table, 'greyscale_record/data_store/table'
7
+ end
8
+ end
@@ -2,29 +2,31 @@ module GreyscaleRecord
2
2
  module Drivers
3
3
  class Base
4
4
 
5
- class_attribute :root
5
+ attr_reader :root
6
+
7
+ def initialize( root )
8
+ @root = root
9
+ end
6
10
 
7
- class << self
8
- def load!(class_name)
11
+ def load!(object)
9
12
 
10
- raise GreyscaleRecord::DriverError "driver needs to define a `root`" unless root
11
-
12
- data = load_data(class_name)
13
-
14
- GreyscaleRecord.logger.info "#{class_name} successfully loaded data"
13
+ raise GreyscaleRecord::Errors::DriverError, "driver needs to define a `root`" unless root
14
+
15
+ data = load_data(object)
16
+
17
+ GreyscaleRecord.logger.info "#{object} successfully loaded data"
15
18
 
16
- data
19
+ data
17
20
 
18
- rescue => e
19
- GreyscaleRecord.logger.error "#{self} failed to load data for #{class_name}: #{e}"
20
- return nil
21
- end
21
+ rescue => e
22
+ GreyscaleRecord.logger.error "#{self.class} failed to load data for #{object}: #{e}`"
23
+ {}
24
+ end
22
25
 
23
- private
26
+ private
24
27
 
25
- def load_data
26
- raise NotImplementedError "load_data is not implemented"
27
- end
28
+ def load_data
29
+ raise NotImplementedError, "load_data is not implemented"
28
30
  end
29
31
  end
30
32
  end
@@ -2,17 +2,14 @@ module GreyscaleRecord
2
2
  module Drivers
3
3
  class Yaml < Base
4
4
 
5
- class << self
5
+ private
6
6
 
7
- private
8
-
9
- def load_data( class_name )
10
- YAML.load_file( data_file( class_name ) ).with_indifferent_access
11
- end
7
+ def load_data( object )
8
+ YAML.load_file( data_file( object ) ).with_indifferent_access
9
+ end
12
10
 
13
- def data_file( class_name )
14
- [root, "#{class_name}.yml"].compact.join("/")
15
- end
11
+ def data_file( object )
12
+ [root, "#{object}.yml"].compact.join("/")
16
13
  end
17
14
  end
18
15
  end
@@ -11,5 +11,8 @@ module GreyscaleRecord
11
11
 
12
12
  class DriverError < StandardError
13
13
  end
14
+
15
+ class DataStoreError < StandardError
16
+ end
14
17
  end
15
18
  end
@@ -3,31 +3,12 @@ module GreyscaleRecord
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- class_attribute :__indices
7
- self.__indices = { }
8
-
9
6
  class << self
7
+ # DEPRICATED
8
+ # TODO: remove
10
9
  def index(field)
11
10
  return if GreyscaleRecord.live_reload
12
- self.__indices = __indices.merge( { field => Index.new(field, data) } )
13
- end
14
-
15
- def find_in_index(field, values)
16
- keys = Array(index_for(field).find(values))
17
-
18
- keys.map do |id|
19
- data[id]
20
- end
21
- end
22
-
23
- def indexed?(field)
24
- __indices[field].present?
25
- end
26
-
27
- protected
28
-
29
- def index_for(field)
30
- __indices[field]
11
+ data_store.add_index( name, field )
31
12
  end
32
13
  end
33
14
  end
@@ -5,69 +5,27 @@ module GreyscaleRecord
5
5
  included do
6
6
  class << self
7
7
  def find(id)
8
- record = data[id]
9
- raise Errors::RecordNotFound, "#{self}: Record not found: #{id}" unless record
10
- new record
8
+ records = where( id: id.to_s )
9
+ raise Errors::RecordNotFound, "#{ self }: Record not found: #{ id }" if records.empty?
10
+ records.first
11
11
  end
12
12
 
13
- def find_by(params = {})
13
+ def find_by( params = { } )
14
14
  results = where params
15
- raise Errors::RecordNotFound, "#{self}: Could not find record that matches: #{params.inspect}" if results.empty?
15
+ raise Errors::RecordNotFound, "#{ self }: Could not find record that matches: #{ params.inspect }" if results.empty?
16
16
  results.first
17
17
  end
18
18
 
19
19
  def all
20
- data.values.map do |obj|
21
- new obj
22
- end
20
+ where
23
21
  end
24
22
 
25
23
  def first
26
- new data.values.first
24
+ all.first
27
25
  end
28
26
 
29
- # TODO: move this into scopes
30
- def where(params)
31
- if all_indexed?(params.keys)
32
- results = find_by_indexed(params)
33
- else
34
- results = find_by_scan(params)
35
- end
36
- results.map do |result|
37
- new result
38
- end
39
- end
40
-
41
- private
42
-
43
- def find_by_scan(params)
44
- data.values.select do |datum|
45
- params.all? do |param, expected_value|
46
- val = Array(expected_value).include? datum[param]
47
- end
48
- end
49
- end
50
-
51
- def find_by_indexed(params)
52
- sets = []
53
- params.each do |index, values|
54
- sets << find_in_index(index, Array(values))
55
- end
56
-
57
- # find the intersection of all the sets
58
- sets.inject( sets.first ) do |result, subset|
59
- result & subset
60
- end
61
- end
62
-
63
- def all_indexed?(fields)
64
- fields.all? do |field|
65
- indexed = indexed? field
66
- unless indexed
67
- GreyscaleRecord.logger.warn "You are running a query on #{self}.#{field} which is not indexed. This will perform a table scan."
68
- end
69
- indexed
70
- end
27
+ def where( params = {} )
28
+ Relation.new self, params
71
29
  end
72
30
  end
73
31
  end
@@ -0,0 +1,29 @@
1
+ module GreyscaleRecord
2
+ class Relation
3
+
4
+ delegate :present?, :empty?, :==, to: :all
5
+
6
+ def initialize( base, params )
7
+ @base = base
8
+ @params = params.dup.merge!( _table: @base.name )
9
+ end
10
+
11
+ def where( params )
12
+ self.class.new @base, @params.merge( params )
13
+ end
14
+
15
+ def and( params )
16
+ self.class.new @base, @params.merge( params )
17
+ end
18
+
19
+ def all
20
+ @all ||= @base.data_store.find( @params.dup ).map do | result |
21
+ @base.new result
22
+ end
23
+ end
24
+
25
+ def method_missing( method, *args, &block )
26
+ all.send method, *args, &block
27
+ end
28
+ end
29
+ end
@@ -1,3 +1,3 @@
1
1
  module GreyscaleRecord
2
- VERSION = "0.0.1"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -5,6 +5,8 @@ require 'active_support'
5
5
  require 'active_support/concern'
6
6
  require 'active_support/core_ext/class/attribute'
7
7
  require 'active_support/core_ext/hash'
8
+ require 'active_support/core_ext/hash/keys'
9
+ require 'active_support/core_ext/object/deep_dup'
8
10
  require 'yaml'
9
11
 
10
12
  module GreyscaleRecord
@@ -12,13 +14,14 @@ module GreyscaleRecord
12
14
  autoload :Associations, 'greyscale_record/associations'
13
15
  autoload :Base, 'greyscale_record/base'
14
16
  autoload :Cacheable, 'greyscale_record/cacheable'
17
+ autoload :DataStore, 'greyscale_record/data_store'
15
18
  autoload :Drivers, 'greyscale_record/drivers'
16
19
  autoload :Errors, 'greyscale_record/errors'
17
20
  autoload :Instanceable, 'greyscale_record/instanceable'
18
- autoload :Index, 'greyscale_record/index'
19
21
  autoload :Indexable, 'greyscale_record/indexable'
20
22
  autoload :Propertiable, 'greyscale_record/propertiable'
21
23
  autoload :Queriable, 'greyscale_record/queriable'
24
+ autoload :Relation, 'greyscale_record/relation'
22
25
 
23
26
  class << self
24
27
  attr_accessor :live_reload
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: greyscale_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg Orlov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-06-29 00:00:00.000000000 Z
11
+ date: 2017-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: hana
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description: An ActiveRecord-like interface for reading from & queryeing flat data
112
126
  interfaces
113
127
  email:
@@ -136,15 +150,20 @@ files:
136
150
  - lib/greyscale_record/associations/hasable.rb
137
151
  - lib/greyscale_record/base.rb
138
152
  - lib/greyscale_record/cacheable.rb
153
+ - lib/greyscale_record/data_store.rb
154
+ - lib/greyscale_record/data_store/engine.rb
155
+ - lib/greyscale_record/data_store/index.rb
156
+ - lib/greyscale_record/data_store/store.rb
157
+ - lib/greyscale_record/data_store/table.rb
139
158
  - lib/greyscale_record/drivers.rb
140
159
  - lib/greyscale_record/drivers/base.rb
141
160
  - lib/greyscale_record/drivers/yaml.rb
142
161
  - lib/greyscale_record/errors.rb
143
- - lib/greyscale_record/index.rb
144
162
  - lib/greyscale_record/indexable.rb
145
163
  - lib/greyscale_record/instanceable.rb
146
164
  - lib/greyscale_record/propertiable.rb
147
165
  - lib/greyscale_record/queriable.rb
166
+ - lib/greyscale_record/relation.rb
148
167
  - lib/greyscale_record/version.rb
149
168
  homepage: https://github.com/greyscale-io/greyscale_record
150
169
  licenses:
@@ -1,23 +0,0 @@
1
- module GreyscaleRecord
2
- class Index
3
- def initialize(field, data)
4
- @indexed_data = {}
5
- data.each do |id, datum|
6
- key = datum[field]
7
-
8
- # storing key => array of matching ids
9
- @indexed_data[key] = Array(@indexed_data[key]) + [id]
10
- end
11
- end
12
-
13
- # returns ids
14
- def find(values)
15
- # find all the arrays of ids for the values,
16
- # get rid of nils (value not present),
17
- # and compact for a single array result
18
- values.map do |value|
19
- @indexed_data[value]
20
- end.compact.flatten
21
- end
22
- end
23
- end