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 +4 -4
- data/README.md +42 -6
- data/lib/poros/class_methods.rb +1 -48
- data/lib/poros/instance_methods.rb +4 -0
- data/lib/poros/query.rb +71 -0
- data/lib/poros/relations.rb +55 -0
- data/lib/poros/version.rb +1 -1
- data/lib/poros.rb +4 -0
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6dc1a45e91216abe73208b6c54926ad645e00217ac26c1ee829afc4b75bd279a
|
4
|
+
data.tar.gz: b0eae29db2cba9dfe71dc4d830bbba43c41ff2ea8cb6a6d4c89328f4ce2d450b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
`
|
55
|
+
`poro_attr :blah` will define a getter and setter for `:blah` and also be persisted when you run `#save`
|
56
56
|
|
57
|
-
`
|
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
|
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
|
data/lib/poros/class_methods.rb
CHANGED
@@ -57,54 +57,7 @@ module Poros
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def where(query)
|
60
|
-
|
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
|
data/lib/poros/query.rb
ADDED
@@ -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
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.
|
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
|