hypostasis 0.1.0 → 0.1.1

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: 3ef5cc8995a6ef7a748862673f907a6b5fb95e43
4
- data.tar.gz: bfa8febeae9d58a04764948cde524fea4172b706
3
+ metadata.gz: fb31443e0e30e596eee33533e9bf70bf207df3b6
4
+ data.tar.gz: b5753b79d36c1fec6000a0bb20bac292383b0db7
5
5
  SHA512:
6
- metadata.gz: afd6b2484b51d26be937f3152f0bfae13e2f5739ce8e0608f3aaadffbc4c70d53e2c6b08acfde1558aab8b7f81d0fd513f08f5cbe9cb3e1cb074bbc53431696b
7
- data.tar.gz: af7539814a855d5ff6845fb136051a162757da126fe7547d3948d2508c1c0a6d97bf0bad8ce3f05ba6dfcea1445a83c40c38c978177751ce81ae446fdaeea308
6
+ metadata.gz: 72f6be472948ea18c1ac60df3d8503f61cc58be05f20a572b7d81a5a626dbe826ce7f5ad89513aa13f8396d89ba0762d5006a3796a66c8c8b5d385b52d590c3e
7
+ data.tar.gz: 492764de3d86804dd84e195944b3c3b2cbc9bf144ecb60e50f5fd6db92e75888a9274275c20d9e91d09189a53b39943b617b818e8d7b4667ceb3fcc940df8e65
data/lib/hypostasis.rb CHANGED
@@ -7,3 +7,5 @@ require 'hypostasis/key_path'
7
7
  require 'hypostasis/connection'
8
8
  require 'hypostasis/data_models'
9
9
  require 'hypostasis/namespace'
10
+
11
+ require 'hypostasis/document'
@@ -1,3 +1,17 @@
1
1
  module Hypostasis::DataModels::Document
2
+ def transact
3
+ database.transact do |tr|
4
+ yield tr
5
+ end
6
+ end
2
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
11
+ name.to_s + '\\' + Hypostasis::Tuple.new(class_name, document_id).to_s
12
+ end
13
+
14
+ def for_field(document, field, type)
15
+ for_document(document) + '\\' + Hypostasis::Tuple.new(field.to_s, type.to_s).to_s
16
+ end
3
17
  end
