poros 0.2.3 → 0.3.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 +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
|