mongocore 0.1.0 → 0.1.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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +9 -0
- data/LICENSE +21 -0
- data/README.md +367 -0
- data/config/boot.rb +23 -0
- data/config/db/schema/model.yml +103 -0
- data/config/db/schema/parent.yml +41 -0
- data/lib/mongocore/access.rb +63 -0
- data/lib/mongocore/cache.rb +41 -0
- data/lib/mongocore/document.rb +301 -0
- data/lib/mongocore/filters.rb +45 -0
- data/lib/mongocore/query.rb +125 -0
- data/lib/mongocore/schema.rb +117 -0
- data/lib/mongocore.rb +5 -0
- data/models/model.rb +44 -0
- data/models/parent.rb +30 -0
- data/mongocore.gemspec +22 -0
- metadata +18 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 930f0c5ba53f15b7014cb473803554975acf1679
|
4
|
+
data.tar.gz: 6d84ab1c806b72b558641f89cbb3608d7ee34c79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 750dcd341fee0a1266951f93705d6aeb02a03f5b0ef44af2c439ccc5d2db0d284da1d241a325393982662b88a436b61cecf768850547d252e0842dfd1fc6b42c
|
7
|
+
data.tar.gz: 9a98403d956ae87fec94e8833a6bdd6acd9d0ed9ea2c4979629b84ce0f69ff72b6542b04da5b87cd6dfb657f239cdccea37c371d9574647959714080d65a902e
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2016 Fugroup
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,367 @@
|
|
1
|
+
# Mongocore Ruby Database Driver
|
2
|
+
A new MongoDB ORM implementation on top of the [MongoDB Ruby driver.](https://docs.mongodb.com/ruby-driver/master/quick-start/) Very fast and light weight.
|
3
|
+
|
4
|
+
The perfect companion for Sinatra or other Rack-based web frameworks.
|
5
|
+
|
6
|
+
### Features
|
7
|
+
With Mongocore you can do:
|
8
|
+
|
9
|
+
* Insert, update and delete
|
10
|
+
* Finding, sorting, limit, defaults
|
11
|
+
* Scopes, associations, validations
|
12
|
+
* Read and write access control for each key
|
13
|
+
* Request cache, counter cache, track changes
|
14
|
+
* Automatic timestamps, tagged keys
|
15
|
+
|
16
|
+
The schema is specified with a YAML file which supports default values, data types, and security levels for each key.
|
17
|
+
|
18
|
+
Please read [the source code](https://github.com/fugroup/mongocore/tree/master/lib/mongocore) to see how it works, it's fully commented and very small, only 7 files, and 354 lines of fully test driven code.
|
19
|
+
|
20
|
+
| Library | Files | Comment | Lines of code |
|
21
|
+
| -------------------------------------- | ----- | ------- | ------------- |
|
22
|
+
| [Mongoid](http://mongoid.com) | 256 | 14371 | 10590 |
|
23
|
+
| [MongoMapper](http://mongomapper.com) | 91 | 200 | 4070 |
|
24
|
+
| [Mongocore](http://mongocore.com) | 7 | 224 | 354 |
|
25
|
+
|
26
|
+
<br>
|
27
|
+
If you are looking for something even lighter, we also [have Minimongo,](https://github.com/fugroup/minimongo) the world's tiniest MongoDB library.
|
28
|
+
|
29
|
+
The tests are written [using Futest,](https://github.com/fugroup/futest) try it out if you haven't, it makes testing so much fun.
|
30
|
+
|
31
|
+
### Installation
|
32
|
+
```
|
33
|
+
gem install mongocore
|
34
|
+
```
|
35
|
+
or add to your Gemfile.
|
36
|
+
|
37
|
+
Then in your model:
|
38
|
+
```ruby
|
39
|
+
class Model
|
40
|
+
include Mongocore::Document
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
### Settings
|
45
|
+
Mongocore has a few built in settings you can easily toggle:
|
46
|
+
```ruby
|
47
|
+
# Schema path is $app_root/config/db/schema/:model.yml
|
48
|
+
# The yml files should have singular names
|
49
|
+
Mongocore.schema = File.join(Dir.pwd, 'config', 'db', 'schema')
|
50
|
+
|
51
|
+
# The cache stores documents in memory to avoid db round trips
|
52
|
+
Mongocore.cache = true
|
53
|
+
|
54
|
+
# The access enables the read / write access levels for the keys
|
55
|
+
Mongocore.access = true
|
56
|
+
|
57
|
+
# Enable timestamps, auto-save created_at and updated_at keys
|
58
|
+
Mongocore.timestamps = true
|
59
|
+
|
60
|
+
# Enable debug to see caching information and help
|
61
|
+
Mongocore.debug = false
|
62
|
+
```
|
63
|
+
|
64
|
+
### Usage
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
# Create a new document
|
68
|
+
m = Model.new
|
69
|
+
m.duration = 59
|
70
|
+
m.save
|
71
|
+
|
72
|
+
# Create another document
|
73
|
+
p = Parent.new(:house => 'Nice')
|
74
|
+
p.save
|
75
|
+
|
76
|
+
# Reload the model attributes from the database
|
77
|
+
p.reload
|
78
|
+
|
79
|
+
# Add the parent to the model
|
80
|
+
m.parent = p
|
81
|
+
m.save
|
82
|
+
|
83
|
+
# Finding
|
84
|
+
query = Model.find
|
85
|
+
|
86
|
+
# Query doesn't get executed until you call all, count, last or first
|
87
|
+
m = query.all
|
88
|
+
a = query.featured.all
|
89
|
+
c = query.count
|
90
|
+
l = query.last
|
91
|
+
f = query.first
|
92
|
+
|
93
|
+
# All
|
94
|
+
m = Model.find.all
|
95
|
+
|
96
|
+
# All of these can be used:
|
97
|
+
# https://docs.mongodb.com/manual/reference/operator/query-comparison
|
98
|
+
m = Model.find(:house => {:$ne => nil, :$eq => 'Nice'}).last
|
99
|
+
|
100
|
+
# Sorting, use -1 for descending, 1 for ascending
|
101
|
+
m = Model.find({:duration => {:$gt => 40}}, {}, :sort => {:duration => -1}).all
|
102
|
+
m = p.models.find(:duration => 10).sort(:duration => -1).first
|
103
|
+
|
104
|
+
# Limit, pass as third option to find or chain, up to you
|
105
|
+
p = Parent.find.sort(:duration => 1).limit(5).all
|
106
|
+
p = Parent.limit(1).last
|
107
|
+
m = p.models.find({}, {}, :sort => {:goal => 1}, :limit => 1).first
|
108
|
+
m = Model.sort(:goal => 1, :duration => -1).limit(10).all
|
109
|
+
|
110
|
+
# First
|
111
|
+
m = Model.find(:_id => object_id).first
|
112
|
+
m = Model.find(object_id).first
|
113
|
+
m = Model.find(string).first
|
114
|
+
m = Model.find(:duration => 60, :goal => {:$gt => 0}).first
|
115
|
+
|
116
|
+
# Last
|
117
|
+
m = Model.last
|
118
|
+
m = p.models.last
|
119
|
+
|
120
|
+
# Count
|
121
|
+
c = Model.count
|
122
|
+
c = p.models.featured.count
|
123
|
+
|
124
|
+
# Tagged keys for attributes and to_json
|
125
|
+
m = Model.first
|
126
|
+
m.attributes # => All attributes
|
127
|
+
m.attributes(:badge) # => Attributes with the badge tag only
|
128
|
+
m.to_json # => All attributes as json
|
129
|
+
m.to_json(:badge, :test) # => Pass multiple tags if needed
|
130
|
+
|
131
|
+
# Track changes
|
132
|
+
m.duration = 33
|
133
|
+
m.changed?
|
134
|
+
m.duration_changed?
|
135
|
+
m.duration_was
|
136
|
+
m.changes
|
137
|
+
m.saved?
|
138
|
+
m.unsaved?
|
139
|
+
|
140
|
+
# Validate
|
141
|
+
m.valid?
|
142
|
+
m.errors.any?
|
143
|
+
m.errors
|
144
|
+
|
145
|
+
# Update
|
146
|
+
m.update(:duration => 60)
|
147
|
+
|
148
|
+
# Delete
|
149
|
+
m.delete
|
150
|
+
|
151
|
+
# Many associations
|
152
|
+
q = p.models.all
|
153
|
+
m = p.models.first
|
154
|
+
m = p.models.last
|
155
|
+
|
156
|
+
# Scopes
|
157
|
+
q = p.models.featured.all
|
158
|
+
q = p.models.featured.nested.all
|
159
|
+
m = Model.featured.first
|
160
|
+
|
161
|
+
# In your model
|
162
|
+
class Model
|
163
|
+
include Mongocore::Document
|
164
|
+
|
165
|
+
# Validations will be run if you pass model.save(:validate => true)
|
166
|
+
# You can run them manually by calling model.valid?
|
167
|
+
# You can have multiple validate blocks if you want to
|
168
|
+
validate do
|
169
|
+
# The errors hash can be used to collect error messages.
|
170
|
+
errors[:duration] << 'duration must be greater than 0' if duration and duration < 1
|
171
|
+
errors[:goal] << 'you need a higher goal' if goal and goal < 5
|
172
|
+
end
|
173
|
+
|
174
|
+
# Before and after, filters: :save, :update, :delete
|
175
|
+
# You can have multiple blocks for each filter if needed
|
176
|
+
before :save, :setup
|
177
|
+
|
178
|
+
def setup
|
179
|
+
puts "Before save"
|
180
|
+
end
|
181
|
+
|
182
|
+
after :delete do
|
183
|
+
puts "After delete"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Use pure Ruby driver, returns BSON::Document objects
|
188
|
+
Mongocore.db[:models].find.to_a
|
189
|
+
Mongocore.db[:models].find({:_id => m._id}).first
|
190
|
+
|
191
|
+
# Indexing
|
192
|
+
Mongocore.db[:models].indexes.create_one({:key => 1})
|
193
|
+
Mongocore.db[:models].indexes.create_one({:key => 1}, :unique => true)
|
194
|
+
```
|
195
|
+
|
196
|
+
### Schema
|
197
|
+
For keys, defaults, description, counters, associations, scopes and accessors, use a schema file written in [YAML.](http://yaml.org)
|
198
|
+
|
199
|
+
#### Parent example schema
|
200
|
+
```yml
|
201
|
+
|
202
|
+
# The meta is information about your model
|
203
|
+
meta:
|
204
|
+
name: parent
|
205
|
+
type: document
|
206
|
+
|
207
|
+
keys:
|
208
|
+
|
209
|
+
# Use the _id everywhere. The id can be used for whatever you want.
|
210
|
+
# @desc: Describes the key, can be used for documentation.
|
211
|
+
# @type: object_id, string, integer, float, boolean, time, hash, array
|
212
|
+
# @default: the default value for the key when you call .new
|
213
|
+
# @read: access level for read: all, user, dev, admin, super, app
|
214
|
+
# @write: access level for write. Returns nil if no access, as on read
|
215
|
+
|
216
|
+
# Object ID, usually added for each model
|
217
|
+
_id:
|
218
|
+
desc: Unique id
|
219
|
+
type: object_id
|
220
|
+
read: all
|
221
|
+
write: app
|
222
|
+
|
223
|
+
# String key
|
224
|
+
world:
|
225
|
+
desc: Parent world
|
226
|
+
type: string
|
227
|
+
read: all
|
228
|
+
write: user
|
229
|
+
|
230
|
+
# If the key ends with _count, it will be used automatically when
|
231
|
+
# you call .count on the model as an automatic caching mechanism
|
232
|
+
models_count:
|
233
|
+
desc: Models count
|
234
|
+
type: integer
|
235
|
+
default: 0
|
236
|
+
read: all
|
237
|
+
write: app
|
238
|
+
|
239
|
+
# This field will be returned when you write models.featured.count
|
240
|
+
# Remember to create an after filter to keep it updated
|
241
|
+
models_featured_count:
|
242
|
+
desc: Models featured count
|
243
|
+
type: integer
|
244
|
+
default: 0
|
245
|
+
read: all
|
246
|
+
write: app
|
247
|
+
|
248
|
+
# Many relationships lets you do:
|
249
|
+
# Model.parents.all or model.parents.featured.all with scopes
|
250
|
+
many:
|
251
|
+
models:
|
252
|
+
dependent: destroy
|
253
|
+
```
|
254
|
+
|
255
|
+
|
256
|
+
#### Model example schema
|
257
|
+
|
258
|
+
```yml
|
259
|
+
meta:
|
260
|
+
name: model
|
261
|
+
type: document
|
262
|
+
|
263
|
+
keys:
|
264
|
+
# Object ID
|
265
|
+
_id:
|
266
|
+
desc: Unique id
|
267
|
+
type: object_id
|
268
|
+
read: all
|
269
|
+
write: app
|
270
|
+
|
271
|
+
# Integer key with default
|
272
|
+
duration:
|
273
|
+
desc: Model duration in days
|
274
|
+
type: integer
|
275
|
+
default: 60
|
276
|
+
read: dev
|
277
|
+
write: user
|
278
|
+
# Add tags for keys for use with attributes and to_json
|
279
|
+
tags:
|
280
|
+
- badge
|
281
|
+
|
282
|
+
# Time key
|
283
|
+
expires_at:
|
284
|
+
desc: Model expiry date
|
285
|
+
type: time
|
286
|
+
read: all
|
287
|
+
write: dev
|
288
|
+
# Multiple tags possible: to_json(:badge, :campaigns)
|
289
|
+
tags:
|
290
|
+
- badge
|
291
|
+
- campaigns
|
292
|
+
|
293
|
+
# Hash key
|
294
|
+
location_data:
|
295
|
+
desc: Model location data
|
296
|
+
type: hash
|
297
|
+
read: all
|
298
|
+
write: user
|
299
|
+
|
300
|
+
# Counter key
|
301
|
+
votes_count:
|
302
|
+
desc: Votes count
|
303
|
+
type: integer
|
304
|
+
default: 0
|
305
|
+
read: all
|
306
|
+
write: dev
|
307
|
+
tags:
|
308
|
+
- badge
|
309
|
+
|
310
|
+
# If the key ends with _id, it is treated as a foreign key,
|
311
|
+
# and you can access it from the referencing model and set it too.
|
312
|
+
# Example: model.parent, model.parent = parent
|
313
|
+
parent_id:
|
314
|
+
desc: Parent id
|
315
|
+
type: object_id
|
316
|
+
read: all
|
317
|
+
write: dev
|
318
|
+
|
319
|
+
# Generate accessors (attr_accessor) for each key
|
320
|
+
accessor:
|
321
|
+
- submittable
|
322
|
+
- update_expires_at
|
323
|
+
- skip_before_save
|
324
|
+
|
325
|
+
# Define scopes that lets you do Models.featured.count
|
326
|
+
# Each scope has a name, and a set of triggers
|
327
|
+
scopes:
|
328
|
+
|
329
|
+
# This will create a .featured scope, and add :duration => 60 to the query.
|
330
|
+
featured:
|
331
|
+
duration: 60
|
332
|
+
|
333
|
+
nested:
|
334
|
+
goal: 10
|
335
|
+
|
336
|
+
# Any mongodb driver query is possible
|
337
|
+
finished:
|
338
|
+
duration: 60
|
339
|
+
goal:
|
340
|
+
$gt: 10
|
341
|
+
|
342
|
+
active:
|
343
|
+
params:
|
344
|
+
- duration
|
345
|
+
duration:
|
346
|
+
$ne: duration
|
347
|
+
|
348
|
+
# You can also pass parameters into the scope, as a lambda.
|
349
|
+
ending:
|
350
|
+
params:
|
351
|
+
- user
|
352
|
+
$or:
|
353
|
+
- user_id: user.id
|
354
|
+
- listener: user.id
|
355
|
+
- listener: user.link
|
356
|
+
deletors:
|
357
|
+
$ne: user.id
|
358
|
+
```
|
359
|
+
|
360
|
+
### Contribute
|
361
|
+
Contributions and feedback are welcome! MIT Licensed.
|
362
|
+
|
363
|
+
Issues will be fixed, this library is actively maintained by [Fugroup Ltd.](http://www.fugroup.net) We are the creators of [CrowdfundHQ.](https://crowdfundhq.com)
|
364
|
+
|
365
|
+
Thanks!
|
366
|
+
|
367
|
+
`@authors: Vidar`
|
data/config/boot.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
Bundler.require(:default, :development, :test)
|
3
|
+
|
4
|
+
MODE = ENV['RACK_ENV'] || 'test'
|
5
|
+
|
6
|
+
require './lib/mongocore.rb'
|
7
|
+
|
8
|
+
# Add settings here
|
9
|
+
Mongocore.schema = File.join(Dir.pwd, 'config', 'db', 'schema')
|
10
|
+
|
11
|
+
require './models/parent.rb'
|
12
|
+
require './models/model.rb'
|
13
|
+
|
14
|
+
# Logging verbosity
|
15
|
+
Mongo::Logger.logger.level = ::Logger::DEBUG
|
16
|
+
Mongo::Logger.logger.level = ::Logger::FATAL
|
17
|
+
|
18
|
+
# To make the driver log to a logfile instead:
|
19
|
+
# Mongo::Logger.logger = ::Logger.new('mongo.log')
|
20
|
+
# Mongo::Logger.logger.level = ::Logger::INFO
|
21
|
+
|
22
|
+
# Connect to DB
|
23
|
+
Mongocore.db = Mongo::Client.new(['127.0.0.1:27017'], :database => "mongocore_#{MODE}")
|
@@ -0,0 +1,103 @@
|
|
1
|
+
---
|
2
|
+
meta:
|
3
|
+
name: model
|
4
|
+
type: document
|
5
|
+
keys:
|
6
|
+
_id:
|
7
|
+
desc: Unique id
|
8
|
+
type: object_id
|
9
|
+
read: all
|
10
|
+
write: app
|
11
|
+
link:
|
12
|
+
desc: Model link
|
13
|
+
read: all
|
14
|
+
write: dev
|
15
|
+
tags:
|
16
|
+
- badge
|
17
|
+
goal:
|
18
|
+
desc: Model goal
|
19
|
+
type: float
|
20
|
+
read: all
|
21
|
+
write: user
|
22
|
+
tags:
|
23
|
+
- badge
|
24
|
+
duration:
|
25
|
+
desc: Model duration in days
|
26
|
+
type: integer
|
27
|
+
default: 60
|
28
|
+
read: dev
|
29
|
+
write: user
|
30
|
+
tags:
|
31
|
+
- badge
|
32
|
+
expires_at:
|
33
|
+
desc: Model expiry date
|
34
|
+
type: time
|
35
|
+
read: all
|
36
|
+
write: dev
|
37
|
+
tags:
|
38
|
+
- badge
|
39
|
+
location_data:
|
40
|
+
desc: Model location data
|
41
|
+
type: hash
|
42
|
+
read: all
|
43
|
+
write: user
|
44
|
+
reminders_sent:
|
45
|
+
desc: Reminders sent?
|
46
|
+
type: boolean
|
47
|
+
default: false
|
48
|
+
read: user
|
49
|
+
write: dev
|
50
|
+
votes_count:
|
51
|
+
desc: Votes count
|
52
|
+
type: integer
|
53
|
+
default: 0
|
54
|
+
read: all
|
55
|
+
write: dev
|
56
|
+
tags:
|
57
|
+
- badge
|
58
|
+
parent_id:
|
59
|
+
desc: Parent id
|
60
|
+
type: object_id
|
61
|
+
read: all
|
62
|
+
write: dev
|
63
|
+
created_at:
|
64
|
+
desc: Created at
|
65
|
+
type: time
|
66
|
+
read: all
|
67
|
+
write: dev
|
68
|
+
updated_at:
|
69
|
+
desc: Updated at
|
70
|
+
type: time
|
71
|
+
read: all
|
72
|
+
write: dev
|
73
|
+
|
74
|
+
accessor:
|
75
|
+
- submittable
|
76
|
+
- update_expires_at
|
77
|
+
- skip_before_save
|
78
|
+
- owner
|
79
|
+
- validate_campaign_fields
|
80
|
+
- update_link
|
81
|
+
scopes:
|
82
|
+
featured:
|
83
|
+
duration: 60
|
84
|
+
nested:
|
85
|
+
goal: 10
|
86
|
+
finished:
|
87
|
+
duration: 60
|
88
|
+
goal:
|
89
|
+
$gt: 10
|
90
|
+
active:
|
91
|
+
params:
|
92
|
+
- duration
|
93
|
+
duration:
|
94
|
+
$ne: duration
|
95
|
+
ending:
|
96
|
+
params:
|
97
|
+
- user
|
98
|
+
$or:
|
99
|
+
- user_id: user.id
|
100
|
+
- listener: user.id
|
101
|
+
- listener: user.link
|
102
|
+
deletors:
|
103
|
+
$ne: user.id
|
@@ -0,0 +1,41 @@
|
|
1
|
+
---
|
2
|
+
meta:
|
3
|
+
name: parent
|
4
|
+
type: document
|
5
|
+
keys:
|
6
|
+
_id:
|
7
|
+
desc: Unique id
|
8
|
+
type: object_id
|
9
|
+
read: all
|
10
|
+
write: app
|
11
|
+
house:
|
12
|
+
desc: Parent house
|
13
|
+
type: string
|
14
|
+
read: all
|
15
|
+
write: user
|
16
|
+
models_count:
|
17
|
+
desc: Models count
|
18
|
+
type: integer
|
19
|
+
default: 0
|
20
|
+
read: all
|
21
|
+
write: app
|
22
|
+
models_featured_count:
|
23
|
+
desc: Models featured count
|
24
|
+
type: integer
|
25
|
+
default: 0
|
26
|
+
read: all
|
27
|
+
write: app
|
28
|
+
models_featured_nested_count:
|
29
|
+
desc: Models nested featured count
|
30
|
+
type: integer
|
31
|
+
default: 0
|
32
|
+
read: all
|
33
|
+
write: app
|
34
|
+
link:
|
35
|
+
desc: Link
|
36
|
+
read: all
|
37
|
+
write: dev
|
38
|
+
|
39
|
+
many:
|
40
|
+
models:
|
41
|
+
dependent: destroy
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Mongocore
|
2
|
+
class Access
|
3
|
+
|
4
|
+
# # # # # # # #
|
5
|
+
# The Access class is responsible for checking if an attribute
|
6
|
+
# can be read or written. It uses 6 access levels and the
|
7
|
+
# read and write attributes in the schema yml file for the model.
|
8
|
+
#
|
9
|
+
# If your current access level is above the key level, then you
|
10
|
+
# can read or write, if not you get nil. This is very useful for APIs
|
11
|
+
# where f.ex. you want to show the email to logged in users, but not to all.
|
12
|
+
#
|
13
|
+
|
14
|
+
# Access levels (6)
|
15
|
+
AL = [:all, :user, :dev, :admin, :super, :app]
|
16
|
+
|
17
|
+
# Holds the keys from the model schema
|
18
|
+
attr_accessor :keys
|
19
|
+
|
20
|
+
# The access control class
|
21
|
+
def initialize(schema)
|
22
|
+
@keys = schema.keys
|
23
|
+
end
|
24
|
+
|
25
|
+
# Set the current access level
|
26
|
+
def set(level = nil)
|
27
|
+
set?(level) ? RequestStore.store[:access] = level : get
|
28
|
+
end
|
29
|
+
|
30
|
+
# Get the current access level
|
31
|
+
def get
|
32
|
+
RequestStore.store[:access]
|
33
|
+
end
|
34
|
+
|
35
|
+
# Reset the access level
|
36
|
+
def reset
|
37
|
+
RequestStore.store[:access] = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
# Key readable?
|
41
|
+
def read?(key)
|
42
|
+
ok?(keys[key][:read]) rescue false
|
43
|
+
end
|
44
|
+
|
45
|
+
# Key writable?
|
46
|
+
def write?(key)
|
47
|
+
ok?(keys[key][:write]) rescue false
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
# Set?
|
53
|
+
def set?(level)
|
54
|
+
AL.index(level) > AL.index(get || :all)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Ok?
|
58
|
+
def ok?(level)
|
59
|
+
!Mongocore.access || AL.index(level.to_sym) <= AL.index(get || :app)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Mongocore
|
2
|
+
|
3
|
+
# # # # # # # #
|
4
|
+
# The Cache class keeps track of cache entries.
|
5
|
+
#
|
6
|
+
# Every query is cached, used the state as the cache key. This is a
|
7
|
+
# very aggressive strategy, where arrays won't get updated on update or delete.
|
8
|
+
#
|
9
|
+
|
10
|
+
class Cache
|
11
|
+
|
12
|
+
# Accessors
|
13
|
+
attr_accessor :query, :cache, :key, :type
|
14
|
+
|
15
|
+
# Init
|
16
|
+
def initialize(q)
|
17
|
+
@query = q
|
18
|
+
@cache = (RequestStore[:cache] ||= {})
|
19
|
+
@key = Digest::MD5.hexdigest(@query.key)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Get the cache key
|
23
|
+
def get(t)
|
24
|
+
@cache[t = key + t.to_s].tap{|d| stat(d, t) if Mongocore.debug}
|
25
|
+
end
|
26
|
+
|
27
|
+
# Set the cache key
|
28
|
+
def set(t, v = nil)
|
29
|
+
t = key + t.to_s; v ? cache[t] = v : cache.delete(t)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# Stats for debug and cache
|
35
|
+
def stat(d, t)
|
36
|
+
puts('Cache ' + (d ? 'Hit!' : 'Miss') + ': ' + t)
|
37
|
+
RequestStore[d ? :h : :m] = (RequestStore[d ? :h : :m] || 0) + 1
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|