mementus 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://travis-ci.org/maetl/mementus.svg?branch=master)](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
|