Skip to content

Commit 06ff0d8

Browse files
committed
Init
0 parents  commit 06ff0d8

File tree

194 files changed

+3454
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

194 files changed

+3454
-0
lines changed

.gitignore

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
*.gem
2+
*.rbc
3+
.bundle
4+
.config
5+
.yardoc
6+
Gemfile.lock
7+
InstalledFiles
8+
_yardoc
9+
coverage
10+
doc/
11+
lib/bundler/man
12+
pkg
13+
rdoc
14+
spec/reports
15+
test/tmp
16+
test/version_tmp
17+
tmp

.rspec

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
--tty
2+
--colour
3+
--format <%= ENV["CI"] ? 'progress' : 'documentation'%>

Gemfile

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
source 'https://rubygems.org'
2+
3+
gemspec
4+
5+
gem "rake"
6+
gem "mongoid", github: 'mongoid', branch: "4.0.0-dev"
7+
8+
git "git://github.com/rails/rails.git" do
9+
gem "activemodel"
10+
end
11+
12+
group :test do
13+
gem "rspec", "~> 2.11"
14+
end

LICENSE

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Copyright (c) 2013 Josef Šimánek
2+
3+
MIT License
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
"Software"), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Mongoid::Paranoia
2+
3+
TODO: Write a gem description
4+
5+
## Installation
6+
7+
Add this line to your application's Gemfile:
8+
9+
gem 'mongoid-paranoia'
10+
11+
And then execute:
12+
13+
$ bundle
14+
15+
Or install it yourself as:
16+
17+
$ gem install mongoid-paranoia
18+
19+
## Usage
20+
21+
TODO: Write usage instructions here
22+
23+
## Contributing
24+
25+
1. Fork it
26+
2. Create your feature branch (`git checkout -b my-new-feature`)
27+
3. Commit your changes (`git commit -am 'Add some feature'`)
28+
4. Push to the branch (`git push origin my-new-feature`)
29+
5. Create new Pull Request

Rakefile

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
require "bundler"
2+
Bundler.setup
3+
4+
require "rspec/core/rake_task"
5+
require "rake"
6+
7+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
8+
9+
RSpec::Core::RakeTask.new("spec") do |spec|
10+
spec.pattern = "spec/**/*_spec.rb"
11+
end
12+
13+
task :default => :spec

lib/mongoid-paranoia.rb

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require "mongoid/paranoia"

