hypostasis 0.2.3 → 0.3.0

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,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6caf9a586e59a87fa6af2c7403f8f6a111367f45
4
- data.tar.gz: acb363691d0bede7084ae87720b35ed7eee871d9
3
+ metadata.gz: c5d1ed53d8953d86bdbf7c430f94f7b0cb175d8a
4
+ data.tar.gz: 15cc8dcd3abb23678df603443e6f5f12e8797cd3
5
5
  SHA512:
6
- metadata.gz: 461374040933e42113e95cfb5c3f31746df9a9c99732cf5cb72f4781ad0bcc40f8f909d5c5ddc9007f8937f66652d6e63388498212c366771e849284af3da417
7
- data.tar.gz: 1811b054f4ffd51b3aa17d01615bc49aeec934adf50b19ef9d6bdbdf009cad40eb334f381cfdc6782a69dd10c2b2d41ae008326ba8b56c21bcdf3f76e92903a7
6
+ metadata.gz: fb5c00de6a634eb076e224f8d863db4f0008252fa0b828c4806090598e4a4258ef5a443adcd83e74fa69d8acd0fe52b98bca843d8dcfea1038f017b940889ad7
7
+ data.tar.gz: a983faf3f5085fa01702658daaeb57486877a34f585fff043c5a4172d247ce880c88ed1a70abd3394a6ac6e1ce480d8900b8294e7e051ce904bb00082e40e3a3
data/README.md CHANGED
@@ -19,8 +19,10 @@ variety of data models while using the same underlying storage system, provided
19
19
  by FoundationDB. The data models Hypostasis currently aims to support are the
20
20
  following:
21
21
 
22
- * Document
23
22
  * Key-Value
23
+ * Column Group
24
+ * Document
25
+
24
26
 
25
27
  ## Installation
26
28
 
@@ -68,14 +70,14 @@ basic language types currently suported include the following:
68
70
  * Time
69
71
  * Boolean
70
72
 
71
- ### Document Data Model
73
+ ### ColumnGroup Data Model
72
74
 
73
75
  require 'hypostasis'
74
76
 
75
- ns = Hypostasis::Connection.create_namespace('keystore', {data_model: :document})
77
+ ns = Hypostasis::Connection.create_namespace('keystore', {data_model: :column_group})
76
78
 
77
- class SampleDocument
78
- include Hypostasis::Document
79
+ class SampleColumnGroup
80
+ include Hypostasis::ColumnGroup
79
81
 
80
82
  field :name
81
83
  field :age
@@ -85,17 +87,19 @@ basic language types currently suported include the following:
85
87
  index :age
86
88
  end
87
89
 
88
- SampleDocument.create(name: 'John', age: 21, dob: Date.today.prev_year(21))
90
+ SampleColumnGroup.create(name: 'John', age: 21, dob: Date.today.prev_year(21))
89
91
 
90
- SampleDocument.find(<<id>>)
92
+ SampleColumnGroup.find(<<id>>)
91
93
 
92
- SampleDocument.find_where(name: 'John')
93
- SampleDocument.find_where(age: 21)
94
+ SampleColumnGroup.find_where(name: 'John')
95
+ SampleColumnGroup.find_where(age: 21)
94
96
 
95
- The Document data model provides a simple document-oriented data model on top
96
- of FoundationDB, including simple indexing. Like the Key-Value data model the
97
- document-oriented model is able to automatically encode and reconstitute
98
- certain basic Ruby data types, including the following:
97
+ The Column Group data model provides a data model very similar to what would be
98
+ provided by a traditional RDBMS or Column-Family data store with data organized
99
+ along the idea of tables and rows, but mapped directly to the underlying
100
+ key-value store of FoundationDB. Like the other data models, the Column Group
101
+ model is able to automatically encode and reconstitute certain basic Ruby data
102
+ types, including the following:
99
103
 
100
104
  * String
101
105
  * Fixnum
@@ -4,8 +4,9 @@ require 'hypostasis/errors'
4
4
 
5
5
  require 'hypostasis/tuple'
6
6
  require 'hypostasis/key_path'
7
+ require 'hypostasis/key'
7
8
  require 'hypostasis/connection'
8
9
  require 'hypostasis/data_models'
9
10
  require 'hypostasis/namespace'
10
11
 
