poros 0.2.3 → 0.3.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
  SHA256:
3
- metadata.gz: cb33cb3edeb46a15e44bb915e71420a9c92ed99234ee52ab3d083b2e963b9807
4
- data.tar.gz: 503c54369c8579a4a0d7fa41a2ae5bdb3cbdd59e8b4a4c999ad531d104858825
3
+ metadata.gz: 6dc1a45e91216abe73208b6c54926ad645e00217ac26c1ee829afc4b75bd279a
4
+ data.tar.gz: b0eae29db2cba9dfe71dc4d830bbba43c41ff2ea8cb6a6d4c89328f4ce2d450b
5
5
  SHA512:
6
- metadata.gz: 02f0e7d5fbb462f9e4e29595c8d2e22fc775410b4b7782e1db43c787f078c4b8b07c61ebb2b57c4ea35215a4f1074faadc1bdbd297be29dd409f493c5a5bf31b
7
- data.tar.gz: 95c434c7a70309d7bf2181dfbee83c9e0856969bff04051353b8b06c1c0391768e7802e3fe37457b712893b7950af959f75e7f0a75b1cfb866ccfc92fb256752
6
+ metadata.gz: c26f6f28c9324df4cd0be12b514ee967486e3a80a6fa051b0682099b77fdaa50ae77720aa698af07dcd4c789593ddddd32e0d9cb0d926e8cd1314fc1a3a57834
7
+ data.tar.gz: 3c04c87297694078d97ec8b29c98d440ce0e5c0274791899bab06ac859d5638b671b1b3b94d33b0177471367a2ec76c74fa234fb7cc2fbac3327fcd6df38c293
data/README.md CHANGED
@@ -52,9 +52,9 @@ many_widgets = Widget.where(order: 1, name: /regex/)
52
52
  attributes defined in `poro_attr`. In the future I may define this function for
53
53
  you but for right now I'm not sure I want to go that direction.
54
54
 
55
- `poro_attrs :blah` will define a getter and setter for `:blah` and also be persisted when you run `#save`
55
+ `poro_attr :blah` will define a getter and setter for `:blah` and also be persisted when you run `#save`
56
56
 
57
- `poro_indexes :blah` will create indexes on these columns, this will greatly
57
+ `poro_index :blah` will create indexes on these columns, this will greatly
58
58
  speed up searching but if your index gets really big the initial load of a
59
59
  model will take quite a long time.
60
60
 
@@ -62,8 +62,7 @@ model will take quite a long time.
62
62
  save to the default of `./db/#{self}`. If you do re-define it you _must_
63
63
  seperate each model into it's own folder or it will have _lots_ of issues.
64
64
 
65
- `.where` acts a bit like ActiveRecord but it's not currently chainable (I plan
66
- to do that in the future though) and takes exact matches, regexs, arrays, or
65
+ `.where` acts a bit like ActiveRecord and it takes exact matches, regexs, arrays, or
67
66
  lambdas in any combination.
68
67
 
69
68
  ```ruby
@@ -72,15 +71,52 @@ Widget.where(name: 'sprocket')
72
71
  Widget.where(name: /spr.*cket/)
73
72
  Widget.where(order: -> value { value > 3 })
74
73
  Widget.where(order: [1, 5, 8], active: true)
74
+ Widget.where(order: 1).where(name: 'cog')
75
75
 
76
76
  # Invalid examples
77
77
  Widget.where(name: 'sprocket', name: 'cog') # can't check same value twice, use arrays
78
- Widget.where(order: 1).where(name: 'cog') # can't chain wheres
79
78
  ```
80
79
 
81
-
82
80
  `.find` takes the `#uuid` which is generated by Poros and returns the single record.
83
81
 