@@ -0,0 +1,121 @@
1
+ module Hypostasis::Document
2
+ def self.included(base)
3
+ base.extend ClassMethods
4
+ base.class_eval do
5
+ attr_reader :id
6
+ # Register somewhere?
7
+ end
8
+ end
9
+
10
+ def initialize(*attributes)
11
+ self.class.namespace.open
12
+
13
+ @fields = {}
14
+ self.class.fields.each {|name| @fields[name] = nil}
15
+ attributes.each {|hsh| hsh.each {|name, value| @fields[name.to_sym] = value}}
16
+ end
17
+
18
+ def save
19
+ generate_id
20
+ self.class.namespace.transact do |tr|
21
+ tr.set(self.class.namespace.for_document(self), true.to_s)
22
+
23
+ @fields.each do |field_name, value|
24
+ tr.set(self.class.namespace.for_field(self, field_name, value.class.to_s), value.to_s)
25
+ end
26
+ end
27
+ self
28
+ end
29
+
30
+ def generate_id
31
+ @id ||= SecureRandom.uuid
32
+ end
33
+
34
+ def set_id(id)
35
+ @id ||= id.to_s
36
+ end
37
+
38
+ module ClassMethods
39
+ def use_namespace(namespace)
40
+ @@namespace = Hypostasis::Namespace.new(namespace.to_s, :document)
41
+ end
42
+
43
+ def namespace
44
+ @@namespace
45
+ end
46
+
47
+ def supported_field_types
48
+ @@supported_field_types ||= %w{Fixnum Bignum String Integer Float Date DateTime Time Boolean}
49
+ end
50
+
51
+ def field(name, options = {})
52
+ named = name.to_s
53
+ raise Hypostasis::Errors::MustDefineFieldType if options[:type].nil?
54
+ raise Hypostasis::Errors::UnsupportedFieldType unless supported_field_types.include?(options[:type].to_s)
55
+ register_field(name.to_sym)
56
+ create_accessors(named, options)
57
+ end
58
+
59
+ def fields
60
+ @@fields
61
+ end
62
+
63
+ def register_field(name)
64
+ @@fields = [] unless defined?(@@fields)
65
+ @@fields << name.to_sym
66
+ end
67
+
68
+ def create_accessors(name, options)
69
+ self.class_eval do
70
+ define_method(name) { @fields[name.to_sym] || nil }
71
+ define_method("#{name}=") {|value| @fields[name.to_sym] = value}
72
+ end
73
+ end
74
+
75
+ def find(id)
76
+ document_keys = []
77
+ namespace.transact do |tr|
78
+ document_keys = tr.get_range_start_with(namespace.for_document(self, id))
79
+ end
80
+ #raise Hypostasis::Errors::DocumentNotFound if document_keys.empty?
81
+ attributes = {}
82
+ id = Hypostasis::Tuple.unpack(document_keys.first.key.split('\\')[1]).to_a[1]
83
+ document_keys.each do |key|
84
+ attribute_tuple = key.key.split('\\')[2]
85
+ next if attribute_tuple.nil?
86
+ unpacked_key = Hypostasis::Tuple.unpack(attribute_tuple)
87
+ raw_value = key.value
88
+ attributes[unpacked_key.to_a[0].to_sym] = reconstitute_value(unpacked_key, raw_value)
89
+ end
90
+ document = self.new(attributes)
91
+ document.set_id(id)
92
+ document
93
+ end
94
+
95
+ def reconstitute_value(tuple, raw_value)
96
+ data_type = tuple.to_a.last
97
+ case data_type
98
+ when 'Fixnum'
99
+ Integer(raw_value)
100
+ when 'Bignum'
101
+ Integer(raw_value)
102
+ when 'Float'
103
+ Float(raw_value)
104
+ when 'String'
105
+ raw_value
106
+ when 'Date'
107
+ Date.parse(raw_value)
108
+ when 'DateTime'
109
+ DateTime.parse(raw_value)
110
+ when 'Time'
111
+ Time.parse(raw_value)
112
+ when 'TrueClass'
113
+ true
114
+ when 'FalseClass'
115
+ false
116
+ else
117
+ raise Hypostasis::Errors::UnknownValueType
118
+ end
119
+ end
120
+ end
121
+ end
@@ -8,4 +8,5 @@ module Hypostasis::Errors
8
8
  class InvalidTuple < StandardError; end
9
9
  class TupleExhausted < StandardError; end
10
10
  class UnknownValueType < StandardError; end
11
+ class MustDefineFieldType < StandardError; end
11
12
  end
@@ -4,10 +4,16 @@ class Hypostasis::Namespace
4
4
  def initialize(name, data_model = :key_value)
5
5
  @name = name.to_s
6
6
  @data_model = data_model.to_sym
7
-
8
7
  load_data_model
9
8
  end
10
9
 
10
+ def open
11
+ raise Hypostasis::Errors::NonExistentNamespace if database[name].nil?
12
+ data_model = database.get(name + '\\' + Hypostasis::Tuple.new('config','data_model').to_s)
13
+ raise Hypostasis::Errors::NamespaceDataModelMismatch if data_model != @data_model.to_s
14
+ self
15
+ end
16
+
11
17
  def destroy
12
18
  database.clear_range_start_with(@name)
13
19
  true
@@ -1,3 +1,3 @@
1
1
  module Hypostasis
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.1'
3
3
  end