11
- require 'hypostasis/document'
12
+ require 'hypostasis/column_group'
@@ -0,0 +1,48 @@
1
+ require 'active_support/concern'
2
+ require 'active_support/inflector'
3
+
4
+ require 'hypostasis/column_group/namespaced'
5
+ require 'hypostasis/column_group/fields'
6
+ require 'hypostasis/column_group/indexes'
7
+ require 'hypostasis/column_group/persistence'
8
+ require 'hypostasis/column_group/findable'
9
+ require 'hypostasis/column_group/belongs_to'
10
+ require 'hypostasis/column_group/has_one'
11
+ require 'hypostasis/column_group/has_many'
12
+
13
+ module Hypostasis::ColumnGroup
14
+ extend ActiveSupport::Concern
15
+
16
+ include Hypostasis::ColumnGroup::Namespaced
17
+ include Hypostasis::ColumnGroup::Fields
18
+ include Hypostasis::ColumnGroup::Indexes
19
+ include Hypostasis::ColumnGroup::Persistence
20
+ include Hypostasis::ColumnGroup::Findable
21
+
22
+ include Hypostasis::ColumnGroup::BelongsTo
23
+ include Hypostasis::ColumnGroup::HasOne
24
+ include Hypostasis::ColumnGroup::HasMany
25
+
26
+ attr_reader :id
27
+
28
+ def initialize(*attributes)
29
+ self.class.namespace.open
30
+
31
+ @fields = {}
32
+ self.class.fields.each {|name| @fields[name] = nil}
33
+ attributes.each {|hsh| hsh.each {|name, value| @fields[name.to_sym] = value}}
34
+ self
35
+ end
36
+
37
+ def generate_id
38
+ @id ||= SecureRandom.uuid
39
+ end
40
+
41
+ def set_id(id)
42
+ @id ||= id.to_s
43
+ end
44
+
45
+ module ClassMethods
46
+ include Hypostasis::DataModels::Utilities
47
+ end
48
+ end
@@ -1,4 +1,4 @@
1
- module Hypostasis::Document
1
+ module Hypostasis::ColumnGroup
2
2
  module BelongsTo
3
3
  extend ActiveSupport::Concern
4
4
 
@@ -1,4 +1,4 @@
1
- module Hypostasis::Document
1
+ module Hypostasis::ColumnGroup
2
2
  module Fields
3
3
  extend ActiveSupport::Concern
4
4
 
@@ -12,6 +12,8 @@ module Hypostasis::Document
12
12
  self.class_eval { class_variable_get(:@@fields) }
13
13
  end
14
14
 
15
+ private
16
+
15
17
  def register_field(name)
16
18
  self.class_eval do
17
19
  class_variable_set(:@@fields, []) unless class_variable_defined?(:@@fields)
@@ -1,26 +1,14 @@
1
- module Hypostasis::Document
1
+ module Hypostasis::ColumnGroup
2
2
  module Findable
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  module ClassMethods
6
6
  def find(id)
7
- document_keys = []
8
- namespace.transact do |tr|
9
- document_keys = tr.get_range_start_with(namespace.for_document(self, id)).to_a
7
+ document_keys = namespace.transact do |tr|
8
+ tr.get_range_start_with(namespace.for_column_group(self, id)).to_a
10
9
  end
11
- raise Hypostasis::Errors::DocumentNotFound if document_keys.empty?
12
- attributes = {}
13
- id = Hypostasis::Tuple.unpack(document_keys.first.key.split('\\')[1]).to_a[1]
14
- document_keys.each do |key|
15
- attribute_tuple = key.key.split('\\')[2]
16
- next if attribute_tuple.nil?
17
- unpacked_key = Hypostasis::Tuple.unpack(attribute_tuple)
18
- raw_value = key.value
19
- attributes[unpacked_key.to_a[0].to_sym] = reconstitute_value(unpacked_key, raw_value)
20
- end
21
- document = self.new(attributes)
22
- document.set_id(id)
23
- document
10
+ raise Hypostasis::Errors::ColumnGroupNotFound if document_keys.empty?
11
+ reconstitute_column_group(document_keys)
24
12
  end
25
13
 
26
14
  def find_where(field_value_pairs)
@@ -36,6 +24,22 @@ module Hypostasis::Document
36
24
  results.uniq!
37
25
  results.collect! {|result| find(result) }
38
26
  end
27
+
28
+ private
29
+
30
+ def reconstitute_column_group(keys)
31
+ attributes = {}
32
+ keys.each do |key|
33
+ attribute_tuple = key.key.split('\\')[2]
34
+ next if attribute_tuple.nil?
35
+ unpacked_key = Hypostasis::Tuple.unpack(attribute_tuple)
36
+ raw_value = key.value
37
+ attributes[unpacked_key.to_a[0].to_sym] = reconstitute_value(unpacked_key, raw_value)
38
+ end
39
+ document = self.new(attributes)
40
+ document.set_id(Hypostasis::Tuple.unpack(keys.first.key.split('\\')[1]).to_a[1])
41
+ document
42
+ end
39
43
  end
40
44
  end
41
45
  end
@@ -1,4 +1,4 @@
1
- module Hypostasis::Document
1
+ module Hypostasis::ColumnGroup
2
2
  module HasMany
