simply_couch 0.1.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 +7 -0
- data/CHANGELOG.md +182 -0
- data/LICENSE.txt +15 -0
- data/README.md +294 -0
- data/lib/core_ext/date.rb +15 -0
- data/lib/core_ext/time.rb +23 -0
- data/lib/simply_couch/class_methods_base.rb +72 -0
- data/lib/simply_couch/has_attachment.rb +225 -0
- data/lib/simply_couch/include_relation.rb +160 -0
- data/lib/simply_couch/instance_methods.rb +356 -0
- data/lib/simply_couch/locale/en.yml +5 -0
- data/lib/simply_couch/model/ancestry.rb +307 -0
- data/lib/simply_couch/model/association_property.rb +26 -0
- data/lib/simply_couch/model/attachments.rb +90 -0
- data/lib/simply_couch/model/belongs_to.rb +140 -0
- data/lib/simply_couch/model/database.rb +209 -0
- data/lib/simply_couch/model/embedded_in.rb +196 -0
- data/lib/simply_couch/model/find_by.rb +202 -0
- data/lib/simply_couch/model/finders.rb +77 -0
- data/lib/simply_couch/model/has_and_belongs_to_many.rb +223 -0
- data/lib/simply_couch/model/has_many.rb +177 -0
- data/lib/simply_couch/model/has_many_embedded.rb +187 -0
- data/lib/simply_couch/model/has_one.rb +75 -0
- data/lib/simply_couch/model/pagination.rb +25 -0
- data/lib/simply_couch/model/pagination_options.rb +55 -0
- data/lib/simply_couch/model/persistence.rb +411 -0
- data/lib/simply_couch/model/properties.rb +11 -0
- data/lib/simply_couch/model/validations.rb +28 -0
- data/lib/simply_couch/model/view/base_view_spec.rb +115 -0
- data/lib/simply_couch/model/view/custom_view_spec.rb +49 -0
- data/lib/simply_couch/model/view/custom_views.rb +50 -0
- data/lib/simply_couch/model/view/lists.rb +25 -0
- data/lib/simply_couch/model/view/model_view_spec.rb +106 -0
- data/lib/simply_couch/model/view/properties_view_spec.rb +53 -0
- data/lib/simply_couch/model/view/raw_view_spec.rb +30 -0
- data/lib/simply_couch/model/view/view_query.rb +98 -0
- data/lib/simply_couch/model/view.rb +8 -0
- data/lib/simply_couch/model/views/array_property_view_spec.rb +26 -0
- data/lib/simply_couch/model/views/deleted_model_view_spec.rb +43 -0
- data/lib/simply_couch/model/views.rb +2 -0
- data/lib/simply_couch/model.rb +195 -0
- data/lib/simply_couch/rake.rb +23 -0
- data/lib/simply_couch/storage.rb +147 -0
- data/lib/simply_couch.rb +26 -0
- metadata +144 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: ae31eaff1df5b1b5f92f31fc03ed41f757e8d790d5ed6a288bc57f8f15b41f80
|
|
4
|
+
data.tar.gz: 337be26593098ec144a9f89ea94f21e9614dea96ad44f0b6933191fb9ee9a72f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 60edce6ad7801d418943af609c9bef4b09cc5ffeec88acca6ea9e111030f2f9981981c4b26f862d2b013dd260573ea2096e1df890803a03b07ffc6546fefc14e
|
|
7
|
+
data.tar.gz: 21aca11008af8b4ed59fdb5adaf366cf9bdbc7e66db7cee4582879cf64411f44f9faf54658c5e143fc8dd5db5eed7ffa8c6a1d013b795927e5fbd927c80c794b
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
Changelog
|
|
2
|
+
=============
|
|
3
|
+
|
|
4
|
+
1.0.0
|
|
5
|
+
-----
|
|
6
|
+
- Added Contaiment validator
|
|
7
|
+
- Lots of other stuff
|
|
8
|
+
|
|
9
|
+
0.6.8
|
|
10
|
+
|
|
11
|
+
- Lax restriction on ActiveSupport version
|
|
12
|
+
|
|
13
|
+
0.6.7
|
|
14
|
+
|
|
15
|
+
- Rebuild with Ruby 1.8
|
|
16
|
+
|
|
17
|
+
0.6.6
|
|
18
|
+
|
|
19
|
+
- Bump supported CouchPotato version
|
|
20
|
+
|
|
21
|
+
0.6.5
|
|
22
|
+
|
|
23
|
+
- Retry on connection refused errors, useful when CouchDB takes a break in excessive test runs that teardown/re-create many databases
|
|
24
|
+
|
|
25
|
+
0.6.4
|
|
26
|
+
|
|
27
|
+
- Restore Ruby 1.9.2 compatibility
|
|
28
|
+
|
|
29
|
+
0.6.3
|
|
30
|
+
|
|
31
|
+
- Compatible with CouchPotato 0.5.6
|
|
32
|
+
|
|
33
|
+
0.6.2
|
|
34
|
+
|
|
35
|
+
- Decorate conflict exceptions with information about the conflict
|
|
36
|
+
|
|
37
|
+
0.6.1
|
|
38
|
+
|
|
39
|
+
- Fix warning of dynamically created views to point to the correct called
|
|
40
|
+
|
|
41
|
+
0.6.0
|
|
42
|
+
|
|
43
|
+
- Ruby 1.9.2 compatible
|
|
44
|
+
|
|
45
|
+
- compatible with CouchPotato > 0.5 where the attributes are lazy loaded
|
|
46
|
+
|
|
47
|
+
- Depends on ActiveSupport/ActiveModel 3.x
|
|
48
|
+
--> Does not longer work with Rails 2.x !
|
|
49
|
+
|
|
50
|
+
0.5.4
|
|
51
|
+
|
|
52
|
+
- Add Rake task to compact all views in a given database:
|
|
53
|
+
DATABASE=http://localhost:5984/my_db rake simply_couch:compact_design_documents
|
|
54
|
+
|
|
55
|
+
0.5.3
|
|
56
|
+
|
|
57
|
+
- Change implementation of all_documents_without_deleted view so that it can now be passed view parameters
|
|
58
|
+
|
|
59
|
+
0.5.1
|
|
60
|
+
|
|
61
|
+
- Fix nullifying soft deleted objects when they are not deleted
|
|
62
|
+
|
|
63
|
+
0.5.0
|
|
64
|
+
|
|
65
|
+
- Add support for has_and_belongs_to_many relations:
|
|
66
|
+
|
|
67
|
+
n:m relations where the IDs are stored on one part as an array:
|
|
68
|
+
|
|
69
|
+
class Server
|
|
70
|
+
include SimplyCouch::Couch
|
|
71
|
+
|
|
72
|
+
property :hostname
|
|
73
|
+
|
|
74
|
+
has_and_belongs_to_many :networks, :storing_keys => true
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
class Network
|
|
78
|
+
include SimplyCouch::Couch
|
|
79
|
+
|
|
80
|
+
property :klass
|
|
81
|
+
|
|
82
|
+
has_and_belongs_to_many :servers, :storing_keys => false
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
network = Network.create(:klass => "A")
|
|
86
|
+
server = Server.new(:hostname => 'www.example.com')
|
|
87
|
+
network.add_server(server)
|
|
88
|
+
server.network_ids # => [network.id]
|
|
89
|
+
network.servers # => [server]
|
|
90
|
+
server.networks # => [network]
|
|
91
|
+
|
|
92
|
+
The array property holding the IDs of the other item will be used to constuct two view to lookup
|
|
93
|
+
the other part. Soft deleting is only supported on the class holding the IDs.
|
|
94
|
+
|
|
95
|
+
- Add support for .last - which is the same as first by reverse order
|
|
96
|
+
|
|
97
|
+
User.last # => User.find(:first, :order => :desc)
|
|
98
|
+
|
|
99
|
+
- Drop support for SimpleDB
|
|
100
|
+
|
|
101
|
+
0.3.8
|
|
102
|
+
|
|
103
|
+
- Fix loading of has_many/has_one associations for inherited relations.
|
|
104
|
+
|
|
105
|
+
- Pre-populate the parent object on has_many and has_one associations so that user.posts.first.user
|
|
106
|
+
doesn't reload the user.
|
|
107
|
+
|
|
108
|
+
- Add support for associations not named after the class [akm]
|
|
109
|
+
|
|
110
|
+
0.3.3
|
|
111
|
+
|
|
112
|
+
- Fix association counting bug
|
|
113
|
+
|
|
114
|
+
- Introduce :ignore option to has_many :dependent option. If :dependent is set to :ignore,
|
|
115
|
+
dependent objects will not be deleted or nullified but just ignored.
|
|
116
|
+
|
|
117
|
+
0.3.0
|
|
118
|
+
=============
|
|
119
|
+
|
|
120
|
+
- SimplyCouch now automatically retries conflicted save operations if it is possible to resolve the conflict.
|
|
121
|
+
Solving the conflict means that if updated were done one different attributes the local object will
|
|
122
|
+
refresh those attributes and try to save again. This will be tried two times by default. Afterwards the conflict
|
|
123
|
+
exception will be re-raised.
|
|
124
|
+
|
|
125
|
+
This feature can be controlled on the class level like this: User.auto_conflict_resolution_on_save = true | false
|
|
126
|
+
|
|
127
|
+
0.2.5
|
|
128
|
+
=============
|
|
129
|
+
|
|
130
|
+
- Allow to pass a custom logger to S3-attachments / RightAws
|
|
131
|
+
|
|
132
|
+
- Support :order option to has_many associations and classes, e.g:
|
|
133
|
+
|
|
134
|
+
@user.posts(:order => :desc)
|
|
135
|
+
Post.find(:all, :order => :desc)
|
|
136
|
+
|
|
137
|
+
Default to the CouchDB default of ascending.
|
|
138
|
+
Please update ALL design documents!
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
- Support :limit option to has_many and has_many :through associations, e.g:
|
|
142
|
+
|
|
143
|
+
@user.posts(:limit => 5)
|
|
144
|
+
|
|
145
|
+
0.1.14
|
|
146
|
+
=============
|
|
147
|
+
|
|
148
|
+
- Add ability to delete all design documents:
|
|
149
|
+
|
|
150
|
+
SimplyCouch::Couch.delete_all_design_documents('http://localhost:5984/mydbname')
|
|
151
|
+
|
|
152
|
+
- Add rake tasks to delete all design documents. In your Rakefile:
|
|
153
|
+
|
|
154
|
+
require 'simply_couch/rake'
|
|
155
|
+
|
|
156
|
+
Then you can delete all design documents in a database like this:
|
|
157
|
+
|
|
158
|
+
DATABASE=http://localhost:5984/mydb rake simply_couch:delete_design_documents
|
|
159
|
+
|
|
160
|
+
0.1.13
|
|
161
|
+
=============
|
|
162
|
+
|
|
163
|
+
- Please delete all your design documents!
|
|
164
|
+
- Auto-generate count-methods for has_many associations, e.g
|
|
165
|
+
|
|
166
|
+
class Blog
|
|
167
|
+
include SimplyCouch::Couch
|
|
168
|
+
has_many :posts
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
class Post
|
|
172
|
+
include SimplyCouch::Couch
|
|
173
|
+
belongs_to :blog
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
blog = Blog.create
|
|
177
|
+
blog.post_count
|
|
178
|
+
# => 0
|
|
179
|
+
|
|
180
|
+
Post.create(:blog => blog)
|
|
181
|
+
blog.post_count(:force_reload => true)
|
|
182
|
+
# => 1
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2010 Peritor GmbH <info@peritor.com>
|
|
3
|
+
*
|
|
4
|
+
* Permission to use, copy, modify, and distribute this software for any
|
|
5
|
+
* purpose with or without fee is hereby granted, provided that the above
|
|
6
|
+
* copyright notice and this permission notice appear in all copies.
|
|
7
|
+
*
|
|
8
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
9
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
10
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
11
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
12
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
13
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
14
|
+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
15
|
+
*/
|
data/README.md
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# SimplyCouch
|
|
2
|
+
|
|
3
|
+
[](https://rubygems.org/gems/simply_couch)
|
|
4
|
+
[](LICENSE.txt)
|
|
5
|
+
|
|
6
|
+
**Simple CouchDB ORM for Rails** — ActiveModel-compliant, driver-agnostic.
|
|
7
|
+
|
|
8
|
+
Zero driver dependencies. Your app brings its own CouchDB client (couchrest, couchbase, etc.).
|
|
9
|
+
|
|
10
|
+
## History
|
|
11
|
+
|
|
12
|
+
SimplyCouch is based on **[simply_stored](https://github.com/peritor/simply_stored)** (140 ★), created by [Mathias Meyer](https://github.com/roidrage) and [Jonathan Weiss](https://github.com/jweiss) at [Peritor Consulting](https://github.com/peritor) in Berlin (~2010). simply_stored was a convenience layer on top of [CouchPotato](https://github.com/langalex/couch_potato).
|
|
13
|
+
|
|
14
|
+
This fork evolved over a decade with substantial additions — pagination, ancestry trees, embedded documents, include relations, multi-database support, and a migration toward ActiveModel. In 2026, the CouchPotato dependency was fully removed (~930 lines of view system + persistence ported directly into the gem), couchrest was removed from the gemspec, and the gem was renamed to **SimplyCouch** as its own project.
|
|
15
|
+
|
|
16
|
+
**Where are the original authors?** Jonathan Weiss (jweiss) co-founded Scalarium and is active in the Berlin tech scene. Mathias Meyer (roidrage) moved to Amazon Web Services Germany. Peritor's [webistrano](https://github.com/peritor/webistrano) (868 ★) was widely used in the Capistrano era.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
gem 'simply_couch'
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or from git:
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
gem 'simply_couch', git: 'https://github.com/bterkuile/simply_couch.git'
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
You must also add a CouchDB client to your Gemfile (the gem doesn't force one):
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
gem 'couchrest' # or couchbase, or any CouchDB HTTP client
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
class User
|
|
40
|
+
include SimplyCouch::Model
|
|
41
|
+
|
|
42
|
+
property :name
|
|
43
|
+
property :email
|
|
44
|
+
property :active, type: Boolean
|
|
45
|
+
property :last_login, type: Time
|
|
46
|
+
property :tags, type: Array
|
|
47
|
+
|
|
48
|
+
has_many :posts
|
|
49
|
+
belongs_to :company
|
|
50
|
+
|
|
51
|
+
view :by_name, key: :name
|
|
52
|
+
view :active_by_created, key: :created_at, conditions: 'doc.active == true'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class Post
|
|
56
|
+
include SimplyCouch::Model
|
|
57
|
+
|
|
58
|
+
property :title
|
|
59
|
+
property :body
|
|
60
|
+
|
|
61
|
+
belongs_to :user
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# CRUD
|
|
65
|
+
user = User.create(name: 'Alice', email: 'alice@example.com', active: true)
|
|
66
|
+
user.update(name: 'Alice B.')
|
|
67
|
+
user.destroy
|
|
68
|
+
|
|
69
|
+
# Queries
|
|
70
|
+
User.find_by_name('Alice')
|
|
71
|
+
User.find_all_by_active(true)
|
|
72
|
+
User.active_by_created(descending: true)
|
|
73
|
+
User.all(page: 1, per_page: 40)
|
|
74
|
+
|
|
75
|
+
# Associations
|
|
76
|
+
user.posts # => [Post, ...]
|
|
77
|
+
user.posts(limit: 5, order: :desc)
|
|
78
|
+
user.post_count # => 42
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Features
|
|
82
|
+
|
|
83
|
+
### Properties & Type Casting
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
property :name
|
|
87
|
+
property :age, type: Integer
|
|
88
|
+
property :price, type: Float
|
|
89
|
+
property :active, type: Boolean # stored as true/false
|
|
90
|
+
property :last_login, type: Time
|
|
91
|
+
property :tags, type: Array
|
|
92
|
+
property :metadata, type: Hash
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Associations
|
|
96
|
+
|
|
97
|
+
`belongs_to`, `has_many`, `has_many_embedded`, `has_and_belongs_to_many`, `has_one`, `embedded_in`.
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
class Post
|
|
101
|
+
include SimplyCouch::Model
|
|
102
|
+
has_many :comments, dependent: :destroy
|
|
103
|
+
has_many :authors, through: :comments, source: :user
|
|
104
|
+
belongs_to :category
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
class User
|
|
108
|
+
include SimplyCouch::Model
|
|
109
|
+
has_and_belongs_to_many :networks, storing_keys: true
|
|
110
|
+
end
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Validations
|
|
114
|
+
|
|
115
|
+
Standard ActiveModel validations plus a `containment` validator for array properties:
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
class Page
|
|
119
|
+
include SimplyCouch::Model
|
|
120
|
+
property :categories
|
|
121
|
+
validates_containment_of :categories, in: %w[news blog docs]
|
|
122
|
+
end
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Callbacks
|
|
126
|
+
|
|
127
|
+
`before_save`, `after_save`, `before_create`, `after_create`, `before_destroy`, `after_destroy` — all standard ActiveModel callbacks.
|
|
128
|
+
|
|
129
|
+
### Views
|
|
130
|
+
|
|
131
|
+
CouchDB views are auto-generated from your model's property declarations. JavaScript only (Erlang dropped in 2026 port).
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
view :by_status, key: :status
|
|
135
|
+
view :published, key: :created_at, conditions: 'doc.status == "published"'
|
|
136
|
+
view :by_tags, key: :tags # array properties work too
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Custom views and raw map/reduce are supported via view spec classes.
|
|
140
|
+
|
|
141
|
+
### Pagination
|
|
142
|
+
|
|
143
|
+
```ruby
|
|
144
|
+
Post.all(page: 2, per_page: 25)
|
|
145
|
+
User.active_by_created(page: 1, per_page: 50, descending: true)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Soft Delete
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
class Document
|
|
152
|
+
include SimplyCouch::Model
|
|
153
|
+
enable_soft_delete # defaults to :deleted_at
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
doc = Document.create(title: 'draft')
|
|
157
|
+
doc.destroy
|
|
158
|
+
Document.all # => [] (soft-deleted filtered out)
|
|
159
|
+
Document.all(with_deleted: true) # => [doc] (recoverable)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Ancestry (Tree Structures)
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
class Page
|
|
166
|
+
include SimplyCouch::Model
|
|
167
|
+
property :title
|
|
168
|
+
has_ancestry
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Build trees
|
|
172
|
+
parent = Page.create(title: 'Products')
|
|
173
|
+
child = Page.create(title: 'Widgets', parent: parent)
|
|
174
|
+
|
|
175
|
+
# Query trees
|
|
176
|
+
Page.roots # pages with no parent
|
|
177
|
+
Page.full_tree # entire tree loaded in one query
|
|
178
|
+
parent.children # direct children
|
|
179
|
+
parent.descendants # all descendants (flattened)
|
|
180
|
+
child.ancestors # path to root
|
|
181
|
+
|
|
182
|
+
# Scoped trees (different trees per property)
|
|
183
|
+
has_ancestry by_property: :locale
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Dynamic Finders
|
|
187
|
+
|
|
188
|
+
```ruby
|
|
189
|
+
User.find_by_name('Alice')
|
|
190
|
+
User.find_all_by_active(true)
|
|
191
|
+
User.count_by_active(true)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Include Relations
|
|
195
|
+
|
|
196
|
+
Eager-load associations to avoid N+1 queries on CouchDB:
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
Post.all(include: :user) # loads users with posts
|
|
200
|
+
Post.all(include: [:user, :comments]) # multiple associations
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Conflict Resolution
|
|
204
|
+
|
|
205
|
+
Auto-merge on CouchDB conflicts by default (can be disabled):
|
|
206
|
+
|
|
207
|
+
```ruby
|
|
208
|
+
User.auto_conflict_resolution_on_save = false # disable
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Multi-Database Support
|
|
212
|
+
|
|
213
|
+
```ruby
|
|
214
|
+
class ArchivedPost
|
|
215
|
+
include SimplyCouch::Model
|
|
216
|
+
use_database 'http://couchdb:5984/archive'
|
|
217
|
+
end
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Design Document Splitting
|
|
221
|
+
|
|
222
|
+
Prevent full view reindexing when adding a new view:
|
|
223
|
+
|
|
224
|
+
```ruby
|
|
225
|
+
class Post
|
|
226
|
+
include SimplyCouch::Model
|
|
227
|
+
split_design_documents_per_view # each view → own _design doc
|
|
228
|
+
|
|
229
|
+
view :by_user_id, key: :user_id # → _design/Post_view_by_user_id
|
|
230
|
+
view :by_status, key: :status # → _design/Post_view_by_status
|
|
231
|
+
end
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Without splitting, changing any view reindexes all views. On large databases, this can take hours.
|
|
235
|
+
With splitting, only the new/changed view reindexes.
|
|
236
|
+
|
|
237
|
+
### Attachments
|
|
238
|
+
|
|
239
|
+
SimplyCouch supports **two** attachment strategies — use the one that fits your use case:
|
|
240
|
+
|
|
241
|
+
#### 1. CouchDB Native Inline Attachments
|
|
242
|
+
|
|
243
|
+
```ruby
|
|
244
|
+
class Invoice
|
|
245
|
+
include SimplyCouch::Model
|
|
246
|
+
include SimplyCouch::Model::Attachments
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
invoice.put_attachment('receipt.pdf', file, content_type: 'application/pdf')
|
|
250
|
+
invoice.fetch_attachment('receipt.pdf')
|
|
251
|
+
invoice.delete_attachment('receipt.pdf')
|
|
252
|
+
invoice.attachment_names # => ['receipt.pdf', 'logo.png']
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Attachments are stored inline in the CouchDB document — atomic, no extra storage, replicable.
|
|
256
|
+
|
|
257
|
+
#### 2. ActiveStorage Compatibility
|
|
258
|
+
|
|
259
|
+
*Coming soon — `has_one_attached` / `has_many_attached` backed by CouchDB attachments.*
|
|
260
|
+
|
|
261
|
+
See `docs/attachments.md` for a detailed comparison of approaches.
|
|
262
|
+
|
|
263
|
+
### Legacy: S3 Attachments
|
|
264
|
+
|
|
265
|
+
The `has_s3_attachment` method (using RightAws) exists but is **unmaintained and untested**.
|
|
266
|
+
It was part of the original simply_stored and has not been verified in years. Use CouchDB
|
|
267
|
+
native attachments or ActiveStorage instead.
|
|
268
|
+
|
|
269
|
+
## Dependencies
|
|
270
|
+
|
|
271
|
+
| Gem | Version | Notes |
|
|
272
|
+
|-----|---------|-------|
|
|
273
|
+
| activemodel | >= 6.0 | Validations, callbacks, dirty tracking |
|
|
274
|
+
| activesupport | >= 6.0 | Inflections, callbacks, concern |
|
|
275
|
+
|
|
276
|
+
**No CouchDB driver dependency.** Add `couchrest` or `couchbase` to your app's Gemfile.
|
|
277
|
+
|
|
278
|
+
## Testing
|
|
279
|
+
|
|
280
|
+
Uses RSpec with an in-memory CouchDB via [RockingChair](https://github.com/jweiss/rocking_chair).
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
bundle exec rspec
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## License
|
|
287
|
+
|
|
288
|
+
BSD 2-Clause — see [LICENSE.txt](LICENSE.txt)
|
|
289
|
+
|
|
290
|
+
## Credits
|
|
291
|
+
|
|
292
|
+
- **Original simply_stored:** [Mathias Meyer](https://github.com/roidrage) & [Jonathan Weiss](https://github.com/jweiss) at [Peritor Consulting](https://github.com/peritor)
|
|
293
|
+
- **Fork & simply_couch:** [Benjamin ter Kuile](https://github.com/bterkuile)
|
|
294
|
+
- **CouchPotato removal + 2026 port:** BenClaw & Benjamin ter Kuile
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'active_support/time'
|
|
2
|
+
# use ISO8601 as timeformat
|
|
3
|
+
class Time
|
|
4
|
+
def to_json(*a)
|
|
5
|
+
%|"#{as_json}"|
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def as_json(*args)
|
|
9
|
+
getutc.iso8601
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.json_create string
|
|
13
|
+
return nil if string.nil?
|
|
14
|
+
d = DateTime.parse(string.to_s).new_offset
|
|
15
|
+
self.utc(d.year, d.month, d.day, d.hour, d.min, d.sec).in_time_zone
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
ActiveSupport::TimeWithZone.class_eval do
|
|
20
|
+
def as_json(*args)
|
|
21
|
+
utc.iso8601
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module SimplyCouch
|
|
2
|
+
module ClassMethods
|
|
3
|
+
module Base
|
|
4
|
+
def get_class_from_name(klass_name)
|
|
5
|
+
# Try to find class from property definition
|
|
6
|
+
if property = _find_property(klass_name) and property.respond_to?(:options) and property.options[:class_name].present?
|
|
7
|
+
property.options[:class_name].constantize
|
|
8
|
+
else # Fall back to name guessing
|
|
9
|
+
base = klass_name.to_s.gsub('__','/')
|
|
10
|
+
base = base.classify unless base[0,1] =~ /[A-Z]/
|
|
11
|
+
base.constantize
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def foreign_key
|
|
16
|
+
name.underscore.gsub('/','__').gsub('::','__') + "_id"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def foreign_property
|
|
20
|
+
name.underscore.gsub('/','__').gsub('::','__')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def attr_protected(*args)
|
|
24
|
+
@_protected_attributes ||= []
|
|
25
|
+
@_protected_attributes += args.to_a
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def attr_accessible(*args)
|
|
29
|
+
@_accessible_attributes ||= []
|
|
30
|
+
@_accessible_attributes += args.to_a
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def _find_property(name)
|
|
34
|
+
properties.find{|property| property.name == name}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Namespace aware method of creating proper class names
|
|
38
|
+
def find_association_class_name(association_name)
|
|
39
|
+
(name.split('::')[0..-2] + [association_name.to_s.singularize.camelize]).join('::')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# More compatibility with active record plugins
|
|
43
|
+
def primary_key
|
|
44
|
+
'id'
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def view(view_name, options)
|
|
48
|
+
options[:reduce] = options.delete(:reduce_function) if options[:reduce_function]
|
|
49
|
+
options[:map] = options.delete(:map_function) if options[:map_function]
|
|
50
|
+
super(view_name, options)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Fix for paperclip > 3.5.2
|
|
54
|
+
def after_commit(*); end
|
|
55
|
+
|
|
56
|
+
# Get documents by ids and bulk update attributes
|
|
57
|
+
def bulk_update(ids, pairs)
|
|
58
|
+
# Bulk load documents
|
|
59
|
+
# Map to doc
|
|
60
|
+
# Filter out errors, or none founds (compact)
|
|
61
|
+
# Select the Couch objects
|
|
62
|
+
docs = database.couchrest_database.bulk_load(ids)['rows'].map{|r| r['doc']}.compact.select{|d| d.is_a?(SimplyCouch::Model)}
|
|
63
|
+
for doc in docs
|
|
64
|
+
pairs.each_pair do |k, v|
|
|
65
|
+
doc.send("#{k}=", v) if doc.respond_to?("#{k}=")
|
|
66
|
+
end
|
|
67
|
+
doc.save # Should become a bulk update in the future
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|