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 +4 -4
- data/lib/hypostasis.rb +2 -0
- data/lib/hypostasis/data_models/document.rb +14 -0
- data/lib/hypostasis/document.rb +121 -0
- data/lib/hypostasis/errors.rb +1 -0
- data/lib/hypostasis/namespace.rb +7 -1
- data/lib/hypostasis/version.rb +1 -1
- data/test/document_spec.rb +50 -0
- data/test/minitest_helper.rb +2 -0
- data/test/support/sample_document.rb +9 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb31443e0e30e596eee33533e9bf70bf207df3b6
|
4
|
+
data.tar.gz: b5753b79d36c1fec6000a0bb20bac292383b0db7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72f6be472948ea18c1ac60df3d8503f61cc58be05f20a572b7d81a5a626dbe826ce7f5ad89513aa13f8396d89ba0762d5006a3796a66c8c8b5d385b52d590c3e
|
7
|
+
data.tar.gz: 492764de3d86804dd84e195944b3c3b2cbc9bf144ecb60e50f5fd6db92e75888a9274275c20d9e91d09189a53b39943b617b818e8d7b4667ceb3fcc940df8e65
|
data/lib/hypostasis.rb
CHANGED
@@ -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
|
data/lib/hypostasis/errors.rb
CHANGED
data/lib/hypostasis/namespace.rb
CHANGED
@@ -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
|
data/lib/hypostasis/version.rb
CHANGED
@@ -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
|
data/test/minitest_helper.rb
CHANGED
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.
|
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-
|
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
|
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
|