3
3
  extend ActiveSupport::Concern
4
4
 
@@ -1,4 +1,4 @@
1
- module Hypostasis::Document
1
+ module Hypostasis::ColumnGroup
2
2
  module HasOne
3
3
  extend ActiveSupport::Concern
4
4
 
@@ -1,7 +1,9 @@
1
- module Hypostasis::Document
1
+ module Hypostasis::ColumnGroup
2
2
  module Indexes
3
3
  extend ActiveSupport::Concern
4
4
 
5
+ private
6
+
5
7
  def indexed_fields_to_commit
6
8
  self.class.class_eval { class_variable_set(:@@indexed_fields, []) unless class_variable_defined?(:@@indexed_fields) }
7
9
  self.class.indexed_fields.collect do |field_name|
@@ -1,11 +1,11 @@
1
- module Hypostasis::Document
1
+ module Hypostasis::ColumnGroup
2
2
  module Namespaced
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  module ClassMethods
6
6
  def use_namespace(namespace)
7
7
  data_model = :key_value
8
- data_model = :document if self.included_modules.include?(Hypostasis::Document)
8
+ data_model = :column_group if self.included_modules.include?(Hypostasis::ColumnGroup)
9
9
  self.class_eval do
10
10
  class_variable_set(:@@namespace, Hypostasis::Namespace.new(namespace.to_s, data_model))
11
11
  end
@@ -1,11 +1,11 @@
1
- module Hypostasis::Document
1
+ module Hypostasis::ColumnGroup
2
2
  module Persistence
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  def save
6
6
  generate_id
7
7
  self.class.namespace.transact do |tr|
8
- tr.set(self.class.namespace.for_document(self), true.to_s)
8
+ tr.set(self.class.namespace.for_column_group(self), true.to_s)
9
9
 
10
10
  @fields.each do |field_name, value|
11
11
  tr.set(self.class.namespace.for_field(self, field_name, value.class.to_s), value.to_s)
@@ -20,7 +20,7 @@ module Hypostasis::Document
20
20
 
21
21
  def destroy
22
22
  self.class.namespace.transact do |tr|
23
- tr.clear_range_start_with(self.class.namespace.for_document(self))
23
+ tr.clear_range_start_with(self.class.namespace.for_column_group(self))
24
24
  end
25
25
  end
26
26
 
@@ -2,4 +2,4 @@ module Hypostasis::DataModels; end
2
2
 
3
3
  require 'hypostasis/data_models/utilities'
4
4
  require 'hypostasis/data_models/key_value'
5
- require 'hypostasis/data_models/document'
5
+ require 'hypostasis/data_models/column_group'
@@ -1,18 +1,18 @@
1
- module Hypostasis::DataModels::Document
1
+ module Hypostasis::DataModels::ColumnGroup
2
2
  def transact
3
3
  database.transact do |tr|
4
4
  yield tr
5
5
  end
6
6
  end
7
7
 
8
- def for_document(document, id = nil)
9
- class_name = document.is_a?(Class) ? document.to_s : document.class.to_s
10
- document_id = id.nil? ? document.id.to_s : id.to_s
8
+ def for_column_group(column_group, id = nil)
9
+ class_name = column_group.is_a?(Class) ? column_group.to_s : column_group.class.to_s
10
+ document_id = id.nil? ? column_group.id.to_s : id.to_s
11
11
  name.to_s + '\\' + Hypostasis::Tuple.new(class_name, document_id).to_s
12
12
  end
13
13
 
14
14
  def for_field(document, field, type)
15
- for_document(document) + '\\' + Hypostasis::Tuple.new(field.to_s, type.to_s).to_s
15
+ for_column_group(document) + '\\' + Hypostasis::Tuple.new(field.to_s, type.to_s).to_s
16
16
  end
17
17
 
18
18
  def for_index(document, field_name, value)
@@ -1,4 +1,6 @@
1
1
  module Hypostasis::DataModels::Utilities
2
+ private
3
+
2
4
  def reconstitute_value(tuple, raw_value)
3
5
  data_type = tuple.to_a.last
4
6
  case data_type
@@ -10,5 +10,5 @@ module Hypostasis::Errors
10
10
  class TupleExhausted < StandardError; end
11
11
  class UnknownValueType < StandardError; end
12
12
  class MustDefineFieldType < StandardError; end
13
- class DocumentNotFound < StandardError; end
13
+ class ColumnGroupNotFound < StandardError; end
14
14
  end
