mementus 0.1.1 → 0.1.2

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
- Mzg4MDg1OTYxZjllZGJiMWM1OGFjODc5MTcyNDQ1YzIyYmU3NzgwMA==
4
+ N2I2NmZkNjY1MGMwYWE0ZGI3ZmRmZjY0OGFlODI1YWQyZjhkMTU5OA==
5
5
  data.tar.gz: !binary |-
6
- YjcyZWZiNGE0ZTllMWU2MzI1Nzc1Yjg1ZDlkMGUzZGQxMTkyOWJhNg==
6
+ NDNhZGVhZjZlMWE5NzJmYmY5YjM0ODIxODA0ZDViZWZiNjZmNGExZg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- YjIyNDEyNTQyZWQwYzgzMzhlMzEzYTI5MzQyZDQ2YjE3MGQwYTZmMTljY2Vm
10
- MTIxZGVhMDJmYjQ2NWE3MTFjYWU0YjQxYWUyYTgyZTAxODEwM2UwNmIyNzM5
11
- YzI3MzI2ZmY4NjU5YmEyMTA4OTg3ZDBlNDM3MzFjZGY3MTVmZTg=
9
+ OWYyMGY5NDc1ODdkNGQ2ZmQ5ZDExZTI2ODA4MjUxZWYyM2RmYmM5NTE3ZTAx
10
+ NmQ4ODNjZTgxODQyZjdkZjFhYjMzNTQ4YTA2MDQ0YTU4NGY1MjVmMWI2NzZk
11
+ NTQ4ZjBiNGZmN2I0ODYxN2U2N2RjZDdmZWE3ZTM2YTNhZGJhMGQ=
12
12
  data.tar.gz: !binary |-
13
- NjZjOGRkZWZhMjE0MDVhM2NhZjk1NDg3NDE3N2JiYzBmMGVmMGY4NDQ5M2Zj
14
- N2Y0ZWQ5Y2QyNGRmZWY4YzdhOTJkOWIxNzA5OTYyY2JmOGZmZTJhNWM0ZGU0
15
- ZGI3N2NlYzYxYWQwZDUyMDY2NTU2ZjRkMmQwMmIxZTNkNTlhYzc=
13
+ NTlhZTVmODY1OGQ1MDhmYzU3MWE1NWM0NWUyMmM1MTIwMjY1YmNjZDkyMGJk
14
+ YzU4MTk2ODA5MGYyMWRlODk4YjZkOGFlZTkzMGNjZGQyNGI3MGI3M2I2NTI4
15
+ NzFkMGYzNDA1ODFkMTczMGMxOTA0MzdjYTU1MmEwMTI0OTIzMTU=
data/README.md CHANGED
@@ -2,20 +2,7 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/maetl/mementus.svg?branch=master)](https://travis-ci.org/maetl/mementus)
4
4
 
5
- ```ruby
6
- # Proof of concept for a toy ORM that combines some aspects of the
7
- # ActiveRecord API with an in-memory query model based on the Axiom
8
- # relational algebra API.
9
- #
10
- # The weirdest trick is that the data stored in the relational model
11
- # is a read-only index that never gets re-materialised back into the
12
- # model objects themselves (though Axiom does seem to be capable of
13
- # doing this).
14
- #
15
- # Instead of returning mapped data from queries, the Ruby object_id
16
- # is used as a reference to point to the existing instance in the
17
- # runtime object space.
18
- ```
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.
19
6
 
20
7
  ## Installation
21
8
 
@@ -1,5 +1,6 @@
1
1
  require 'virtus'
2
2
  require 'axiom-memory-adapter'
3
+ require 'mini_cache'
3
4
 
4
5
  module Mementus
5
6
 
@@ -7,15 +8,6 @@ module Mementus
7
8
  # ActiveRecord API with an in-memory query model based on the Axiom
8
9
  # relational algebra API.
9
10
  #
10
- # The weirdest trick is that the data stored in the relational model
11
- # is a read-only index that never gets re-materialised back into the
12
- # model objects themselves (though Axiom does seem to be capable of
13
- # doing this).
14
- #
15
- # Instead of returning mapped data from queries, the Ruby object_id
16
- # is used as a reference to point to the existing instance in the
17
- # runtime object space.
18
- #
19
11
  class Model
20
12
 
21
13
  @@local_storage = nil
@@ -25,12 +17,18 @@ module Mementus
25
17
  name_without_namespace = name.split("::").last
26
18
  name_without_namespace.gsub(/([^\^])([A-Z])/,'\1_\2').downcase.to_sym
27
19
  end
20
+
21
+ # Unique cache identifier for this instance
22
+ #
23
+ def cache_key
24
+ "#{self.class.name_to_sym.to_s}-#{object_id.to_s}"
25
+ end
28
26
 
29
27
  # TODO: this mapping could be based on declared indexes,
30
28
  # rather than dumping the entire attribute schema here.
31
29
  #
32
30
  def schema_tuple
33
- tuple = [[:__object_id, String]]
31
+ tuple = [[:__cache_key, String]]
34
32
  attribute_set.each do |attribute_type|
35
33
  tuple << [attribute_type.name.to_sym, attribute_type.primitive]
36
34
  end
@@ -41,7 +39,7 @@ module Mementus
41
39
  # rather than dumping the entire attribute data set here.
42
40
  #
43
41
  def values_tuple
44
- tuple = [object_id.to_s]
42
+ tuple = [cache_key]
45
43
  attributes.each do |_, attribute_value|
46
44
  tuple << attribute_value
47
45
  end
@@ -58,6 +56,7 @@ module Mementus
58
56
  def create
59
57
  ensure_registered(self)
60
58
  local_storage[self.class.name_to_sym].insert([values_tuple])
59
+ self.class.cache_put(self.cache_key, self)
61
60
  end
62
61
 
63
62
  def ensure_registered(model)
@@ -79,27 +78,64 @@ module Mementus
79
78
  end
80
79
 
81
80
  def local_storage
82
- unless @@local_storage
83
- @@local_storage = Axiom::Adapter::Memory.new
84
- end
85
- @@local_storage
81
+ @@local_storage ||= Axiom::Adapter::Memory.new
86
82
  end
87
83
 
88
84
  def self.collection
89
85
  @@local_storage[name_to_sym]
90
86
  end
87
+
88
+ def self.all
89
+ self.collection.inject([]) do |list, relation|
90
+ list << self.cache_get(relation[:__cache_key])
91
+ end
92
+ end
91
93
 
92
- # Stub implementation that demonstrates the ObjectSpace
93
- # reference grabbing.
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.
94
98
  #
95
- # Currently just splats to an array instead of handing back
96
- # a chainable scope object.
99
+ # Pass in a block to construct a more specialised predicate match.
97
100
  #
98
101
  def self.where(constraints)
99
102
  self.collection.restrict(constraints).inject([]) do |list, relation|
100
- list << ObjectSpace._id2ref(relation[:__object_id].to_i)
103
+ list << self.cache_get(relation[:__cache_key])
101
104
  end
102
105
  end
106
+
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)
118
+ end
119
+
120
+ private
121
+
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
+ def self.cache
129
+ @@cache ||= {}
130
+ end
131
+
132
+ def self.cache_put(cache_key, object)
133
+ self.cache[cache_key] = object
134
+ end
135
+
136
+ def self.cache_get(cache_key)
137
+ self.cache[cache_key]
138
+ end
103
139
 
