stores_in_mongo 0.3.1 → 1.0.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/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: []
|