hypostasis 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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