@@ -0,0 +1,50 @@
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
+ end
9
+
10
+ after do
11
+ Hypostasis::Connection.destroy_namespace 'sample_docs'
12
+ end
13
+
14
+ it { subject.must_respond_to :name }
15
+ it { subject.must_respond_to :age }
16
+ it { subject.must_respond_to :dob }
17
+
18
+ it { subject.must_respond_to :name= }
19
+ it { subject.must_respond_to :age= }
20
+ it { subject.must_respond_to :dob= }
21
+
22
+ it { subject.name.must_equal 'John' }
23
+ it { subject.age.must_equal 21 }
24
+ it { subject.dob.must_equal Date.today.prev_year(21) }
25
+
26
+ it { subject.must_respond_to :save }
27
+
28
+ describe '#save' do
29
+ let(:document_tuple) { Hypostasis::Tuple.new(SampleDocument.to_s, @document.id.to_s).to_s }
30
+
31
+ def field_path(name, type)
32
+ 'sample_docs\\' + document_tuple + '\\' + Hypostasis::Tuple.new(name.to_s, type.to_s).to_s
33
+ end
34
+
35
+ before do
36
+ @document = subject.save
37
+ end
38
+
39
+ it { database.get(field_path(:name, String)).must_equal 'John' }
40
+ it { database.get(field_path(:age, Fixnum)).must_equal '21' }
41
+ it { database.get(field_path(:dob, Date)).must_equal Date.today.prev_year(21).to_s }
42
+ end
43
+
44
+ describe '.find' do
45
+ let(:document_id) { subject.save.id }
46
+
47
+ it { SampleDocument.find(document_id).is_a?(SampleDocument).must_equal true }
48
+ it { SampleDocument.find(document_id).id.must_equal document_id }
49
+ end
50
+ end
@@ -13,6 +13,8 @@ require 'hypostasis'
13
13
 
14
14
  require 'minitest/autorun'
15
15
 
16
+ require 'support/sample_document'
17
+
16
18
  class Minitest::Spec
17
19
 
18
20
  def database
@@ -0,0 +1,9 @@
1
+ class SampleDocument
2
+ include Hypostasis::Document
3
+
4
+ use_namespace 'sample_docs'
5
+
6
+ field :name, type: String
7
+ field :age, type: Fixnum
8
+ field :dob, type: Date
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.1.0
4
+ version: 0.1.1
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-19 00:00:00.000000000 Z
11
+ date: 2014-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fdb
@@ -86,15 +86,18 @@ files:
86
86
  - lib/hypostasis/data_models.rb
87
87
  - lib/hypostasis/data_models/document.rb
88
88
  - lib/hypostasis/data_models/key_value.rb
89
+ - lib/hypostasis/document.rb
89
90
  - lib/hypostasis/errors.rb
90
91
  - lib/hypostasis/key_path.rb
91
92
  - lib/hypostasis/namespace.rb
92
93
  - lib/hypostasis/tuple.rb
93
94
  - lib/hypostasis/version.rb
94
95
  - test/connection_spec.rb
96
+ - test/document_spec.rb
95
97
  - test/key_path_spec.rb
96
98
  - test/minitest_helper.rb
97
99
  - test/namespace_spec.rb
100
+ - test/support/sample_document.rb
98
101
  - test/tuple_spec.rb
99
102
  homepage: ''
100
103
  licenses:
@@ -116,13 +119,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
119
  version: '0'
117
120
  requirements: []
118
121
  rubyforge_project:
119
- rubygems_version: 2.1.11
122
+ rubygems_version: 2.2.1
120
123
  signing_key:
121
124
  specification_version: 4
122
125
  summary: A layer for FoundationDB providing multiple data models for Ruby.
123
126
  test_files:
124
127
  - test/connection_spec.rb
128
+ - test/document_spec.rb
125
129
  - test/key_path_spec.rb
126
130
  - test/minitest_helper.rb
127
131
  - test/namespace_spec.rb
132
+ - test/support/sample_document.rb
128
133
  - test/tuple_spec.rb