perpetuity-postgres 0.0.6 → 0.0.7
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 +4 -4
- data/CHANGELOG.md +5 -0
- data/lib/perpetuity/postgres/date_value.rb +29 -0
- data/lib/perpetuity/postgres/query_expression.rb +6 -1
- data/lib/perpetuity/postgres/serializer.rb +1 -1
- data/lib/perpetuity/postgres/sql_value.rb +3 -0
- data/lib/perpetuity/postgres/table/attribute.rb +6 -1
- data/lib/perpetuity/postgres/version.rb +1 -1
- data/spec/perpetuity/postgres/connection_pool_spec.rb +4 -4
- data/spec/perpetuity/postgres/date_value_spec.rb +24 -0
- data/spec/perpetuity/postgres/query_attribute_spec.rb +3 -2
- data/spec/perpetuity/postgres/query_expression_spec.rb +6 -0
- data/spec/perpetuity/postgres/serialized_data_spec.rb +2 -2
- data/spec/perpetuity/postgres/serializer_spec.rb +10 -5
- data/spec/perpetuity/postgres/sql_select_spec.rb +11 -3
- data/spec/perpetuity/postgres/sql_value_spec.rb +5 -0
- data/spec/perpetuity/postgres/table/attribute_spec.rb +8 -0
- data/spec/perpetuity/postgres/table_spec.rb +8 -0
- data/spec/perpetuity/postgres_spec.rb +27 -16
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 131881bc7b24a361b04326b0fac2699ca1ca2c22
|
4
|
+
data.tar.gz: 57dc7bd53e485500524439604ceaa517f5990215
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1c978801cc9d1a5c4bc888c899ce27ff15166bb396ad4eb5b95212664b408e76f13afb57175220072b532b6beaeb598794c67c0f1de809cb893bad71de49e8a
|
7
|
+
data.tar.gz: 5645ce0e3ebca3602b789515db6762ca0713c958dd915502dea87d8137df67f1c55b8b53bd9a632e081c55ce8ee767a12984a294a74db2992150ef48c8b32a68
|
data/CHANGELOG.md
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module Perpetuity
|
4
|
+
class Postgres
|
5
|
+
class DateValue
|
6
|
+
attr_reader :date
|
7
|
+
|
8
|
+
def initialize date
|
9
|
+
@date = date
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.from_sql date_string
|
13
|
+
new(Date.parse(date_string))
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_date
|
17
|
+
date
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
"'#{date.to_s}'::date"
|
22
|
+
end
|
23
|
+
|
24
|
+
def value
|
25
|
+
date
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -66,7 +66,12 @@ module Perpetuity
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def in
|
69
|
-
|
69
|
+
case sql_value
|
70
|
+
when Range
|
71
|
+
"#{attribute} BETWEEN #{SQLValue.new(sql_value.min)} AND #{SQLValue.new(sql_value.max)}"
|
72
|
+
else
|
73
|
+
"#{attribute} IN #{sql_value}"
|
74
|
+
end
|
70
75
|
end
|
71
76
|
|
72
77
|
def =~
|
@@ -12,7 +12,7 @@ module Perpetuity
|
|
12
12
|
class Serializer
|
13
13
|
include DataInjectable
|
14
14
|
|
15
|
-
SERIALIZABLE_CLASSES = Set[Fixnum, Float, String, Time, TrueClass, FalseClass, NilClass]
|
15
|
+
SERIALIZABLE_CLASSES = Set[Fixnum, Float, String, Time, Date, TrueClass, FalseClass, NilClass]
|
16
16
|
attr_reader :mapper, :mapper_registry
|
17
17
|
|
18
18
|
def initialize mapper
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'perpetuity/postgres/text_value'
|
2
2
|
require 'perpetuity/postgres/timestamp_value'
|
3
|
+
require 'perpetuity/postgres/date_value'
|
3
4
|
require 'perpetuity/postgres/numeric_value'
|
4
5
|
require 'perpetuity/postgres/null_value'
|
5
6
|
require 'perpetuity/postgres/boolean_value'
|
@@ -17,6 +18,8 @@ module Perpetuity
|
|
17
18
|
TextValue.new(value)
|
18
19
|
when Time
|
19
20
|
TimestampValue.new(value)
|
21
|
+
when Date
|
22
|
+
DateValue.new(value)
|
20
23
|
when Fixnum, Float
|
21
24
|
NumericValue.new(value)
|
22
25
|
when Hash, JSONHash
|
@@ -18,6 +18,7 @@ module Perpetuity
|
|
18
18
|
Float => 'FLOAT',
|
19
19
|
UUID => 'UUID',
|
20
20
|
Time => 'TIMESTAMPTZ',
|
21
|
+
Date => 'DATE',
|
21
22
|
TrueClass => 'BOOLEAN',
|
22
23
|
FalseClass => 'BOOLEAN'
|
23
24
|
}.tap{|m| m.default = 'JSON' }
|
@@ -26,7 +27,11 @@ module Perpetuity
|
|
26
27
|
@name = name
|
27
28
|
@type = type
|
28
29
|
@max_length = options[:max_length]
|
29
|
-
@primary_key =
|
30
|
+
@primary_key = if @name.to_s == 'id'
|
31
|
+
true
|
32
|
+
else
|
33
|
+
options.fetch(:primary_key) { false }
|
34
|
+
end
|
30
35
|
@default = options.fetch(:default) { NoDefaultValue }
|
31
36
|
end
|
32
37
|
|
@@ -6,7 +6,7 @@ module Perpetuity
|
|
6
6
|
let(:pool) { ConnectionPool.new }
|
7
7
|
|
8
8
|
it 'defaults to 5 connections' do
|
9
|
-
pool.
|
9
|
+
expect(pool.connections.size).to eq 5
|
10
10
|
end
|
11
11
|
|
12
12
|
describe 'lending a connection' do
|
@@ -20,9 +20,9 @@ module Perpetuity
|
|
20
20
|
|
21
21
|
it 'lends a connection for the duration of a block' do
|
22
22
|
pool.lend_connection do |connection|
|
23
|
-
pool.
|
23
|
+
expect(pool.connections.size).to eq 4
|
24
24
|
end
|
25
|
-
pool.
|
25
|
+
expect(pool.connections.size).to eq 5
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'returns the value of the block' do
|
@@ -48,7 +48,7 @@ module Perpetuity
|
|
48
48
|
pool.lend_connection { |c| connections << c }
|
49
49
|
end
|
50
50
|
|
51
|
-
connections.uniq.
|
51
|
+
expect(connections.uniq.size).to eq pool.size
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'perpetuity/postgres/date_value'
|
2
|
+
|
3
|
+
module Perpetuity
|
4
|
+
class Postgres
|
5
|
+
describe DateValue do
|
6
|
+
it 'converts to a SQL string' do
|
7
|
+
date = Date.new(2014, 8, 25)
|
8
|
+
DateValue.new(date).to_s.should == "'2014-08-25'::date"
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'conversion from a SQL value string' do
|
12
|
+
it 'converts GMT-X times' do
|
13
|
+
actual = DateValue.from_sql('2013-12-01')
|
14
|
+
expected = Date.new(2013, 12, 1)
|
15
|
+
actual.to_date.should == expected
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns its wrapped value' do
|
20
|
+
DateValue.new(:foo).value.should == :foo
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -4,9 +4,10 @@ module Perpetuity
|
|
4
4
|
class Postgres
|
5
5
|
describe QueryAttribute do
|
6
6
|
let(:attribute) { QueryAttribute.new :attribute_name }
|
7
|
-
subject { attribute }
|
8
7
|
|
9
|
-
|
8
|
+
it 'returns its name' do
|
9
|
+
attribute.name.should == :attribute_name
|
10
|
+
end
|
10
11
|
|
11
12
|
it 'checks for equality' do
|
12
13
|
(attribute == 1).should be_a QueryExpression
|
@@ -57,6 +57,12 @@ module Perpetuity
|
|
57
57
|
expression.to_db.should == "attribute IN (1,2,3)"
|
58
58
|
end
|
59
59
|
|
60
|
+
it 'checks for inclusion in a range' do
|
61
|
+
expression.comparator = :in
|
62
|
+
expression.value = (1..3)
|
63
|
+
expression.to_db.should == "attribute BETWEEN 1 AND 3"
|
64
|
+
end
|
65
|
+
|
60
66
|
it 'checks for inclusion of strings' do
|
61
67
|
expression.comparator = :in
|
62
68
|
expression.value = ['abc', '123']
|
@@ -45,9 +45,9 @@ module Perpetuity
|
|
45
45
|
end
|
46
46
|
|
47
47
|
it 'checks whether there are any objects' do
|
48
|
-
serialized.any?.should
|
48
|
+
serialized.any?.should be_truthy
|
49
49
|
serialized.values.clear << []
|
50
|
-
serialized.any?.should
|
50
|
+
serialized.any?.should be_falsey
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'iterates like a hash' do
|
@@ -81,6 +81,11 @@ module Perpetuity
|
|
81
81
|
serializer.serialize_attribute(time).should == "'2000-01-02 03:04:05.123456-0400'::timestamptz"
|
82
82
|
end
|
83
83
|
|
84
|
+
it 'serializes Date objects' do
|
85
|
+
date = Date.new(2014, 8, 25)
|
86
|
+
serializer.serialize_attribute(date).should == "'2014-08-25'::date"
|
87
|
+
end
|
88
|
+
|
84
89
|
it 'serializes an array as JSON' do
|
85
90
|
serializer.serialize_attribute([1, 'foo']).should == %q{'[1,"foo"]'}
|
86
91
|
end
|
@@ -181,25 +186,25 @@ module Perpetuity
|
|
181
186
|
|
182
187
|
describe 'identifying embedded/referenced objects as foreign' do
|
183
188
|
it 'sees hashes with metadata keys as foreign objects' do
|
184
|
-
serializer.foreign_object?({'__metadata__' => 'lol'}).should
|
189
|
+
serializer.foreign_object?({'__metadata__' => 'lol'}).should be_truthy
|
185
190
|
end
|
186
191
|
|
187
192
|
it 'sees hashes without metadata keys as simple hashes' do
|
188
|
-
serializer.foreign_object?({ 'name' => 'foo' }).should
|
193
|
+
serializer.foreign_object?({ 'name' => 'foo' }).should be_falsey
|
189
194
|
end
|
190
195
|
end
|
191
196
|
|
192
197
|
describe 'identifying possible JSON strings' do
|
193
198
|
it 'identifies JSON objects' do
|
194
|
-
serializer.possible_json_value?('{"name":"foo"}').should
|
199
|
+
serializer.possible_json_value?('{"name":"foo"}').should be_truthy
|
195
200
|
end
|
196
201
|
|
197
202
|
it 'identifies JSON arrays' do
|
198
|
-
serializer.possible_json_value?('[{"name":"foo"}]').should
|
203
|
+
serializer.possible_json_value?('[{"name":"foo"}]').should be_truthy
|
199
204
|
end
|
200
205
|
|
201
206
|
it 'rejects things it does not detect as either of the above' do
|
202
|
-
serializer.possible_json_value?('foo is my name').should
|
207
|
+
serializer.possible_json_value?('foo is my name').should be_falsey
|
203
208
|
end
|
204
209
|
end
|
205
210
|
|
@@ -8,9 +8,17 @@ module Perpetuity
|
|
8
8
|
limit: 4) }
|
9
9
|
subject { query }
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
it 'returns its table name' do
|
12
|
+
query.table.should == 'foo'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'returns its WHERE clause' do
|
16
|
+
query.where.should == "name = 'foo'"
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns its limit' do
|
20
|
+
query.limit.should == 4
|
21
|
+
end
|
14
22
|
|
15
23
|
it 'generates a SQL query' do
|
16
24
|
query.to_s.should == %Q{SELECT * FROM "foo" WHERE name = 'foo' LIMIT 4}
|
@@ -50,6 +50,11 @@ module Perpetuity
|
|
50
50
|
time = Time.new(2013, 1, 2, 3, 4, 5.1234567, '+05:30')
|
51
51
|
SQLValue.new(time).should == "'2013-01-02 03:04:05.123456+0530'::timestamptz"
|
52
52
|
end
|
53
|
+
|
54
|
+
it 'converts Date objects' do
|
55
|
+
date = Date.new(2014, 8, 25)
|
56
|
+
SQLValue.new(date).should == "'2014-08-25'::date"
|
57
|
+
end
|
53
58
|
end
|
54
59
|
end
|
55
60
|
end
|
@@ -80,6 +80,14 @@ module Perpetuity
|
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
|
+
describe 'dates' do
|
84
|
+
let(:date) { Attribute.new('anniversary_date', Date) }
|
85
|
+
|
86
|
+
it 'converts to the SQL DATE type' do
|
87
|
+
date.sql_type.should == 'DATE'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
83
91
|
describe 'booleans' do
|
84
92
|
it 'is stored in a BOOLEAN column' do
|
85
93
|
Attribute.new(:true, TrueClass).sql_type.should == 'BOOLEAN'
|
@@ -29,6 +29,14 @@ module Perpetuity
|
|
29
29
|
'CREATE TABLE IF NOT EXISTS "Article" (id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), title TEXT, body TEXT, author JSON, published_at TIMESTAMPTZ, views BIGINT)'
|
30
30
|
end
|
31
31
|
|
32
|
+
it 'sets the id as PRIMARY KEY even if specified in attributes' do
|
33
|
+
attributes = self.attributes.dup
|
34
|
+
attributes.unshift Table::Attribute.new(:id, String)
|
35
|
+
table = Table.new('Article', attributes)
|
36
|
+
table.create_table_sql.should ==
|
37
|
+
'CREATE TABLE IF NOT EXISTS "Article" (id TEXT PRIMARY KEY, title TEXT, body TEXT, author JSON, published_at TIMESTAMPTZ, views BIGINT)'
|
38
|
+
end
|
39
|
+
|
32
40
|
describe 'id column' do
|
33
41
|
context 'when there is an id attribute' do
|
34
42
|
it 'uses the attribute type for the column type' do
|
@@ -25,25 +25,36 @@ module Perpetuity
|
|
25
25
|
password: password
|
26
26
|
)
|
27
27
|
end
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
its(:username) { should == username }
|
35
|
-
its(:password) { should == password }
|
28
|
+
|
29
|
+
[:host, :port, :db, :pool_size, :username, :password].each do |attribute|
|
30
|
+
it "returns its #{attribute}" do
|
31
|
+
postgres.public_send(attribute).should == send(attribute)
|
32
|
+
end
|
33
|
+
end
|
36
34
|
end
|
37
35
|
|
38
36
|
context 'default values' do
|
39
37
|
let(:postgres) { Postgres.new(db: 'my_db') }
|
40
|
-
subject { postgres }
|
41
38
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
it 'defaults to host = localhost' do
|
40
|
+
postgres.host.should == 'localhost'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'defaults to port = 5432 (Postgres default)' do
|
44
|
+
postgres.port.should == 5432
|
45
|
+
end
|
46
|
+
|
47
|
+
it "defaults to username = #{ENV['USER']}" do
|
48
|
+
postgres.username.should == ENV['USER']
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'defaults to a blank password' do
|
52
|
+
postgres.password.should be nil
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'defaults to pool_size = 5' do
|
56
|
+
postgres.pool_size.should == 5
|
57
|
+
end
|
47
58
|
end
|
48
59
|
end
|
49
60
|
|
@@ -108,7 +119,7 @@ module Perpetuity
|
|
108
119
|
Postgres::SerializedData.new([:name], ["'Kevin'"])
|
109
120
|
ids = postgres.insert('User', data, attributes)
|
110
121
|
ids.should be_a Array
|
111
|
-
ids.
|
122
|
+
expect(ids.count).to eq 3
|
112
123
|
end
|
113
124
|
|
114
125
|
it 'returns numeric ids when numeric ids are specified' do
|
@@ -128,7 +139,7 @@ module Perpetuity
|
|
128
139
|
it 'counts objects with a string query' do
|
129
140
|
insert = proc { postgres.insert 'User', data, attributes }
|
130
141
|
expect(&insert).to change { postgres.count('User', "name = 'Jamie'") }.by 1
|
131
|
-
expect(&insert).not_to change { postgres.count('User', "name = 'Jessica'") }
|
142
|
+
expect(&insert).not_to change { postgres.count('User', "name = 'Jessica'") }
|
132
143
|
end
|
133
144
|
|
134
145
|
it 'returns a count of 0 when the table does not exist' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: perpetuity-postgres
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamie Gaskins
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -98,6 +98,7 @@ files:
|
|
98
98
|
- lib/perpetuity/postgres/boolean_value.rb
|
99
99
|
- lib/perpetuity/postgres/connection.rb
|
100
100
|
- lib/perpetuity/postgres/connection_pool.rb
|
101
|
+
- lib/perpetuity/postgres/date_value.rb
|
101
102
|
- lib/perpetuity/postgres/expression.rb
|
102
103
|
- lib/perpetuity/postgres/index.rb
|
103
104
|
- lib/perpetuity/postgres/index_collection.rb
|
@@ -130,6 +131,7 @@ files:
|
|
130
131
|
- spec/perpetuity/postgres/boolean_value_spec.rb
|
131
132
|
- spec/perpetuity/postgres/connection_pool_spec.rb
|
132
133
|
- spec/perpetuity/postgres/connection_spec.rb
|
134
|
+
- spec/perpetuity/postgres/date_value_spec.rb
|
133
135
|
- spec/perpetuity/postgres/expression_spec.rb
|
134
136
|
- spec/perpetuity/postgres/index_collection_spec.rb
|
135
137
|
- spec/perpetuity/postgres/index_spec.rb
|
@@ -187,6 +189,7 @@ test_files:
|
|
187
189
|
- spec/perpetuity/postgres/boolean_value_spec.rb
|
188
190
|
- spec/perpetuity/postgres/connection_pool_spec.rb
|
189
191
|
- spec/perpetuity/postgres/connection_spec.rb
|
192
|
+
- spec/perpetuity/postgres/date_value_spec.rb
|
190
193
|
- spec/perpetuity/postgres/expression_spec.rb
|
191
194
|
- spec/perpetuity/postgres/index_collection_spec.rb
|
192
195
|
- spec/perpetuity/postgres/index_spec.rb
|