hypostasis 0.1.0 → 0.1.1

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