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 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