@@ -0,0 +1,36 @@
1
+ class Hypostasis::Key
2
+ def initialize(key_path, value = nil)
3
+ @key_path = key_path
4
+ end
5
+
6
+ def first
7
+ unpack_tuple(decomposed_key.first)
8
+ end
9
+
10
+ def last
11
+ unpack_tuple(decomposed_key.last)
12
+ end
13
+
14
+ def [](index)
15
+ unpack_tuple(decomposed_key[index.to_i])
16
+ end
17
+
18
+ private
19
+
20
+ def decomposed_key
21
+ @decomposed_key ||= @key_path.split('\\')
22
+ end
23
+
24
+ def unpack_tuple(key)
25
+ begin
26
+ Hypostasis::Tuple.unpack(key)
27
+ rescue RuntimeError => e
28
+ if e.message.match(/^Unknown data type in DB:/)
29
+ key
30
+ else
31
+ raise e
32
+ end
33
+ end
34
+ end
35
+
36
+ end
@@ -56,8 +56,8 @@ private
56
56
  case @data_model
57
57
  when :key_value
58
58
  self.extend Hypostasis::DataModels::KeyValue
59
- when :document
60
- self.extend Hypostasis::DataModels::Document
59
+ when :column_group
60
+ self.extend Hypostasis::DataModels::ColumnGroup
61
61
  else
62
62
  raise Hypostasis::Errors::UnknownNamespaceDataModel, "#{@data_model} unknown"
63
63
  end
@@ -1,3 +1,3 @@
1
1
  module Hypostasis
2
- VERSION = '0.2.3'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -1,7 +1,7 @@
1
1
  require 'minitest_helper'
2
2
 
3
3
  class HasManyOwnerDocument
4
- include Hypostasis::Document
4
+ include Hypostasis::ColumnGroup
5
5
 
6
6
  use_namespace 'hasmany_docs'
7
7
 
@@ -12,7 +12,7 @@ class HasManyOwnerDocument
12
12
  end
13
13
 
14
14
  class HasManyChildDocument
15
- include Hypostasis::Document
15
+ include Hypostasis::ColumnGroup
16
16
 
17
17
  use_namespace 'hasmany_docs'
18
18
 
@@ -22,9 +22,9 @@ class HasManyChildDocument
22
22
  belongs_to :has_many_owner_document
23
23
  end
24
24
 
25
- describe 'Document has_many Relationship' do
25
+ describe 'ColumnGroup has_many Relationship' do
26
26
  before do
27
- Hypostasis::Connection.create_namespace 'hasmany_docs', data_model: :document
27
+ Hypostasis::Connection.create_namespace 'hasmany_docs', data_model: :column_group
28
28
  @owner = HasManyOwnerDocument.create(name: 'John', age: '25')
29
29
  @children = []
30
30
  @children << HasManyChildDocument.create(name: 'James', age: '6', has_many_owner_document_id: @owner.id)
@@ -1,7 +1,7 @@
1
1
  require 'minitest_helper'
2
2
 
3
3
  class HasOneOwnerDocument
4
- include Hypostasis::Document
4
+ include Hypostasis::ColumnGroup
5
5
 
6
6
  use_namespace 'hasone_docs'
7
7
 
@@ -12,7 +12,7 @@ class HasOneOwnerDocument
12
12
  end
13
13
 
14
14
  class HasOneChildDocument
15
- include Hypostasis::Document
15
+ include Hypostasis::ColumnGroup
16
16
 
17
17
  use_namespace 'hasone_docs'
18
18
 
@@ -22,9 +22,9 @@ class HasOneChildDocument
22
22
  belongs_to :has_one_owner_document
23
23
  end
24
24
 
25
- describe 'Document has_one Relationship' do
25
+ describe 'ColumnGroup has_one Relationship' do
26
26
  before do
27
- Hypostasis::Connection.create_namespace 'hasone_docs', data_model: :document
27
+ Hypostasis::Connection.create_namespace 'hasone_docs', data_model: :column_group
28
28
  @owner = HasOneOwnerDocument.create(name: 'John', age: '25')
29
29
  @child = HasOneChildDocument.create(name: 'James', age: '6', has_one_owner_document_id: @owner.id)
30
30
  end
