mongo_light 0.0.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.
- data/lib/mongo_light/connection.rb +36 -0
- data/lib/mongo_light/document.rb +75 -0
- data/lib/mongo_light/embedded_document.rb +75 -0
- data/lib/mongo_light/id.rb +17 -0
- data/lib/mongo_light/version.rb +3 -0
- data/lib/mongo_light.rb +4 -0
- data/license +14 -0
- data/readme.markdown +68 -0
- metadata +62 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'mongo'
|
|
2
|
+
|
|
3
|
+
module MongoLight
|
|
4
|
+
module Connection
|
|
5
|
+
|
|
6
|
+
def self.setup(connection, database_name)
|
|
7
|
+
@@connection = connection
|
|
8
|
+
@@database = @@connection.db(database_name)
|
|
9
|
+
handle_passenger_forking
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.connection
|
|
13
|
+
@@connection
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.database
|
|
17
|
+
@@database
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.collections
|
|
21
|
+
@@database.collections
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.[](collection_name)
|
|
25
|
+
@@database.collection(collection_name)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.handle_passenger_forking
|
|
29
|
+
if defined?(PhusionPassenger)
|
|
30
|
+
PhusionPassenger.on_event(:starting_worker_process) do |forked|
|
|
31
|
+
@@connection.connect if forked
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module MongoLight
|
|
2
|
+
module Document
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
include EmbeddedDocument
|
|
5
|
+
|
|
6
|
+
module ClassMethods
|
|
7
|
+
def collection
|
|
8
|
+
Connection[self.to_s.tableize]
|
|
9
|
+
end
|
|
10
|
+
def find_by_id(id)
|
|
11
|
+
real_id = Id.from_string(id)
|
|
12
|
+
return nil if real_id.nil?
|
|
13
|
+
|
|
14
|
+
found = collection.find_one(real_id)
|
|
15
|
+
found.nil? ? nil : self.new(unmap(found))
|
|
16
|
+
end
|
|
17
|
+
def find_one(selector = {})
|
|
18
|
+
found = collection.find_one(map(selector))
|
|
19
|
+
found.nil? ? nil : self.new(unmap(found))
|
|
20
|
+
end
|
|
21
|
+
def find(selector={}, opts={}, collection = nil)
|
|
22
|
+
raw = opts.delete(:raw) || false
|
|
23
|
+
opts[:transformer] = Proc.new{|data| raw ? unmap(data, raw) : self.new(unmap(data)) }
|
|
24
|
+
c = collection || self.collection
|
|
25
|
+
c.find(map(selector), map_options(opts))
|
|
26
|
+
end
|
|
27
|
+
def remove(selector={}, collection = nil)
|
|
28
|
+
c = collection || self.collection
|
|
29
|
+
c.remove(map(selector))
|
|
30
|
+
end
|
|
31
|
+
def update(selector, document, options = {}, collection = nil)
|
|
32
|
+
c = collection || self.collection
|
|
33
|
+
c.update(map(selector), map(document), options)
|
|
34
|
+
end
|
|
35
|
+
def count(selector={}, collection = nil)
|
|
36
|
+
c = collection || self.collection
|
|
37
|
+
c.find(map(selector)).count
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
module InstanceMethods
|
|
41
|
+
def initialize(attributes = {})
|
|
42
|
+
attributes[:_id] = Id.new unless attributes.include?('_id') || attributes.include?(:_id)
|
|
43
|
+
@attributes = attributes
|
|
44
|
+
attributes.each do |k,v|
|
|
45
|
+
send("#{k}=", v) unless k == :_id || k == '_id'
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
def eql?(other)
|
|
49
|
+
other.is_a?(self.class) && id == other.id
|
|
50
|
+
end
|
|
51
|
+
alias :== :eql?
|
|
52
|
+
def hash
|
|
53
|
+
id.hash
|
|
54
|
+
end
|
|
55
|
+
def id
|
|
56
|
+
@attributes[:_id] || @attributes['_id']
|
|
57
|
+
end
|
|
58
|
+
def id=(value)
|
|
59
|
+
@attributes[:_id] = value
|
|
60
|
+
end
|
|
61
|
+
def ==(other)
|
|
62
|
+
other.class == self.class && id == other.id
|
|
63
|
+
end
|
|
64
|
+
def collection
|
|
65
|
+
self.class.collection
|
|
66
|
+
end
|
|
67
|
+
def save
|
|
68
|
+
collection.save(self.class.map(@attributes))
|
|
69
|
+
end
|
|
70
|
+
def save!
|
|
71
|
+
collection.save(self.class.map(@attributes), {:safe => true})
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module MongoLight
|
|
2
|
+
module EmbeddedDocument
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
module ClassMethods
|
|
6
|
+
def mongo_accessor(map)
|
|
7
|
+
@map = map
|
|
8
|
+
@unmap = {}
|
|
9
|
+
map.each do |k,v|
|
|
10
|
+
define_method(k) { @attributes[k] }
|
|
11
|
+
define_method("#{k}=") {|value| @attributes[k] = value }
|
|
12
|
+
if v.is_a?(Hash)
|
|
13
|
+
@unmap[v[:field].to_s] = {:prop => k, :class => v[:class]}
|
|
14
|
+
else
|
|
15
|
+
@unmap[v.to_s] = k
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
def map(raw)
|
|
20
|
+
return {} if raw.blank? || !raw.is_a?(Hash)
|
|
21
|
+
hash = {}
|
|
22
|
+
raw.each do |key, value|
|
|
23
|
+
if value.is_a?(EmbeddedDocument)
|
|
24
|
+
v = value.class.map(value.attributes)
|
|
25
|
+
elsif value.is_a?(Hash)
|
|
26
|
+
v = map(value)
|
|
27
|
+
else
|
|
28
|
+
v = value
|
|
29
|
+
end
|
|
30
|
+
hash[map_key(key.to_sym)] = v
|
|
31
|
+
end
|
|
32
|
+
return hash
|
|
33
|
+
end
|
|
34
|
+
def map_options(options)
|
|
35
|
+
options[:fields] = map(options[:fields]) if options.include?(:fields)
|
|
36
|
+
options[:sort][0] = map_key(options[:sort][0]) if options.include?(:sort)
|
|
37
|
+
options
|
|
38
|
+
end
|
|
39
|
+
def unmap(data, raw = false)
|
|
40
|
+
return {} if data.blank? || !data.is_a?(Hash)
|
|
41
|
+
hash = {}
|
|
42
|
+
data.each do |key, value|
|
|
43
|
+
if @unmap[key].is_a?(Hash)
|
|
44
|
+
real_key = @unmap[key][:prop]
|
|
45
|
+
c = @unmap[key][:class]
|
|
46
|
+
v = raw ? c.unmap(value) : c.new(c.unmap(value))
|
|
47
|
+
else
|
|
48
|
+
real_key = key == '_id' ? :_id : @unmap[key]
|
|
49
|
+
v = value
|
|
50
|
+
end
|
|
51
|
+
hash[real_key] = v
|
|
52
|
+
end
|
|
53
|
+
hash
|
|
54
|
+
end
|
|
55
|
+
def map_key(key)
|
|
56
|
+
return key unless @map.include?(key)
|
|
57
|
+
@map[key].is_a?(Hash) ? @map[key][:field] : @map[key]
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
module InstanceMethods
|
|
61
|
+
def initialize(attributes = {})
|
|
62
|
+
@attributes = attributes
|
|
63
|
+
attributes.each do |k,v|
|
|
64
|
+
send("#{k}=", v)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
def [](name)
|
|
68
|
+
@attributes[name]
|
|
69
|
+
end
|
|
70
|
+
def attributes
|
|
71
|
+
@attributes
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module MongoLight
|
|
2
|
+
module Id
|
|
3
|
+
def self.new
|
|
4
|
+
BSON::ObjectId.new
|
|
5
|
+
end
|
|
6
|
+
def self.valid?(id)
|
|
7
|
+
return false if id.blank? || id.class == Fixnum
|
|
8
|
+
return true if id.class == BSON::ObjectId
|
|
9
|
+
BSON::ObjectId.legal?(id)
|
|
10
|
+
end
|
|
11
|
+
def self.from_string(id)
|
|
12
|
+
return nil unless Id.valid?(id)
|
|
13
|
+
return id if id.class == BSON::ObjectId
|
|
14
|
+
BSON::ObjectId.from_string(id)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/mongo_light.rb
ADDED
data/license
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
This file is part of MongoLight.
|
|
2
|
+
|
|
3
|
+
MongoLight is free software: you can redistribute it and/or modify
|
|
4
|
+
it under the terms of the GNU General Public License as published by
|
|
5
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
(at your option) any later version.
|
|
7
|
+
|
|
8
|
+
MongoLight is distributed in the hope that it will be useful,
|
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
GNU General Public License for more details.
|
|
12
|
+
|
|
13
|
+
You should have received a copy of the GNU General Public License
|
|
14
|
+
along with MongoLight. If not, see <http://www.gnu.org/licenses/>.
|
data/readme.markdown
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# MongoLight #
|
|
2
|
+
MongoLight is a lightweight object-relational mapper for Rails and MongoDB. It is **not** ActiveRecord compatible. Rather, the primary purpose is to be a thin wrapper around the excellent core [MongoDB driver](https://github.com/mongodb/mongo-ruby-driver).
|
|
3
|
+
|
|
4
|
+
The only Rails dependency is on ActiveSupport::Concern.
|
|
5
|
+
|
|
6
|
+
The wrapper fits a specific use-case (mine).
|
|
7
|
+
|
|
8
|
+
## Setup ##
|
|
9
|
+
During initialization (such as in an initializer), call `MongoLight::Connection.setup`, supplying 2 parameters. The first is a MongoDB connection (that you get from the core driver). The second parameter is the database name. For example:
|
|
10
|
+
|
|
11
|
+
MongoLight::Connection.setup(Mongo::Connection.new, 'test')
|
|
12
|
+
|
|
13
|
+
This'll automatically handle Passenger forking issues (if Passenger is running).
|
|
14
|
+
|
|
15
|
+
## Documents ##
|
|
16
|
+
To define a document include `MongoLight::Document` and define your properties using the `mongo_accessor` method:
|
|
17
|
+
|
|
18
|
+
class User
|
|
19
|
+
include MongoLight::Document
|
|
20
|
+
mongo_accessor({:name => :name, password => :pw, :email => :e})
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Within your code, you can access the `name`, `password` and `email` properties. However, internally, MongoDB will store the fields as `name`, `pw` and `e` (document databases store the field names with each document, this can save a lot of space (we saved 25%)).
|
|
24
|
+
|
|
25
|
+
## Document Manipulation ##
|
|
26
|
+
Most of what you can do on a MongoDB collection (again, the Ruby driver), you can do on a MongoLight document:
|
|
27
|
+
|
|
28
|
+
#string ids which are valid BsonIds will automatically get converted
|
|
29
|
+
User.find_by_id(some_id)
|
|
30
|
+
User.find_one(hash_selector)
|
|
31
|
+
User.find(selector, options)
|
|
32
|
+
User.remove(selector)
|
|
33
|
+
User.update(selector, new_document, options)
|
|
34
|
+
|
|
35
|
+
In addition to any options which the ruby driver supports, the `find` method can be passed ``{:raw => true}` which'll cause a hash to be returned rather than a mapped object.
|
|
36
|
+
|
|
37
|
+
Instances can be saved via `save` or `save!` (safe mode).
|
|
38
|
+
|
|
39
|
+
New instances can be created by passing a hash into the constructor:
|
|
40
|
+
|
|
41
|
+
User.new({:name => 'goku', :password => 'over 9000!!!'})
|
|
42
|
+
|
|
43
|
+
Finally, you can always access the underlying `collection` from a class or object (`User.collection` or `user.collection`).
|
|
44
|
+
|
|
45
|
+
## Embedded Documents ##
|
|
46
|
+
Embedded documents are supported. First, define an embedded document using `include MongoLight::EmbeddedDocument` and the same `mongo_accessor` method:
|
|
47
|
+
|
|
48
|
+
class Comment
|
|
49
|
+
include MongoLight::EmbeddedDocument
|
|
50
|
+
mongo_accessor({:title => :t, description => :d})
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
Next, use the following fancy syntax for your root document:
|
|
54
|
+
|
|
55
|
+
class User
|
|
56
|
+
include MongoLight::Document
|
|
57
|
+
mongo_accessor({:name => :name, password => :pw, :email => :e, :comments => {:field => :c, :class => Comment}})
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
Again, this'll make `comments` accessible on your objects, but store it within the `c` field.
|
|
61
|
+
|
|
62
|
+
Please note that aliasing completely fails when querying embedded documents - you need to use the shortened name:
|
|
63
|
+
|
|
64
|
+
User.find({:name => 'blah', 'c.t' => 'blah2}) #yes, it sucks
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
metadata
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: mongo_light
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
prerelease:
|
|
5
|
+
version: 0.0.1
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Karl Seguin
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
|
|
13
|
+
date: 2011-06-27 00:00:00 Z
|
|
14
|
+
dependencies: []
|
|
15
|
+
|
|
16
|
+
description:
|
|
17
|
+
email:
|
|
18
|
+
- karlseguin@gmail.com
|
|
19
|
+
executables: []
|
|
20
|
+
|
|
21
|
+
extensions: []
|
|
22
|
+
|
|
23
|
+
extra_rdoc_files: []
|
|
24
|
+
|
|
25
|
+
files:
|
|
26
|
+
- lib/mongo_light/connection.rb
|
|
27
|
+
- lib/mongo_light/document.rb
|
|
28
|
+
- lib/mongo_light/embedded_document.rb
|
|
29
|
+
- lib/mongo_light/id.rb
|
|
30
|
+
- lib/mongo_light/version.rb
|
|
31
|
+
- lib/mongo_light.rb
|
|
32
|
+
- license
|
|
33
|
+
- readme.markdown
|
|
34
|
+
homepage: http://github.com/karlseguib/MongoLight
|
|
35
|
+
licenses: []
|
|
36
|
+
|
|
37
|
+
post_install_message:
|
|
38
|
+
rdoc_options: []
|
|
39
|
+
|
|
40
|
+
require_paths:
|
|
41
|
+
- lib
|
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
43
|
+
none: false
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: "0"
|
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
|
+
none: false
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: "0"
|
|
54
|
+
requirements: []
|
|
55
|
+
|
|
56
|
+
rubyforge_project:
|
|
57
|
+
rubygems_version: 1.8.5
|
|
58
|
+
signing_key:
|
|
59
|
+
specification_version: 3
|
|
60
|
+
summary: A Lightweight ORM for Rails and MongoDB
|
|
61
|
+
test_files: []
|
|
62
|
+
|