82
+ A basic usage of relations would be something like:
83
+
84
+ ```ruby
85
+ class Author
86
+ include Poros
87
+
88
+ poro_attr :name
89
+
90
+ has_many :books
91
+
92
+ def initialize(name: '')
93
+ @name = name
94
+ end
95
+ end
96
+
97
+ class Book
98
+ include Poros
99
+
100
+ poro_attr :title, :author_uuid
101
+
102
+ belongs_to :author
103
+
104
+ def initialize(title: '', author: nil, author_uuid: nil)
105
+ @title = title
106
+ @author_uuid = author_uuid if author_uuid
107
+ self.author = author if author
108
+ end
109
+ end
110
+
111
+ audrey_niffenegger = Author.new(name: 'Audrey Niffenegger').save
112
+ john_steinbeck = Author.new(name: 'John Steinbeck').save
113
+ book_1 = Book.new(title: 'The Grapes of Wrath', author_uuid: john_steinbeck.uuid).save
114
+ book_2 = Book.new(title: 'The Time Traveler\'s Wife', author_uuid: audrey_niffenegger.uuid).save
115
+ book_3 = Book.new(title: 'Of Mice and Men', author_uuid: john_steinbeck.uuid).save
116
+ ```
117
+
118
+ And then you'll be able to do things like `author_2.books.where(name: /wrath/)` or `book_2.author`
119
+
84
120
  ## Development
85
121
 
86
122
  After checking out the repo, run `bundle install` to install dependencies. Then, run
@@ -57,54 +57,7 @@ module Poros
57
57
  end
58
58
 
59
59
  def where(query)
60
- indexed, table_scan = query.partition { |index, key| poro_indexes.include?(index) }
61
-
62
- indexed_results = indexed.map { |key, value|
63
- case value
64
- when Regexp
65
- index_data[key].keys.flat_map { |value_name|
66
- index_data[key][value_name] if value =~ value_name
67
- }.compact
68
- when Array
69
- value.flat_map { |value_name| index_data[key][value_name] }
70
- when Proc
71
- index_data[key].keys.flat_map { |value_name|
72
- index_data[key][value_name] if value.call(value_name)
73
- }.compact
74
- else
75
- index_data[key].has_key?(value) ?
76
- index_data[key][value] : []
77
- end
78
- }.inject(:&)
79
-
80
- if table_scan.size > 0
81
- scanned_results = Dir.glob(File.join(data_directory, '*.yml')).map { |file|
82
- next if file == index_file
83
- data = YAML.load(File.read(file))
84
- data[:uuid] if table_scan.all? { |key, value|
85
- case value
86
- when Regexp
87
- value =~ data[key]
88
- when Array
89
- value.include?(data[key])
90
- when Proc
91
- value.call(data[key])
92
- else
93
- data[key] == value
94
- end
95
- }
96
- }.compact
97
- end
98
-
99
- if indexed.size > 0 && table_scan.size > 0
100
- results = indexed_results & scanned_results
101
- elsif indexed.size > 0
102
- results = indexed_results
103
- else
104
- results = scanned_results
105
- end
106
-
107
- results.map { |uuid| find(uuid) }
60
+ Poros::Query.new(self).where(query)
108
61
  end
109
62
 
110
63
  def index_data
@@ -23,5 +23,9 @@ module Poros
23
23
  self.class.update_index(self)
24
24
  self
25
25
  end
26
+
27
+ def ==(other)
28
+ uuid == other.uuid
29
+ end
26
30
  end
27
31
  end
