stores_in_mongo 0.3.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/stores_in_mongo.rb +4 -1
- data/lib/stores_in_mongo/base.rb +31 -2
- data/lib/stores_in_mongo/builder.rb +46 -26
- data/lib/stores_in_mongo/document_methods.rb +84 -21
- data/lib/stores_in_mongo/interpreter.rb +15 -0
- data/lib/stores_in_mongo/mongo_store.rb +14 -0
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05ff0ec8463f5f848e7e736bb3e50d71de2c4ae7
|
4
|
+
data.tar.gz: 327f6d173bbda76ebd7e4a614ab58279d9f1422f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3af0be54c3fdee52d4820b781fb7a82c54fabd6c280138c939af99826390b1fcee5a0ce3d469b8bf867f489418be32a69fa6b72cd9b7a556397c261ef9877c9c
|
7
|
+
data.tar.gz: 3765c8da5b23fbf0c2c8219992aa6296fa87c5dd3e507584695afd980492baf6aabdf7b27b6e2becda7021a2c2460d380f8f2f8ac7319a2c082980cbd7ea786c
|
data/lib/stores_in_mongo.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require "stores_in_mongo/base.rb"
|
2
2
|
require "stores_in_mongo/builder.rb"
|
3
3
|
require "stores_in_mongo/document_methods.rb"
|
4
|
+
require "stores_in_mongo/interpreter.rb"
|
4
5
|
|
5
|
-
|
6
|
+
class StoresInMongo::RuntimeError < RuntimeError; end
|
7
|
+
|
8
|
+
ActiveRecord::Base.include(StoresInMongo::Base)
|
data/lib/stores_in_mongo/base.rb
CHANGED
@@ -1,7 +1,36 @@
|
|
1
1
|
module StoresInMongo
|
2
2
|
module Base
|
3
|
-
|
4
|
-
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def stores_in_mongo(field_name = nil, data_type = nil,
|
7
|
+
as: nil,
|
8
|
+
class_name: nil,
|
9
|
+
foreign_key: nil,
|
10
|
+
&blk)
|
11
|
+
raise ArgumentError, "Provide either inline field_name or block syntax, you cannot provide both to stores_in_mongo" if field_name.present? && blk.present?
|
12
|
+
raise ArgumentError, "Cannot use :class_name or :foreign_key with polymorphic :as option" if as.present? && (class_name.present? || foreign_key.present?)
|
13
|
+
if as.present?
|
14
|
+
foreign_key = as.to_s.foreign_key
|
15
|
+
class_name = foreign_key.sub(/id$/, "type")
|
16
|
+
end
|
17
|
+
class_attribute :stores_in_mongo_options
|
18
|
+
self.stores_in_mongo_options = {
|
19
|
+
polymorphic: as.present?,
|
20
|
+
foreign_key: foreign_key,
|
21
|
+
class_name: class_name,
|
22
|
+
use_sessions: false
|
23
|
+
}
|
24
|
+
builder = ::StoresInMongo::Builder.new(self)
|
25
|
+
if field_name.present?
|
26
|
+
builder.build do
|
27
|
+
field(field_name, data_type)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
builder.build(&blk)
|
31
|
+
end
|
32
|
+
end
|
5
33
|
end
|
34
|
+
|
6
35
|
end
|
7
36
|
end
|
@@ -1,44 +1,64 @@
|
|
1
1
|
module StoresInMongo
|
2
2
|
class Builder
|
3
3
|
|
4
|
-
def initialize(model
|
4
|
+
def initialize(model)
|
5
5
|
@model = model
|
6
|
-
@
|
7
|
-
@data_type = data_type
|
6
|
+
@class_given = @model.stores_in_mongo_options[:class_name].present?
|
8
7
|
end
|
9
8
|
|
10
|
-
def build
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@model.
|
16
|
-
|
17
|
-
|
9
|
+
def build(&blk)
|
10
|
+
if !@class_given
|
11
|
+
klass = build_mongo_class
|
12
|
+
@model.stores_in_mongo_options[:class_name] = klass.name
|
13
|
+
end
|
14
|
+
@model.stores_in_mongo_options[:foreign_key] ||= @model.stores_in_mongo_options[:class_name].foreign_key
|
15
|
+
@model.include(get_document_methods_module)
|
16
|
+
Interpreter.new(self).instance_exec(&blk)
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
def build_mongo_class
|
20
|
+
klass = @model.const_set("MongoDocument", Class.new)
|
21
|
+
klass.include Mongoid::Document
|
22
|
+
klass.include Mongoid::Timestamps
|
23
|
+
return klass
|
24
|
+
end
|
21
25
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
+
def get_document_methods_module
|
27
|
+
@model.const_set("MongoDocumentMethods", Module.new)
|
28
|
+
@model::MongoDocumentMethods.include(StoresInMongo::DocumentMethods)
|
29
|
+
@model::MongoDocumentMethods.extend ActiveSupport::Concern
|
30
|
+
@model::MongoDocumentMethods.included do
|
31
|
+
before_save :save_mongo_document
|
32
|
+
after_save :clear_mongo_owner_dirty
|
33
|
+
before_destroy :destroy_mongo_document
|
26
34
|
end
|
35
|
+
return @model::MongoDocumentMethods
|
27
36
|
end
|
28
37
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
38
|
+
def add_field(field_name, data_type)
|
39
|
+
@model.stores_in_mongo_options[:class_name].constantize.field field_name, :type => data_type, default: data_type.try(:new) if !@class_given
|
40
|
+
|
41
|
+
@model::MongoDocumentMethods.instance_exec(field_name) do |field_name|
|
42
|
+
# getter
|
43
|
+
define_method(field_name) do
|
44
|
+
mongo_document.public_send(field_name)
|
35
45
|
end
|
36
46
|
|
37
|
-
|
38
|
-
|
47
|
+
# setter
|
48
|
+
define_method("#{field_name}=") do |data|
|
49
|
+
mongo_document.public_send("#{field_name}=", data)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def define_session(&blk)
|
56
|
+
@model.stores_in_mongo_options[:use_sessions] = true
|
57
|
+
@model::MongoDocumentMethods.instance_exec(blk) do |blk|
|
58
|
+
define_method("mongo_session") do
|
59
|
+
instance_exec(&blk)
|
39
60
|
end
|
40
61
|
end
|
41
|
-
return mod
|
42
62
|
end
|
43
63
|
|
44
64
|
end
|
@@ -1,45 +1,108 @@
|
|
1
1
|
module StoresInMongo
|
2
2
|
module DocumentMethods
|
3
|
+
def mongo_class_name
|
4
|
+
if self.stores_in_mongo_options[:polymorphic]
|
5
|
+
self.public_send(mongo_class_column) or raise RuntimeError, "No mongo type specified in #{mongo_class_column} for #{self}! Initialize your model with a value or use a column default."
|
6
|
+
else
|
7
|
+
self.stores_in_mongo_options[:class_name]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def mongo_class
|
12
|
+
if self.stores_in_mongo_options[:use_sessions]
|
13
|
+
mongo_class_name.constantize.with(session: mongo_session)
|
14
|
+
else
|
15
|
+
mongo_class_name.constantize
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def mongo_key
|
20
|
+
self.public_send(mongo_key_column)
|
21
|
+
end
|
22
|
+
|
23
|
+
def mongo_class_column
|
24
|
+
self.stores_in_mongo_options[:polymorphic] && self.stores_in_mongo_options[:class_name]
|
25
|
+
end
|
26
|
+
|
27
|
+
def mongo_key_column
|
28
|
+
stores_in_mongo_options[:foreign_key]
|
29
|
+
end
|
30
|
+
|
3
31
|
def reload(*args)
|
32
|
+
clear_mongo_cache
|
4
33
|
super
|
5
|
-
find_or_initialize_document if document_loaded?
|
6
|
-
return self
|
7
34
|
end
|
8
35
|
|
9
|
-
def
|
36
|
+
def deep_dup(*args)
|
10
37
|
copy = super
|
11
|
-
copy.
|
38
|
+
copy.mongo_document = mongo_document.deep_dup
|
12
39
|
return copy
|
13
40
|
end
|
14
41
|
|
42
|
+
def changed?
|
43
|
+
@mongo_dirty || super
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def mongo_document=(mongo_document)
|
49
|
+
# We can't easily determine in-place data modification, so always mark as dirty if data has been loaded
|
50
|
+
# TODO: only mark as dirty if data has actually changed. Clear dirty on a fresh load.
|
51
|
+
mark_mongo_owner_as_dirty
|
52
|
+
@mongo_document = mongo_document
|
53
|
+
set_mongo_document_id
|
54
|
+
return mongo_document
|
55
|
+
end
|
56
|
+
|
15
57
|
private
|
16
58
|
|
17
|
-
def
|
18
|
-
@
|
59
|
+
def mark_mongo_owner_as_dirty
|
60
|
+
@mongo_dirty = true
|
61
|
+
return true
|
19
62
|
end
|
20
63
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
64
|
+
def clear_mongo_owner_dirty
|
65
|
+
@mongo_dirty = false
|
66
|
+
return true
|
24
67
|
end
|
25
68
|
|
26
|
-
def
|
27
|
-
|
28
|
-
document.save
|
29
|
-
self.document_id = document.id
|
69
|
+
def mongo_document_loaded?
|
70
|
+
@mongo_document.present?
|
30
71
|
end
|
31
72
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
73
|
+
def clear_mongo_cache
|
74
|
+
@mongo_document = nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def set_mongo_document_id
|
78
|
+
assign_attributes(stores_in_mongo_options[:class_name] => mongo_document.class.name) if self.stores_in_mongo_options[:polymorphic]
|
79
|
+
assign_attributes(stores_in_mongo_options[:foreign_key] => mongo_document.id)
|
80
|
+
return mongo_key
|
81
|
+
end
|
36
82
|
|
37
|
-
def
|
38
|
-
@
|
83
|
+
def mongo_document(reload = false)
|
84
|
+
return @mongo_document if !reload && mongo_document_loaded?
|
85
|
+
self.mongo_document = fetch_mongo_document || initialize_mongo_document
|
39
86
|
end
|
40
87
|
|
41
|
-
def
|
42
|
-
|
88
|
+
def fetch_mongo_document
|
89
|
+
mongo_class.where(id: mongo_key).first
|
43
90
|
end
|
91
|
+
|
92
|
+
def initialize_mongo_document
|
93
|
+
mongo_class.new
|
94
|
+
end
|
95
|
+
|
96
|
+
def save_mongo_document
|
97
|
+
return true if !mongo_document_loaded?
|
98
|
+
mongo_document.save!
|
99
|
+
set_mongo_document_id
|
100
|
+
return true
|
101
|
+
end
|
102
|
+
|
103
|
+
def destroy_mongo_document
|
104
|
+
return true if !mongo_document_loaded?
|
105
|
+
mongo_document.destroy
|
106
|
+
end
|
44
107
|
end
|
45
108
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module StoresInMongo
|
2
|
+
class Interpreter < BasicObject
|
3
|
+
def initialize(builder)
|
4
|
+
@builder = builder
|
5
|
+
end
|
6
|
+
|
7
|
+
def field(name, data_type = nil)
|
8
|
+
@builder.add_field(name, data_type)
|
9
|
+
end
|
10
|
+
|
11
|
+
def session(&blk)
|
12
|
+
@builder.define_session(&blk)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module StoresInMongo
|
2
|
+
class MongoStore
|
3
|
+
attr_reader :name, :klass, :foreign_key
|
4
|
+
|
5
|
+
def initialize(klass, foreign_key)
|
6
|
+
@klass = klass
|
7
|
+
@foreign_key = foreign_key
|
8
|
+
end
|
9
|
+
|
10
|
+
def find_or_initialize_for(owner)
|
11
|
+
owner[@foreign_key].present? && @klass.where(id: owner[@foreign_key]).first || @klass.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stores_in_mongo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Schwartz
|
@@ -30,8 +30,10 @@ dependencies:
|
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 4.0.0
|
33
|
-
description:
|
34
|
-
|
33
|
+
description: Define new or provide existing Mongoid::Document classes that access
|
34
|
+
a mongo db, use the mongo connection for persistence of specified virtual fields
|
35
|
+
in an ActiveRecord model. Document creation, persistence, and reloading is handled
|
36
|
+
automatically and highly customizeable.
|
35
37
|
email: ozydingo@gmail.com
|
36
38
|
executables: []
|
37
39
|
extensions: []
|
@@ -41,6 +43,8 @@ files:
|
|
41
43
|
- lib/stores_in_mongo/base.rb
|
42
44
|
- lib/stores_in_mongo/builder.rb
|
43
45
|
- lib/stores_in_mongo/document_methods.rb
|
46
|
+
- lib/stores_in_mongo/interpreter.rb
|
47
|
+
- lib/stores_in_mongo/mongo_store.rb
|
44
48
|
homepage: https://github.com/ozydingo/stores_in_mongo
|
45
49
|
licenses:
|
46
50
|
- MIT
|
@@ -64,5 +68,5 @@ rubyforge_project:
|
|
64
68
|
rubygems_version: 2.4.5
|
65
69
|
signing_key:
|
66
70
|
specification_version: 4
|
67
|
-
summary: Seamlessly
|
71
|
+
summary: Seamlessly interact with mongo storage as fields of an ActiveRecord model
|
68
72
|
test_files: []
|