lib/mongoid/paranoia.rb

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# encoding: utf-8
2+
require 'mongoid/paranoia/monkey_patches'
3+
module Mongoid
4+
5+
# Include this module to get soft deletion of root level documents.
6+
# This will add a deleted_at field to the +Document+, managed automatically.
7+
# Potentially incompatible with unique indices. (if collisions with deleted items)
8+
#
9+
# @example Make a document paranoid.
10+
# class Person
11+
# include Mongoid::Document
12+
# include Mongoid::Paranoia
13+
# end
14+
module Paranoia
15+
extend ActiveSupport::Concern
16+
17+
included do
18+
field :deleted_at, type: Time
19+
class_attribute :paranoid
20+
self.paranoid = true
21+
22+
default_scope where(deleted_at: nil)
23+
scope :deleted, ne(deleted_at: nil)
24+
end
25+
26+
# Delete the paranoid +Document+ from the database completely. This will
27+
# run the destroy callbacks.
28+
#
29+
# @example Hard destroy the document.
30+
# document.destroy!
31+
#
32+
# @return [ true, false ] If the operation succeeded.
33+
#
34+
# @since 1.0.0
35+
def destroy!
36+
run_callbacks(:destroy) { delete! }
37+
end
38+
39+
# Delete the paranoid +Document+ from the database completely.
40+
#
41+
# @example Hard delete the document.
42+
# document.delete!
43+
#
44+
# @return [ true, false ] If the operation succeeded.
45+
#
46+
# @since 1.0.0
47+
def delete!
48+
Persistence::Operations.remove(self).persist
49+
end
50+
51+
# Delete the +Document+, will set the deleted_at timestamp and not actually
52+
# delete it.
53+
#
54+
# @example Soft remove the document.
55+
# document.remove
56+
#
57+
# @param [ Hash ] options The database options.
58+
#
59+
# @return [ true ] True.
60+
#
61+
# @since 1.0.0
62+
def remove(options = {})
63+
cascade!
64+
time = self.deleted_at = Time.now
65+
paranoid_collection.find(atomic_selector).
66+
update({ "$set" => { paranoid_field => time }})
67+
@destroyed = true
68+
IdentityMap.remove(self)
69+
Threaded.clear_options!
70+
true
71+
end
72+
alias :delete :remove
73+
74+
# Determines if this document is destroyed.
75+
#
76+
# @example Is the document destroyed?
77+
# person.destroyed?
78+
#
79+
# @return [ true, false ] If the document is destroyed.
80+
#
81+
# @since 1.0.0
82+
def destroyed?
83+
(@destroyed ||= false) || !!deleted_at
84+
end
85+
alias :deleted? :destroyed?
86+
87+
# Restores a previously soft-deleted document. Handles this by removing the
88+
# deleted_at flag.
89+
#
90+
# @example Restore the document from deleted state.
91+
# document.restore
92+
#
93+
# @return [ Time ] The time the document had been deleted.
94+
#
95+
# @since 1.0.0
96+
def restore
97+
paranoid_collection.find(atomic_selector).
98+
update({ "$unset" => { paranoid_field => true }})
99+
attributes.delete("deleted_at")
100+
@destroyed = false
101+
true
102+
end
103+
104+
# Returns a string representing the documents's key suitable for use in URLs.
105+
def to_param
106+
new_record? ? nil : to_key.join('-')
107+
end
108+
109+
private
110+
111+
# Get the collection to be used for paranoid operations.
112+
#
113+
# @example Get the paranoid collection.
114+
# document.paranoid_collection
115+
#
116+
# @return [ Collection ] The root collection.
117+
#
118+
# @since 2.3.1
119+
def paranoid_collection
120+
embedded? ? _root.collection : self.collection
121+
end
122+
123+
# Get the field to be used for paranoid operations.
124+
#
125+
# @example Get the paranoid field.
126+
# document.paranoid_field
127+
#
128+
# @return [ String ] The deleted at field.
129+
#
130+
# @since 2.3.1
131+
def paranoid_field
132+
embedded? ? "#{atomic_position}.deleted_at" : "deleted_at"
133+
end
134+
end
135+
end
136+
137+
module Mongoid
138+
module Relations
139+
module Embedded
140+
class Many < Relations::Many
141+
# For use only with Mongoid::Paranoia - will be removed in 4.0.
142+
#
143+
# @example Get the deleted documents from the relation.
144+
# person.paranoid_phones.deleted
145+
#
146+
# @return [ Criteria ] The deleted documents.
147+
#
148+
# @since 3.0.10
149+
def deleted
150+
unscoped.deleted
151+
end
152+
# This class handles the behaviour for a document that embeds many other
153+
# documents within in it as an array.
154+
end
155+
end
156+
end
157+
end
+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
module Mongoid
2+
module Validations
3+
class UniquenessValidator < ActiveModel::EachValidator
4+
# Scope the criteria to the scope options provided.
5+
#
6+
# @api private
7+
#
8+
# @example Scope the criteria.
9+
# validator.scope(criteria, document)
10+
#
11+
# @param [ Criteria ] criteria The criteria to scope.
12+
# @param [ Document ] document The document being validated.
13+
#
14+
# @return [ Criteria ] The scoped criteria.
15+
#
16+
# @since 2.3.0
17+
def scope(criteria, document, attribute)
18+
Array.wrap(options[:scope]).each do |item|
19+
name = document.database_field_name(item)
20+
criteria = criteria.where(item => document.attributes[name])
21+
end
22+
criteria = criteria.where(deleted_at: nil) if document.respond_to?(:paranoid)
23+
criteria
24+
end
25+
end
26+
end
27+
end
28+
29+
module Mongoid
30+
module Relations
31+
module Builders
32+
module NestedAttributes
33+
class Many < NestedBuilder
34+
# Destroy the child document, needs to do some checking for embedded
35+
# relations and delay the destroy in case parent validation fails.
36+
#
37+
# @api private
38+
#
39+
# @example Destroy the child.
40+
# builder.destroy(parent, relation, doc)
41+
#
42+
# @param [ Document ] parent The parent document.
43+
# @param [ Proxy ] relation The relation proxy.
44+
# @param [ Document ] doc The doc to destroy.
45+
#
46+
# @since 3.0.10
47+
def destroy(parent, relation, doc)
48+
doc.flagged_for_destroy = true
49+
if !doc.embedded? || parent.new_record? || doc.paranoid?
50+
destroy_document(relation, doc)
51+
else
52+
parent.flagged_destroys.push(->{ destroy_document(relation, doc) })
53+
end
54+
end
55+
end
56+
end
57+
end
58+
end
59+
end
60+
61+
module Mongoid
62+
module Relations
63+
module Embedded
64+
# This class handles the behaviour for a document that embeds many other
65+
# documents within in it as an array.
66+
class Many < Relations::Many
67+
# Delete the supplied document from the target. This method is proxied
68+
# in order to reindex the array after the operation occurs.
69+
#
70+
# @example Delete the document from the relation.
71+
# person.addresses.delete(address)
72+
#
73+
# @param [ Document ] document The document to be deleted.
74+
#
75+
# @return [ Document, nil ] The deleted document or nil if nothing deleted.
76+
#
77+
# @since 2.0.0.rc.1
78+
def delete(document)
79+
execute_callback :before_remove, document
80+
doc = target.delete_one(document)
81+
if doc && !_binding?
82+
_unscoped.delete_one(doc) unless doc.paranoid?
83+
if _assigning?
84+
if doc.paranoid?
85+
doc.destroy(suppress: true)
86+
else
87+
base.add_atomic_pull(doc)
88+
end
89+
else
90+
doc.delete(suppress: true)
91+
unbind_one(doc)
92+
end
93+
end
94+
reindex
95+
execute_callback :after_remove, document
96+
doc
97+
end
98+
end
99+
end
100+
end
101+
end

mongoid-paranoia.gemspec

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# -*- encoding: utf-8 -*-
2+
lib = File.expand_path('../lib', __FILE__)
3+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4+
5+
Gem::Specification.new do |gem|
6+
gem.name = "mongoid-paranoia"
7+
gem.version = "0.1"
8+
gem.authors = ["Durran Jordan", "Josef Šimánek"]
9+
10+
gem.description = %q{There may be times when you don't want documents to actually get deleted from the database, but "flagged" as deleted. Mongoid provides a Paranoia module to give you just that.}
11+
gem.summary = %q{Paranoid documents}
12+
gem.homepage = "https://github.com/simi/mongoid-paranoia"
13+
14+
gem.files = `git ls-files`.split($/)
15+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
16+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
17+
gem.require_paths = ["lib"]
18+
19+
gem.add_dependency "mongoid", '~> 4.0'
20+
gem.add_development_dependency "rspec", '~> 2.11'
21+
end

0 commit comments

Comments
 (0)