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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- N2I2NmZkNjY1MGMwYWE0ZGI3ZmRmZjY0OGFlODI1YWQyZjhkMTU5OA==
4
+ MjM0MTczODAxNTlkNmQ3ODYwMzdlYWEzNzNjMGIyNTE1YWQ2NWZiMw==
5
5
  data.tar.gz: !binary |-
6
- NDNhZGVhZjZlMWE5NzJmYmY5YjM0ODIxODA0ZDViZWZiNjZmNGExZg==
6
+ YTgyZDJmZjFlMTY0NjUwODNkMDI0OWZjYTIzYzBjYjZhOTUzMTc0Yw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- OWYyMGY5NDc1ODdkNGQ2ZmQ5ZDExZTI2ODA4MjUxZWYyM2RmYmM5NTE3ZTAx
10
- NmQ4ODNjZTgxODQyZjdkZjFhYjMzNTQ4YTA2MDQ0YTU4NGY1MjVmMWI2NzZk
11
- NTQ4ZjBiNGZmN2I0ODYxN2U2N2RjZDdmZWE3ZTM2YTNhZGJhMGQ=
9
+ YjEwYWFhNmIwYWFhYjM3NWNmNDg2ZjY4MTMxZWI5ZDc0M2ZjOTk1ZDFkY2Mw
10
+ YzA0YTYzOTIyYTI4ODViY2U0ZDRhNTA4NDQ2YzIwOTA3ZTYxOWFjYmNhNmEz
11
+ OTcwYjFiODNhYjhmMjI5YTRlNDJlZDc4NjA3ODIwZGUyMWI3YWM=
12
12
  data.tar.gz: !binary |-
13
- NTlhZTVmODY1OGQ1MDhmYzU3MWE1NWM0NWUyMmM1MTIwMjY1YmNjZDkyMGJk
14
- YzU4MTk2ODA5MGYyMWRlODk4YjZkOGFlZTkzMGNjZGQyNGI3MGI3M2I2NTI4
15
- NzFkMGYzNDA1ODFkMTczMGMxOTA0MzdjYTU1MmEwMTI0OTIzMTU=
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
- Proof of concept for a toy ORM that combines some aspects of the ActiveRecord API with an in-memory query model based on the Axiom relational algebra API.
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
- And then execute:
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
- The query API is currently being worked on. Right now to test it out, you can access the relational collection for each model through the `collection` method, and execute basic matching queries using the `where` method:
57
-
58
- ```ruby
59
- Book.collection.count
56
+ ### Matching queries
60
57
 
61
- Book.collection.first
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
@@ -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
- def self.all
89
- self.collection.inject([]) do |list, relation|
90
- list << self.cache_get(relation[:__cache_key])
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
- # Order the collection by attribute and direction
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
@@ -1,3 +1,3 @@
1
1
  module Mementus
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
data/lib/mementus.rb CHANGED
@@ -2,4 +2,6 @@ require 'virtus'
2
2
  require 'axiom-memory-adapter'
3
3
 
4
4
  require_relative 'mementus/version'
5
+ require_relative 'mementus/relation'
5
6
  require_relative 'mementus/model'
7
+
@@ -28,12 +28,13 @@ describe Mementus::Model do
28
28
  end
29
29
 
30
30
  it "finds item by equality match" do
31
- expect(Item.where(order: 10).count).to eq 1
32
- expect(Item.where(order: 10).first.name).to eq "Item: 9"
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"
@@ -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.2
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-07-07 00:00:00.000000000 Z
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