@@ -0,0 +1,71 @@
1
+ module Poros
2
+ class Query
3
+ include Enumerable
4
+ attr_accessor :object, :queries
5
+
6
+ def initialize(object)
7
+ @object = object
8
+ @queries = {}
9
+ end
10
+
11
+ def where(query)
12
+ @queries.merge!(query)
13
+ self
14
+ end
15
+
16
+ def each(&block)
17
+ results.each { |result| block.call(result) }
18
+ end
19
+
20
+ def results
21
+ indexed, table_scan = @queries.partition { |index, key| @object.poro_indexes.include?(index) }
22
+
23
+ indexed_results = indexed.map { |key, value|
24
+ case value
25
+ when Regexp
26
+ @object.index_data[key].keys.flat_map { |value_name|
27
+ @object.index_data[key][value_name] if value =~ value_name
28
+ }.compact
29
+ when Array
30
+ value.flat_map { |value_name| @object.index_data[key][value_name] }
31
+ when Proc
32
+ @object.index_data[key].keys.flat_map { |value_name|
33
+ @object.index_data[key][value_name] if value.call(value_name)
34
+ }.compact
35
+ else
36
+ @object.index_data[key].has_key?(value) ?
37
+ @object.index_data[key][value] : []
38
+ end
39
+ }.inject(:&)
40
+
41
+ if table_scan.size > 0
42
+ scanned_results = Dir.glob(File.join(@object.data_directory, '*.yml')).map { |file|
43
+ next if file == @object.index_file
44
+ data = YAML.load(File.read(file))
45
+ data[:uuid] if table_scan.all? { |key, value|
46
+ case value
47
+ when Regexp
48
+ value =~ data[key]
49
+ when Array
50
+ value.include?(data[key])
51
+ when Proc
52
+ value.call(data[key])
53
+ else
54
+ data[key] == value
55
+ end
56
+ }
57
+ }.compact
58
+ end
59
+
60
+ if indexed.size > 0 && table_scan.size > 0
61
+ results = indexed_results & scanned_results
62
+ elsif indexed.size > 0
63
+ results = indexed_results
64
+ else
65
+ results = scanned_results
66
+ end
67
+
68
+ results.map { |uuid| @object.find(uuid) }
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,55 @@
1
+ module Poros
2
+ module Relations
3
+ def has_many(key, class_name: nil, foreign_key: nil, primary_key: :uuid)
4
+
5
+ define_method key do
6
+ foreign_key = (foreign_key || self.class.to_s.downcase + '_uuid').to_sym
7
+ object = constantize(singularize(class_name || key))
8
+ primary_value = self.send(primary_key)
9
+
10
+ object.where(foreign_key => primary_value)
11
+ end
12
+ end
13
+
14
+ def belongs_to(key, class_name: nil, foreign_key: nil, primary_key: :uuid)
15
+ define_method key do
16
+ object = constantize(class_name || key)
17
+ foreign_method = (foreign_key || (key.to_s + '_uuid')).to_sym
18
+ primary_attr = primary_key || (key.to_s + '_uuid')
19
+
20
+ object.where(primary_attr => self.send(foreign_method)).first
21
+ end
22
+
23
+ define_method key.to_s + '=' do |value|
24
+ foreign_attr = foreign_key || (key.to_s + '_uuid=')
25
+ primary_method = primary_key || (key.to_s + '_uuid')
26
+
27
+ self.send(foreign_attr, value.send(primary_method))
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def singularize(word)
34
+ # I don't want to depend on rails or another gem so I'm doing something
35
+ # incredibly basic that'll work 90+% of the time (for English anyways).
36
+ case word.to_s
37
+ when /ies$/
38
+ word.to_s.chomp('ies') + 'y'
39
+ when /s$/
40
+ word.to_s.chomp('s')
41
+ else
42
+ word.to_s
43
+ end
44
+ end
45
+
46
+ def constantize(word)
47
+ object_name = word
48
+ if word.downcase == word
49
+ object_name = word.to_s.split('_').map(&:capitalize).join
50
+ end
51
+
52
+ Object.const_get(object_name)
53
+ end
54
+ end
55
+ end
data/lib/poros/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Poros
2
- VERSION = "0.2.3"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/poros.rb CHANGED
@@ -1,16 +1,20 @@
1
1
  require 'yaml'
2
2
  require 'securerandom'
3
3
 
4
+ require 'poros/query'
4
5
  require 'poros/instance_methods'
5
6
  require 'poros/class_methods'
7
+ require 'poros/relations'
6
8
 
7
9
  module Poros
8
10
  include Poros::InstanceMethods
9
11
  include Poros::ClassMethods
12
+ include Poros::Relations
10
13
 
11
14
  def self.included(base)
12
15
  base.class_eval do
13
16
  extend ClassMethods
17
+ extend Relations
14
18
  end
15
19
  end
16
20
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: poros
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Ross Earle
@@ -69,6 +69,8 @@ files:
69
69
  - lib/poros/class_methods.rb
70
70
  - lib/poros/info.rb
71
71
  - lib/poros/instance_methods.rb
72
+ - lib/poros/query.rb
73
+ - lib/poros/relations.rb
72
74
  - lib/poros/version.rb
73
75
  - poros.gemspec
74
76
  homepage: https://github.com/HellRok/YAMLCache