104
140
  end
105
141
  end
@@ -1,3 +1,3 @@
1
1
  module Mementus
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
data/mementus.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["me@maetl.net"]
11
11
  spec.description = %q{In-memory data model}
12
12
  spec.summary = %q{In-memory data model}
13
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/maetl/mementus"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
@@ -22,11 +22,23 @@ describe Mementus::Model do
22
22
  expect(Item.collection.count).to eq 20
23
23
  end
24
24
 
25
- it "finds item by matching attribute" do
25
+ it "provides materialized objects" do
26
+ expect(Item.all.count).to eq 20
27
+ expect(Item.all.first.name).to eq "Item: 0"
28
+ end
29
+
30
+ it "finds item by equality match" do
26
31
  expect(Item.where(order: 10).count).to eq 1
27
32
  expect(Item.where(order: 10).first.name).to eq "Item: 9"
28
33
  end
29
34
 
35
+ it "finds items by predicate match" do
36
+ collection = Item.order(order: :desc)
37
+ expect(collection.count).to eq 20
38
+ expect(collection.first.name).to eq "Item: 19"
39
+ expect(collection.last.name).to eq "Item: 0"
40
+ end
41
+
30
42
  end
31
43
 
32
44
  end
data/spec/mapping_spec.rb CHANGED
@@ -16,17 +16,17 @@ describe Mementus::Model do
16
16
  )
17
17
  }
18
18
 
19
- let(:object_id) {
20
- mapping.object_id.to_s
19
+ let(:cache_key) {
20
+ mapping.cache_key
21
21
  }
22
22
 
23
23
  it "maps attribute schema to tuple" do
24
- schema = [[:__object_id, String], [:description, String], [:number, Integer]]
24
+ schema = [[:__cache_key, String], [:description, String], [:number, Integer]]
25
25
  expect(mapping.schema_tuple).to eq schema
26
26
  end
27
27
 
28
28
  it "maps attribute values to tuple" do
29
- values = [object_id, "Hello world.", 2014]
29
+ values = [mapping.cache_key, "Hello world.", 2014]
30
30
  expect(mapping.values_tuple).to eq values
31
31
  end
32
32
 
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.1
4
+ version: 0.1.2
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-06 00:00:00.000000000 Z
11
+ date: 2014-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: virtus
@@ -101,7 +101,7 @@ files:
101
101
  - spec/collection_spec.rb
102
102
  - spec/mapping_spec.rb
103
103
  - spec/spec_helper.rb
104
- homepage: ''
104
+ homepage: https://github.com/maetl/mementus
105
105
  licenses:
106
106
  - MIT
107
107
  metadata: {}