mementus 0.1.2 → 0.1.3
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 +8 -8
- data/README.md +37 -12
- data/lib/mementus/model.rb +13 -40
- data/lib/mementus/relation.rb +56 -0
- data/lib/mementus/version.rb +1 -1
- data/lib/mementus.rb +2 -0
- data/spec/collection_spec.rb +4 -3
- data/spec/scopes_spec.rb +30 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MjM0MTczODAxNTlkNmQ3ODYwMzdlYWEzNzNjMGIyNTE1YWQ2NWZiMw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YTgyZDJmZjFlMTY0NjUwODNkMDI0OWZjYTIzYzBjYjZhOTUzMTc0Yw==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YjEwYWFhNmIwYWFhYjM3NWNmNDg2ZjY4MTMxZWI5ZDc0M2ZjOTk1ZDFkY2Mw
|
10
|
+
YzA0YTYzOTIyYTI4ODViY2U0ZDRhNTA4NDQ2YzIwOTA3ZTYxOWFjYmNhNmEz
|
11
|
+
OTcwYjFiODNhYjhmMjI5YTRlNDJlZDc4NjA3ODIwZGUyMWI3YWM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MGM2ODcxNzYxMmViMjI1YjM5NjMyZmNjZDNiNDVhOWJhMjg4N2FmMjk4YTMz
|
14
|
+
ZjY4Y2QyNzgwZGFlODJlZjk5NTA5MjQyZTMzZTIxODFjMTdmZmIwZWM4MDFm
|
15
|
+
NTdlZDEzYTg5ZWU1M2RiZjAzZDQxMmRlOTY3M2RlOWJhYzUyNzg=
|
data/README.md
CHANGED
@@ -2,24 +2,22 @@
|
|
2
2
|
|
3
3
|
[](https://travis-ci.org/maetl/mementus)
|
4
4
|
|
5
|
-
|
5
|
+
Mementus is a transient ORM for creating and querying in-memory object models.
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
|
-
Add this line to your application's Gemfile
|
9
|
+
Add this line to your application's Gemfile and `bundle` or `bundle update`:
|
10
10
|
|
11
11
|
gem 'mementus'
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
$ bundle
|
16
|
-
|
17
|
-
Or install it yourself as:
|
13
|
+
Or install with your local Rubygems:
|
18
14
|
|
19
15
|
$ gem install mementus
|
20
16
|
|
21
17
|
## Usage
|
22
18
|
|
19
|
+
### Defining model classes
|
20
|
+
|
23
21
|
To define model classes, inherit from the `Mementus::Model` base class and add attributes using the [Virtus API](https://github.com/solnic/virtus):
|
24
22
|
|
25
23
|
```ruby
|
@@ -29,6 +27,8 @@ class Book < Mementus::Model
|
|
29
27
|
end
|
30
28
|
```
|
31
29
|
|
30
|
+
### Creating objects
|
31
|
+
|
32
32
|
Create new instances by passing data through the constructor or assigning attributes directly:
|
33
33
|
|
34
34
|
```ruby
|
@@ -53,18 +53,43 @@ book3 = Book.new(
|
|
53
53
|
book3.create
|
54
54
|
```
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
```ruby
|
59
|
-
Book.collection.count
|
56
|
+
### Matching queries
|
60
57
|
|
61
|
-
|
58
|
+
Basic match queries can be constructed by passing a predicate hash to the `where` method:
|
62
59
|
|
60
|
+
```ruby
|
63
61
|
Book.where(author: "Doris Lessing")
|
64
62
|
|
65
63
|
Book.where(title: "Crash")
|
66
64
|
```
|
67
65
|
|
66
|
+
### Scoped queries
|
67
|
+
|
68
|
+
Reusable query shortcuts can be constructed on the model class by defining a `scope`:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
class Book < Mementus::Model
|
72
|
+
attribute :title, String
|
73
|
+
attribute :author, String
|
74
|
+
attribute :genre, String
|
75
|
+
scope :scifi, genre: 'scifi'
|
76
|
+
scope :romance, genre: 'romance'
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
These defined scopes become class methods on the model:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
scifi_books = Book.scifi
|
84
|
+
romance_books = Book.romance
|
85
|
+
```
|
86
|
+
|
87
|
+
## Roadmap
|
88
|
+
|
89
|
+
- 0.2: Query API
|
90
|
+
- 0.3: Relationships API
|
91
|
+
- 0.4: Value objects
|
92
|
+
|
68
93
|
## Contributing
|
69
94
|
|
70
95
|
1. Fork it
|
data/lib/mementus/model.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'virtus'
|
2
2
|
require 'axiom-memory-adapter'
|
3
|
-
require 'mini_cache'
|
4
3
|
|
5
4
|
module Mementus
|
6
5
|
|
@@ -9,7 +8,12 @@ module Mementus
|
|
9
8
|
# relational algebra API.
|
10
9
|
#
|
11
10
|
class Model
|
12
|
-
|
11
|
+
|
12
|
+
def self.inherited(concrete_model)
|
13
|
+
concrete_model.send(:include, Virtus.model)
|
14
|
+
concrete_model.send(:extend, Relation::ClassMethods)
|
15
|
+
end
|
16
|
+
|
13
17
|
@@local_storage = nil
|
14
18
|
@@model_registry = {}
|
15
19
|
|
@@ -46,10 +50,6 @@ module Mementus
|
|
46
50
|
tuple
|
47
51
|
end
|
48
52
|
|
49
|
-
def self.inherited(concrete_model)
|
50
|
-
concrete_model.send(:include, Virtus.model)
|
51
|
-
end
|
52
|
-
|
53
53
|
# Create only writes to memory. It's required in order to
|
54
54
|
# index the object's attributes in the query model.
|
55
55
|
#
|
@@ -85,46 +85,19 @@ module Mementus
|
|
85
85
|
@@local_storage[name_to_sym]
|
86
86
|
end
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
88
|
+
# TODO: fix incomplete scope chaining
|
89
|
+
def self.scope(name, conditions)
|
90
|
+
if conditions.is_a? Hash
|
91
|
+
scope_method = lambda { self.where(conditions) }
|
92
|
+
elsif conditions.is_a? Proc
|
93
|
+
scope_method = conditions
|
91
94
|
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# The where operation restricts the collection based on the
|
95
|
-
# passed in constraints.
|
96
|
-
#
|
97
|
-
# Pass in a key-value hash to restrict based on matching attributes by equality.
|
98
|
-
#
|
99
|
-
# Pass in a block to construct a more specialised predicate match.
|
100
|
-
#
|
101
|
-
def self.where(constraints)
|
102
|
-
self.collection.restrict(constraints).inject([]) do |list, relation|
|
103
|
-
list << self.cache_get(relation[:__cache_key])
|
104
|
-
end
|
105
|
-
end
|
106
95
|
|
107
|
-
|
108
|
-
# TODO: pass relations as scopes
|
109
|
-
def self.order(constraints)
|
110
|
-
ordered_relations = self.collection.sort_by do |relation|
|
111
|
-
constraints.keys.inject([]) do |list, constraint|
|
112
|
-
direction = constraints[constraint].to_sym
|
113
|
-
direction = :asc unless direction == :desc
|
114
|
-
list << relation.send(constraint.to_sym).send(direction)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
self.materialize(ordered_relations)
|
96
|
+
define_singleton_method(name, &scope_method)
|
118
97
|
end
|
119
98
|
|
120
99
|
private
|
121
100
|
|
122
|
-
def self.materialize(collection)
|
123
|
-
collection.inject([]) do |list, relation|
|
124
|
-
list << self.cache_get(relation[:__cache_key])
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
101
|
def self.cache
|
129
102
|
@@cache ||= {}
|
130
103
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Mementus
|
2
|
+
module Relation
|
3
|
+
module ClassMethods
|
4
|
+
|
5
|
+
def where(constraints)
|
6
|
+
Query.new(self.collection, self.cache).where(constraints)
|
7
|
+
end
|
8
|
+
|
9
|
+
def all
|
10
|
+
Query.new(self.collection, self.cache).all
|
11
|
+
end
|
12
|
+
|
13
|
+
def order(constraints)
|
14
|
+
Query.new(self.collection, self.cache).order(constraints)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
# Chainable query object that delegates to the given relation.
|
20
|
+
class Query
|
21
|
+
|
22
|
+
def initialize(relation, cache)
|
23
|
+
@relation = relation
|
24
|
+
@cache = cache
|
25
|
+
end
|
26
|
+
|
27
|
+
# Filters the collection based on the given constraints.
|
28
|
+
#
|
29
|
+
# - Pass in a key-value hash to filter based on matching attributes by equality.
|
30
|
+
# - Pass in a block to construct a more specialised predicate match.
|
31
|
+
def where(constraints)
|
32
|
+
Query.new(@relation.restrict(constraints), @cache)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Order the collection by attribute and direction
|
36
|
+
def order(constraints)
|
37
|
+
ordered_relation = @relation.sort_by do |relation|
|
38
|
+
constraints.keys.inject([]) do |list, constraint|
|
39
|
+
direction = constraints[constraint].to_sym
|
40
|
+
direction = :asc unless direction == :desc
|
41
|
+
list << relation.send(constraint.to_sym).send(direction)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
Query.new(ordered_relation, @cache)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Materializes the relation to an array of model objects.
|
48
|
+
def all
|
49
|
+
@relation.inject([]) do |list, relation|
|
50
|
+
list << @cache[relation[:__cache_key]]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/mementus/version.rb
CHANGED
data/lib/mementus.rb
CHANGED
data/spec/collection_spec.rb
CHANGED
@@ -28,12 +28,13 @@ describe Mementus::Model do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
it "finds item by equality match" do
|
31
|
-
|
32
|
-
expect(
|
31
|
+
collection = Item.where(order: 10).all
|
32
|
+
expect(collection.count).to eq 1
|
33
|
+
expect(collection.first.name).to eq "Item: 9"
|
33
34
|
end
|
34
35
|
|
35
36
|
it "finds items by predicate match" do
|
36
|
-
collection = Item.order(order: :desc)
|
37
|
+
collection = Item.order(order: :desc).all
|
37
38
|
expect(collection.count).to eq 20
|
38
39
|
expect(collection.first.name).to eq "Item: 19"
|
39
40
|
expect(collection.last.name).to eq "Item: 0"
|
data/spec/scopes_spec.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mementus::Model do
|
4
|
+
|
5
|
+
class CuteThing < Mementus::Model
|
6
|
+
attribute :name, String
|
7
|
+
attribute :category, String
|
8
|
+
scope :cats, category: "cats"
|
9
|
+
scope :dogs, category: "dogs"
|
10
|
+
end
|
11
|
+
|
12
|
+
before(:all) do
|
13
|
+
20.times do |i|
|
14
|
+
thing = CuteThing.new
|
15
|
+
thing.name = rand(36**12).to_s(36)
|
16
|
+
thing.category = (i % 2) == 0 ? "dogs" : "cats"
|
17
|
+
thing.create
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#scope" do
|
22
|
+
|
23
|
+
it "can execute named scopes" do
|
24
|
+
expect(CuteThing.cats.all.count).to eq 10
|
25
|
+
expect(CuteThing.dogs.all.count).to eq 10
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mementus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- maetl
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: virtus
|
@@ -95,11 +95,13 @@ files:
|
|
95
95
|
- Rakefile
|
96
96
|
- lib/mementus.rb
|
97
97
|
- lib/mementus/model.rb
|
98
|
+
- lib/mementus/relation.rb
|
98
99
|
- lib/mementus/version.rb
|
99
100
|
- mementus.gemspec
|
100
101
|
- spec/attribute_spec.rb
|
101
102
|
- spec/collection_spec.rb
|
102
103
|
- spec/mapping_spec.rb
|
104
|
+
- spec/scopes_spec.rb
|
103
105
|
- spec/spec_helper.rb
|
104
106
|
homepage: https://github.com/maetl/mementus
|
105
107
|
licenses:
|
@@ -129,4 +131,5 @@ test_files:
|
|
129
131
|
- spec/attribute_spec.rb
|
130
132
|
- spec/collection_spec.rb
|
131
133
|
- spec/mapping_spec.rb
|
134
|
+
- spec/scopes_spec.rb
|
132
135
|
- spec/spec_helper.rb
|