@@ -0,0 +1,106 @@
1
+ require 'minitest_helper'
2
+
3
+ describe Hypostasis::ColumnGroup do
4
+ let(:subject) { SampleColumn.new(name: 'John', age: 21, dob: Date.today.prev_year(21)) }
5
+
6
+ before do
7
+ Hypostasis::Connection.create_namespace 'sample_columns', data_model: :column_group
8
+ Hypostasis::Connection.create_namespace 'indexed_columns', data_model: :column_group
9
+ end
10
+
11
+ after do
12
+ Hypostasis::Connection.destroy_namespace 'sample_columns'
13
+ Hypostasis::Connection.destroy_namespace 'indexed_columns'
14
+ end
15
+
16
+ it { subject.must_respond_to :name }
17
+ it { subject.must_respond_to :age }
18
+ it { subject.must_respond_to :dob }
19
+
20
+ it { subject.must_respond_to :name= }
21
+ it { subject.must_respond_to :age= }
22
+ it { subject.must_respond_to :dob= }
23
+
24
+ it { subject.name.must_equal 'John' }
25
+ it { subject.age.must_equal 21 }
26
+ it { subject.dob.must_equal Date.today.prev_year(21) }
27
+
28
+ it { subject.must_respond_to :save }
29
+
30
+ describe '#create' do
31
+ let(:subject) { SampleColumn.create(name: 'John', age: 21, dob: Date.today.prev_year(21)) }
32
+
33
+ after do
34
+ subject.destroy
35
+ end
36
+
37
+ it { subject.id.wont_be_nil }
38
+ it { database.get(column_path(subject)).must_equal 'true' }
39
+ it { database.get(field_path(subject, :name, String)).must_equal 'John' }
40
+ it { database.get(field_path(subject, :age, Fixnum)).must_equal '21' }
41
+ it { database.get(field_path(subject, :dob, Date)).must_equal Date.today.prev_year(21).to_s }
42
+ end
43
+
44
+ describe '#save' do
45
+ let(:subject) { SampleColumn.new(name: 'John', age: 21, dob: Date.today.prev_year(21)) }
46
+
47
+ before do
48
+ subject.save
49
+ end
50
+
51
+ after do
52
+ subject.destroy
53
+ end
54
+
55
+ it { subject.id.wont_be_nil }
56
+ it { database.get(column_path(subject)).must_equal 'true' }
57
+ it { database.get(field_path(subject, :name, String)).must_equal 'John' }
58
+ it { database.get(field_path(subject, :age, Fixnum)).must_equal '21' }
59
+ it { database.get(field_path(subject, :dob, Date)).must_equal Date.today.prev_year(21).to_s }
60
+ end
61
+
62
+ describe '.find' do
63
+ let(:column_id) { subject.save.id }
64
+
65
+ after do
66
+ subject.destroy
67
+ end
68
+
69
+ it { SampleColumn.find(column_id).is_a?(SampleColumn).must_equal true }
70
+ it { SampleColumn.find(column_id).id.must_equal column_id }
71
+ end
72
+
73
+ describe 'indexing' do
74
+ before do
75
+ IndexedColumn.create(name: 'John', age: 21, dob: Date.today.prev_year(21))
76
+ IndexedColumn.create(name: 'Jane', age: 21, dob: Date.today.prev_year(21))
77
+ IndexedColumn.create(name: 'John', age: 23, dob: Date.today.prev_year(23))
78
+ IndexedColumn.create(name: 'Tom', age: 20, dob: Date.today.prev_year(20))
79
+ end
80
+
81
+ it { database.get_range_start_with(index_path(IndexedColumn, :name)).size.must_equal 4 }
82
+ it { database.get_range_start_with(index_path(IndexedColumn, :age)).size.must_equal 4 }
83
+
84
+ it { database.get_range_start_with(index_path(IndexedColumn, :name, 'John')).size.must_equal 2 }
85
+ it { database.get_range_start_with(index_path(IndexedColumn, :name, 'Jane')).size.must_equal 1 }
86
+
87
+ it { database.get_range_start_with(index_path(IndexedColumn, :age, 21)).size.must_equal 2 }
88
+ end
89
+
90
+ describe '.find_where' do
91
+ before do
92
+ IndexedColumn.create(name: 'John', age: 21, dob: Date.today.prev_year(21))
93
+ IndexedColumn.create(name: 'Jane', age: 21, dob: Date.today.prev_year(21))
94
+ IndexedColumn.create(name: 'John', age: 23, dob: Date.today.prev_year(23))
95
+ IndexedColumn.create(name: 'Tom', age: 20, dob: Date.today.prev_year(20))
96
+ end
97
+
98
+ it { IndexedColumn.find_where(name: 'John').size.must_equal 2 }
99
+ it { IndexedColumn.find_where(age: 21).size.must_equal 2 }
100
+ it { IndexedColumn.find_where(name: 'Tom').size.must_equal 1 }
101
+ it { IndexedColumn.find_where(name: 'Tom').first.is_a?(IndexedColumn).must_equal true }
102
+
103
+ it { IndexedColumn.find_where(name: 'John', age: 23).size.must_equal 1 }
104
+ it { IndexedColumn.find_where(name: 'John', age: 23).first.is_a?(IndexedColumn).must_equal true }
105
+ end
106
+ end
@@ -0,0 +1,25 @@
1
+ require 'minitest_helper'
2
+
3
+ describe Hypostasis::Key do
4
+ let(:subject) { Hypostasis::Key.new('simple\\path\\example') }
5
+
6
+ it { subject.must_respond_to :[] }
7
+ it { subject.must_respond_to :first }
8
+ it { subject.must_respond_to :last }
9
+
10
+ it { subject[0].must_equal 'simple' }
11
+ it { subject[1].must_equal 'path' }
12
+ it { subject[2].must_equal 'example' }
13
+
14
+ it { subject.first.must_equal 'simple' }
15
+ it { subject.last.must_equal 'example'}
16
+
17
+ describe 'with Tuples' do
18
+ let(:tuple) { Hypostasis::Tuple.new('sample','tuple',15) }
19
+ let(:subject) { Hypostasis::Key.new("simple\\tuple\\#{tuple.to_s}") }
20
+
21
+ it { subject[0].must_equal 'simple' }
22
+ it { subject[1].must_equal 'tuple' }
23
+ it { subject[2].must_be_instance_of Hypostasis::Tuple }
24
+ end
25
+ end
@@ -13,8 +13,8 @@ require 'hypostasis'
13
13
 
