redisant 0.1.1
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 +7 -0
- data/.gitignore +12 -0
- data/.rspec +1 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +46 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/redisant/attribute_builder.rb +38 -0
- data/lib/redisant/connection.rb +5 -0
- data/lib/redisant/criteria.rb +180 -0
- data/lib/redisant/errors.rb +20 -0
- data/lib/redisant/index.rb +11 -0
- data/lib/redisant/index_builder.rb +21 -0
- data/lib/redisant/inflector.rb +13 -0
- data/lib/redisant/orm.rb +19 -0
- data/lib/redisant/query.rb +168 -0
- data/lib/redisant/records.rb +390 -0
- data/lib/redisant/relation_builder.rb +55 -0
- data/lib/redisant/relations.rb +201 -0
- data/lib/redisant/search.rb +29 -0
- data/lib/redisant/search_builder.rb +21 -0
- data/lib/redisant/set.rb +6 -0
- data/lib/redisant/version.rb +3 -0
- data/lib/redisant.rb +17 -0
- data/redisant.gemspec +27 -0
- metadata +145 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
module RelationBuilder
|
2
|
+
def self.included(base)
|
3
|
+
base.extend ClassMethods
|
4
|
+
end
|
5
|
+
|
6
|
+
def find_relation name, &block
|
7
|
+
return unless name
|
8
|
+
relation = relations[name.to_s]
|
9
|
+
return relation if relation
|
10
|
+
relations[name.to_s] = block.call if block
|
11
|
+
end
|
12
|
+
|
13
|
+
def relations
|
14
|
+
@relations ||= {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def setup_relations
|
18
|
+
self.class.relation_definitions.each_pair do |name,klass|
|
19
|
+
relations[name] = klass.new(name, self)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
def relation_definitions
|
26
|
+
@relation_definitions ||= {}
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_relation_definition name, klass
|
30
|
+
raise Redisant::InvalidArgument.new("Relation #{name} already exists") if relation_definitions[name.to_s]
|
31
|
+
relation_definitions[name.to_s] = klass
|
32
|
+
end
|
33
|
+
|
34
|
+
def has_many name
|
35
|
+
add_relation_definition name, HasMany
|
36
|
+
send :define_method, name do
|
37
|
+
relation = find_relation(name) { HasMany.new(name, self) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def belongs_to name
|
42
|
+
add_relation_definition name, BelongsTo
|
43
|
+
send :define_method, name do
|
44
|
+
relation = find_relation(name) { BelongsTo.new(name, self) }
|
45
|
+
relation.owner
|
46
|
+
end
|
47
|
+
send :define_method, "#{name}=" do |item, reprocitate=true|
|
48
|
+
relation = find_relation(name) { BelongsTo.new( name, self ) }
|
49
|
+
relation.set_owner item, reprocitate
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
class Relation
|
2
|
+
attr_reader :name, :object
|
3
|
+
|
4
|
+
def initialize name, object
|
5
|
+
@name = name.to_s
|
6
|
+
@object = object
|
7
|
+
@class = Inflector.constantize Inflector.singularize(name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def object_class
|
11
|
+
@class
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class BelongsTo < Relation
|
16
|
+
|
17
|
+
def initialize name, object
|
18
|
+
super name, object
|
19
|
+
@reverse_name = Inflector.pluralize @object.class.name.downcase
|
20
|
+
end
|
21
|
+
|
22
|
+
def destroy
|
23
|
+
set_owner nil, true
|
24
|
+
end
|
25
|
+
|
26
|
+
# keys
|
27
|
+
def redis_key
|
28
|
+
raise Redisant::InvalidArgument.new('Cannot make key without id') unless @object && @object.id
|
29
|
+
"#{@object.class_name}:#{@object.id}:belongs_to:#{@name}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# query
|
33
|
+
def owner_id
|
34
|
+
@owner_id ||= $redis.get redis_key
|
35
|
+
end
|
36
|
+
|
37
|
+
def owner
|
38
|
+
@owner ||= @class.find(owner_id) if owner_id
|
39
|
+
end
|
40
|
+
|
41
|
+
def set_owner item, reprocitate=true
|
42
|
+
if owner
|
43
|
+
if owner.respond_to? @reverse_name
|
44
|
+
owner.send(@reverse_name).remove @object, false if reprocitate
|
45
|
+
end
|
46
|
+
end
|
47
|
+
if item
|
48
|
+
raise Redisant::InvalidArgument.new('Wrong object type') unless item.class_name == @name
|
49
|
+
raise Redisant::InvalidArgument.new('Missing id') unless item.id
|
50
|
+
$redis.set redis_key, item.id
|
51
|
+
@owner = item
|
52
|
+
@owner_id = item.id
|
53
|
+
if owner.respond_to? @reverse_name
|
54
|
+
owner.send(@reverse_name).add @object, false if reprocitate
|
55
|
+
end
|
56
|
+
else
|
57
|
+
$redis.del redis_key
|
58
|
+
@owner_id = nil
|
59
|
+
@owner = nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
class HasMany < Relation
|
66
|
+
|
67
|
+
def initialize name, object
|
68
|
+
super name, object
|
69
|
+
@reverse_name = @object.class.name.downcase
|
70
|
+
end
|
71
|
+
|
72
|
+
def destroy
|
73
|
+
all.each do |item|
|
74
|
+
item.send("#{@reverse_name}=", nil, true)
|
75
|
+
end
|
76
|
+
$redis.del redis_key
|
77
|
+
end
|
78
|
+
|
79
|
+
# keys
|
80
|
+
def redis_key
|
81
|
+
raise Redisant::InvalidArgument.new('Cannot make key without id') unless @object && @object.id
|
82
|
+
"#{@object.class_name}:#{@object.id}:has_many:#{@name}"
|
83
|
+
end
|
84
|
+
|
85
|
+
# query
|
86
|
+
def ids
|
87
|
+
Criteria.new(self).ids
|
88
|
+
end
|
89
|
+
|
90
|
+
def count
|
91
|
+
Criteria.new(self).count
|
92
|
+
end
|
93
|
+
|
94
|
+
def where attributes
|
95
|
+
Criteria.new(self).where(attributes)
|
96
|
+
end
|
97
|
+
|
98
|
+
def first attributes={}
|
99
|
+
Criteria.new(self).first attributes
|
100
|
+
end
|
101
|
+
|
102
|
+
def last attributes={}
|
103
|
+
Criteria.new(self).last attributes
|
104
|
+
end
|
105
|
+
|
106
|
+
def sort options
|
107
|
+
Criteria.new(self).sort options
|
108
|
+
end
|
109
|
+
|
110
|
+
def order options
|
111
|
+
Criteria.new(self).order options
|
112
|
+
end
|
113
|
+
|
114
|
+
def random
|
115
|
+
Criteria.new(self).random
|
116
|
+
end
|
117
|
+
|
118
|
+
def build options={}
|
119
|
+
item = @class.new options
|
120
|
+
item.save
|
121
|
+
add_item item
|
122
|
+
item
|
123
|
+
end
|
124
|
+
|
125
|
+
def add item, reprocitate=true
|
126
|
+
if item.is_a? Array
|
127
|
+
item.each { |i| add_item i }
|
128
|
+
else
|
129
|
+
add_item item
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def << object, reprocitate=true
|
134
|
+
add object, reprocitate
|
135
|
+
end
|
136
|
+
|
137
|
+
def remove item, reprocitate=true
|
138
|
+
return unless item
|
139
|
+
if item.is_a? Array
|
140
|
+
item.each {|i| remove_item i }
|
141
|
+
else
|
142
|
+
remove_item item
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def remove_all reprocitate=true
|
147
|
+
$redis.del redis_key
|
148
|
+
dirty
|
149
|
+
end
|
150
|
+
|
151
|
+
def all
|
152
|
+
@objects ||= ids.map { |id| @class.find id }
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
def dirty
|
159
|
+
@ids = nil
|
160
|
+
@count = nil
|
161
|
+
@objects = nil
|
162
|
+
end
|
163
|
+
|
164
|
+
def add_item item, reprocitate=true
|
165
|
+
return unless item
|
166
|
+
raise Redisant::InvalidArgument.new("Wrong object type, expected #{@class.name}, got #{item.class}") unless item.is_a? Record
|
167
|
+
raise Redisant::InvalidArgument.new("Wrong object type, expected #{@class.name}, got #{item.class}") unless item.class == @class
|
168
|
+
$redis.sadd redis_key, item.id
|
169
|
+
dirty
|
170
|
+
#update reverse relation
|
171
|
+
if reprocitate
|
172
|
+
if item.respond_to? @reverse_name
|
173
|
+
current_owner = item.send(@reverse_name)
|
174
|
+
current_has_many = current_owner.send(@name) if current_owner
|
175
|
+
if current_has_many && current_has_many != self
|
176
|
+
current_has_many.remove( item, false )
|
177
|
+
end
|
178
|
+
item.send("#{@reverse_name}=", @object, false )
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def remove_item item, reprocitate=true
|
184
|
+
if item.is_a? Integer
|
185
|
+
id = item
|
186
|
+
else
|
187
|
+
klass = Inflector.pluralize(item.class_name)
|
188
|
+
raise Redisant::InvalidArgument.new("Wrong object type, expected #{@name}, got #{klass}") unless klass == @name
|
189
|
+
id = item.id
|
190
|
+
end
|
191
|
+
$redis.srem redis_key, id
|
192
|
+
dirty
|
193
|
+
#update reverse relation
|
194
|
+
if reprocitate
|
195
|
+
if item.respond_to? "#{@reverse_name}="
|
196
|
+
item.send("#{@reverse_name}=", nil, false )
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Search
|
2
|
+
|
3
|
+
attr_reader :name, :class, :options, :type, :order
|
4
|
+
def initialize name, klass, options
|
5
|
+
@name = name.to_s
|
6
|
+
@class = klass
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def key value
|
11
|
+
"#{@class.name.downcase}:search:#{@name}:#{value}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def add record, value
|
15
|
+
$redis.sadd key(value), record.id.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
def update record, prev_value, cur_value
|
19
|
+
if prev_value != cur_value
|
20
|
+
remove record, prev_value
|
21
|
+
add record, cur_value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def remove record, value
|
26
|
+
$redis.srem key(value), record.id.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SearchBuilder
|
2
|
+
def self.included(base)
|
3
|
+
base.extend ClassMethods
|
4
|
+
end
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def finder name, options={}
|
8
|
+
searches[name.to_s] ||= Search.new name, self, options
|
9
|
+
end
|
10
|
+
|
11
|
+
def find_search name
|
12
|
+
searches[name.to_s]
|
13
|
+
end
|
14
|
+
|
15
|
+
def searches
|
16
|
+
@searches ||= {}
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/redisant/set.rb
ADDED
data/lib/redisant.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "redisant/version"
|
2
|
+
|
3
|
+
require 'redis'
|
4
|
+
|
5
|
+
require_relative 'redisant/connection'
|
6
|
+
require_relative 'redisant/errors.rb'
|
7
|
+
require_relative 'redisant/inflector'
|
8
|
+
require_relative 'redisant/attribute_builder'
|
9
|
+
require_relative 'redisant/relation_builder'
|
10
|
+
require_relative 'redisant/index_builder'
|
11
|
+
require_relative 'redisant/search_builder'
|
12
|
+
require_relative 'redisant/relations'
|
13
|
+
require_relative 'redisant/index'
|
14
|
+
require_relative 'redisant/search'
|
15
|
+
require_relative 'redisant/query'
|
16
|
+
require_relative 'redisant/criteria'
|
17
|
+
require_relative 'redisant/records'
|
data/redisant.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'redisant/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "redisant"
|
8
|
+
spec.version = Redisant::VERSION
|
9
|
+
spec.authors = ["Emil Tin"]
|
10
|
+
spec.email = ["emil@tin.dk"]
|
11
|
+
|
12
|
+
spec.summary = %q{ORM-like Redis storage.}
|
13
|
+
spec.description = %q{Schema-less ORM-like Redis store.}
|
14
|
+
spec.homepage = "http://github.com/emiltin/redisant"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", '~> 2.2.26'#, '>= 2.2.26'
|
23
|
+
spec.add_development_dependency "rake", '~> 13.0.6', '>= 13.0.6'
|
24
|
+
spec.add_development_dependency "rspec", '~> 3.10.0', '>= 3.10.0'
|
25
|
+
spec.add_development_dependency "redis", '~> 4.4.0', '>= 4.4.0'
|
26
|
+
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redisant
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Emil Tin
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-08-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.2.26
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.2.26
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 13.0.6
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 13.0.6
|
37
|
+
type: :development
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 13.0.6
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 13.0.6
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 3.10.0
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 3.10.0
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 3.10.0
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 3.10.0
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: redis
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 4.4.0
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 4.4.0
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 4.4.0
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: 4.4.0
|
87
|
+
description: Schema-less ORM-like Redis store.
|
88
|
+
email:
|
89
|
+
- emil@tin.dk
|
90
|
+
executables: []
|
91
|
+
extensions: []
|
92
|
+
extra_rdoc_files: []
|
93
|
+
files:
|
94
|
+
- ".gitignore"
|
95
|
+
- ".rspec"
|
96
|
+
- ".travis.yml"
|
97
|
+
- CODE_OF_CONDUCT.md
|
98
|
+
- Gemfile
|
99
|
+
- LICENSE.txt
|
100
|
+
- README.md
|
101
|
+
- Rakefile
|
102
|
+
- bin/console
|
103
|
+
- bin/setup
|
104
|
+
- lib/redisant.rb
|
105
|
+
- lib/redisant/attribute_builder.rb
|
106
|
+
- lib/redisant/connection.rb
|
107
|
+
- lib/redisant/criteria.rb
|
108
|
+
- lib/redisant/errors.rb
|
109
|
+
- lib/redisant/index.rb
|
110
|
+
- lib/redisant/index_builder.rb
|
111
|
+
- lib/redisant/inflector.rb
|
112
|
+
- lib/redisant/orm.rb
|
113
|
+
- lib/redisant/query.rb
|
114
|
+
- lib/redisant/records.rb
|
115
|
+
- lib/redisant/relation_builder.rb
|
116
|
+
- lib/redisant/relations.rb
|
117
|
+
- lib/redisant/search.rb
|
118
|
+
- lib/redisant/search_builder.rb
|
119
|
+
- lib/redisant/set.rb
|
120
|
+
- lib/redisant/version.rb
|
121
|
+
- redisant.gemspec
|
122
|
+
homepage: http://github.com/emiltin/redisant
|
123
|
+
licenses:
|
124
|
+
- MIT
|
125
|
+
metadata: {}
|
126
|
+
post_install_message:
|
127
|
+
rdoc_options: []
|
128
|
+
require_paths:
|
129
|
+
- lib
|
130
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - ">="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
requirements: []
|
141
|
+
rubygems_version: 3.2.26
|
142
|
+
signing_key:
|
143
|
+
specification_version: 4
|
144
|
+
summary: ORM-like Redis storage.
|
145
|
+
test_files: []
|