greyscale_record 0.0.1 → 1.0.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 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