14
14
  require 'minitest/autorun'
15
15
 
16
- require 'support/sample_document'
17
- require 'support/indexed_document'
16
+ require 'support/sample_column'
17
+ require 'support/indexed_column'
18
18
 
19
19
  class Minitest::Spec
20
20
 
@@ -22,7 +22,7 @@ class Minitest::Spec
22
22
  @database ||= FDB.open
23
23
  end
24
24
 
25
- def document_path(document)
25
+ def column_path(document)
26
26
  document_namespace = document.class.namespace.to_s
27
27
  document_tuple = Hypostasis::Tuple.new(document.class.to_s, document.id.to_s).to_s
28
28
  document_namespace + '\\' + document_tuple
@@ -137,7 +137,7 @@ describe Hypostasis::Namespace do
137
137
  end
138
138
  end
139
139
 
140
- describe 'for a Document namespace' do
140
+ describe 'for a ColumnGroup namespace' do
141
141
  before do
142
142
  subject
143
143
  end
@@ -146,9 +146,9 @@ describe Hypostasis::Namespace do
146
146
  subject.destroy
147
147
  end
148
148
 
149
- let(:subject) { Hypostasis::Namespace.create('document_space', { data_model: :document }) }
149
+ let(:subject) { Hypostasis::Namespace.create('column_space', { data_model: :column_group }) }
150
150
 
151
- it { database.get('document_space\\' + Hypostasis::Tuple.new(['config','data_model']).to_s).must_equal 'document' }
151
+ it { database.get('column_space\\' + Hypostasis::Tuple.new(['config','data_model']).to_s).must_equal 'column_group' }
152
152
  end
153
153
 
154
154
  describe 'for an unknown namespace type' do
@@ -0,0 +1,12 @@
1
+ class IndexedColumn
2
+ include Hypostasis::ColumnGroup
3
+
4
+ use_namespace 'indexed_columns'
5
+
6
+ field :name
7
+ field :age
8
+ field :dob
9
+
10
+ index :name
11
+ index :age
12
+ end
@@ -0,0 +1,9 @@
1
+ class SampleColumn
2
+ include Hypostasis::ColumnGroup
3
+
4
+ use_namespace 'sample_columns'
5
+
6
+ field :name
7
+ field :age
8
+ field :dob
9
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hypostasis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Thompson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-28 00:00:00.000000000 Z
11
+ date: 2014-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fdb
@@ -97,35 +97,37 @@ files:
97
97
  - Vagrantfile
98
98
  - hypostasis.gemspec
99
99
  - lib/hypostasis.rb
100
+ - lib/hypostasis/column_group.rb
101
+ - lib/hypostasis/column_group/belongs_to.rb
102
+ - lib/hypostasis/column_group/fields.rb
103
+ - lib/hypostasis/column_group/findable.rb
104
+ - lib/hypostasis/column_group/has_many.rb
105
+ - lib/hypostasis/column_group/has_one.rb
106
+ - lib/hypostasis/column_group/indexes.rb
107
+ - lib/hypostasis/column_group/namespaced.rb
108
+ - lib/hypostasis/column_group/persistence.rb
100
109
  - lib/hypostasis/connection.rb
101
110
  - lib/hypostasis/data_models.rb
102
- - lib/hypostasis/data_models/document.rb
111
+ - lib/hypostasis/data_models/column_group.rb
103
112
  - lib/hypostasis/data_models/key_value.rb
104
113
  - lib/hypostasis/data_models/utilities.rb
105
- - lib/hypostasis/document.rb
106
- - lib/hypostasis/document/belongs_to.rb
107
- - lib/hypostasis/document/fields.rb
108
- - lib/hypostasis/document/findable.rb
109
- - lib/hypostasis/document/has_many.rb
110
- - lib/hypostasis/document/has_one.rb
111
- - lib/hypostasis/document/indexes.rb
112
- - lib/hypostasis/document/namespaced.rb
113
- - lib/hypostasis/document/persistence.rb
114
114
  - lib/hypostasis/errors.rb
115
+ - lib/hypostasis/key.rb
115
116
  - lib/hypostasis/key_path.rb
116
117
  - lib/hypostasis/namespace.rb
117
118
  - lib/hypostasis/tuple.rb
118
119
  - lib/hypostasis/version.rb
119
120
  - provision.sh
121
+ - test/column/has_many_spec.rb
122
+ - test/column/has_one_spec.rb
123
+ - test/column_spec.rb
120
124
  - test/connection_spec.rb
121
- - test/document/has_many_spec.rb
122
- - test/document/has_one_spec.rb
123
- - test/document_spec.rb
124
125
  - test/key_path_spec.rb
126
+ - test/key_spec.rb
125
127
  - test/minitest_helper.rb
126
128
  - test/namespace_spec.rb
127
- - test/support/indexed_document.rb
128
- - test/support/sample_document.rb
129
+ - test/support/indexed_column.rb
130
+ - test/support/sample_column.rb
129
131
  - test/tuple_spec.rb
130
132
  homepage: ''
131
133
  licenses:
@@ -152,13 +154,14 @@ signing_key:
152
154
  specification_version: 4
153
155
  summary: A layer for FoundationDB providing multiple data models for Ruby.
154
156
  test_files:
157
+ - test/column/has_many_spec.rb
158
+ - test/column/has_one_spec.rb
159
+ - test/column_spec.rb
155
160
  - test/connection_spec.rb
156
- - test/document/has_many_spec.rb
157
- - test/document/has_one_spec.rb
158
- - test/document_spec.rb
159
161
  - test/key_path_spec.rb
162
+ - test/key_spec.rb
160
163
  - test/minitest_helper.rb
161
164
  - test/namespace_spec.rb
162
- - test/support/indexed_document.rb
163
- - test/support/sample_document.rb
165
+ - test/support/indexed_column.rb
166
+ - test/support/sample_column.rb
164
167
  - test/tuple_spec.rb
@@ -1,48 +0,0 @@
1
- require 'active_support/concern'
2
- require 'active_support/inflector'
3
-
4
- require 'hypostasis/document/namespaced'
5
- require 'hypostasis/document/fields'
6
- require 'hypostasis/document/indexes'
7
- require 'hypostasis/document/persistence'
8
- require 'hypostasis/document/findable'
9
- require 'hypostasis/document/belongs_to'
10
- require 'hypostasis/document/has_one'
11
- require 'hypostasis/document/has_many'
12
-
13
- module Hypostasis::Document
14
- extend ActiveSupport::Concern
15
-
16
- include Hypostasis::Document::Namespaced
17
- include Hypostasis::Document::Fields
18
- include Hypostasis::Document::Indexes
19
- include Hypostasis::Document::Persistence
20
- include Hypostasis::Document::Findable
21
-
22
- include Hypostasis::Document::BelongsTo
23
- include Hypostasis::Document::HasOne
24
- include Hypostasis::Document::HasMany
25
-
26
- attr_reader :id
27
-
28
- def initialize(*attributes)
29
- self.class.namespace.open
30
-
31
- @fields = {}
32
- self.class.fields.each {|name| @fields[name] = nil}
33
- attributes.each {|hsh| hsh.each {|name, value| @fields[name.to_sym] = value}}
34
- self
35
- end
36
-
37
- def generate_id
38
- @id ||= SecureRandom.uuid
39
- end
40
-
41
- def set_id(id)
42
- @id ||= id.to_s
43
- end
44
-
45
- module ClassMethods
46
- include Hypostasis::DataModels::Utilities
47
- end
48
- end
@@ -1,106 +0,0 @@
1
- require 'minitest_helper'
2
-
3
- describe Hypostasis::Document do
4
- let(:subject) { SampleDocument.new(name: 'John', age: 21, dob: Date.today.prev_year(21)) }
5
-
6
- before do
7
- Hypostasis::Connection.create_namespace 'sample_docs', data_model: :document
8
- Hypostasis::Connection.create_namespace 'indexed_docs', data_model: :document
9
- end
10
-
11
- after do
12
- Hypostasis::Connection.destroy_namespace 'sample_docs'
13
- Hypostasis::Connection.destroy_namespace 'indexed_docs'
14
- end
15
-
16
- it { subject.must_respond_to :name }
17
- it { subject.must_respond_to :age }
18
- it { subject.must_respond_to :dob }
19
-
20
- it { subject.must_respond_to :name= }
21
- it { subject.must_respond_to :age= }
22
- it { subject.must_respond_to :dob= }
23
-
24
- it { subject.name.must_equal 'John' }
25
- it { subject.age.must_equal 21 }
26
- it { subject.dob.must_equal Date.today.prev_year(21) }
27
-
28
- it { subject.must_respond_to :save }
29
-
30
- describe '#create' do
31
- let(:subject) { SampleDocument.create(name: 'John', age: 21, dob: Date.today.prev_year(21)) }
32
-
33
- after do
34
- subject.destroy
35
- end
36
-
37
- it { subject.id.wont_be_nil }
38
- it { database.get(document_path(subject)).must_equal 'true' }
39
- it { database.get(field_path(subject, :name, String)).must_equal 'John' }
40
- it { database.get(field_path(subject, :age, Fixnum)).must_equal '21' }
41
- it { database.get(field_path(subject, :dob, Date)).must_equal Date.today.prev_year(21).to_s }
42
- end
43
-
44
- describe '#save' do
45
- let(:subject) { SampleDocument.new(name: 'John', age: 21, dob: Date.today.prev_year(21)) }
46
-
47
- before do
48
- subject.save
49
- end
50
-
51
- after do
52
- subject.destroy
53
- end
54
-
55
- it { subject.id.wont_be_nil }
56
- it { database.get(document_path(subject)).must_equal 'true' }
57
- it { database.get(field_path(subject, :name, String)).must_equal 'John' }
58
- it { database.get(field_path(subject, :age, Fixnum)).must_equal '21' }
59
- it { database.get(field_path(subject, :dob, Date)).must_equal Date.today.prev_year(21).to_s }
60
- end
61
-
62
- describe '.find' do
63
- let(:document_id) { subject.save.id }
64
-
65
- after do
66
- subject.destroy
67
- end
68
-
69
- it { SampleDocument.find(document_id).is_a?(SampleDocument).must_equal true }
70
- it { SampleDocument.find(document_id).id.must_equal document_id }
71
- end
72
-
73
- describe 'indexing' do
74
- before do
75
- IndexedDocument.create(name: 'John', age: 21, dob: Date.today.prev_year(21))
76
- IndexedDocument.create(name: 'Jane', age: 21, dob: Date.today.prev_year(21))
77
- IndexedDocument.create(name: 'John', age: 23, dob: Date.today.prev_year(23))
78
- IndexedDocument.create(name: 'Tom', age: 20, dob: Date.today.prev_year(20))
79
- end
80
-
81
- it { database.get_range_start_with(index_path(IndexedDocument, :name)).size.must_equal 4 }
82
- it { database.get_range_start_with(index_path(IndexedDocument, :age)).size.must_equal 4 }
83
-
84
- it { database.get_range_start_with(index_path(IndexedDocument, :name, 'John')).size.must_equal 2 }
85
- it { database.get_range_start_with(index_path(IndexedDocument, :name, 'Jane')).size.must_equal 1 }
86
-
87
- it { database.get_range_start_with(index_path(IndexedDocument, :age, 21)).size.must_equal 2 }
88
- end
89
-
90
- describe '.find_where' do
91
- before do
92
- IndexedDocument.create(name: 'John', age: 21, dob: Date.today.prev_year(21))
93
- IndexedDocument.create(name: 'Jane', age: 21, dob: Date.today.prev_year(21))
94
- IndexedDocument.create(name: 'John', age: 23, dob: Date.today.prev_year(23))
95
- IndexedDocument.create(name: 'Tom', age: 20, dob: Date.today.prev_year(20))
96
- end
97
-
98
- it { IndexedDocument.find_where(name: 'John').size.must_equal 2 }
99
- it { IndexedDocument.find_where(age: 21).size.must_equal 2 }
100
- it { IndexedDocument.find_where(name: 'Tom').size.must_equal 1 }
101
- it { IndexedDocument.find_where(name: 'Tom').first.is_a?(IndexedDocument).must_equal true }
102
-
103
- it { IndexedDocument.find_where(name: 'John', age: 23).size.must_equal 1 }
104
- it { IndexedDocument.find_where(name: 'John', age: 23).first.is_a?(IndexedDocument).must_equal true }
105
- end
106
- end
@@ -1,12 +0,0 @@
1
- class IndexedDocument
2
- include Hypostasis::Document
3
-
4
- use_namespace 'indexed_docs'
5
-
6
- field :name
7
- field :age
8
- field :dob
9
-
10
- index :name
11
- index :age
12
- end
@@ -1,9 +0,0 @@
1
- class SampleDocument
2
- include Hypostasis::Document
3
-
4
- use_namespace 'sample_docs'
5
-
6
- field :name
7
- field :age
8
- field :dob
9
- end