pg_data_encoder 0.1.6 → 0.1.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 +7 -0
- data/lib/pg_data_encoder/decoder.rb +181 -0
- data/lib/pg_data_encoder/encode_for_copy.rb +1 -3
- data/lib/pg_data_encoder/version.rb +1 -1
- data/lib/pg_data_encoder.rb +2 -0
- data/spec/fixtures/dates.dat +0 -0
- data/spec/fixtures/dates_p924.dat +0 -0
- data/spec/fixtures/dates_pg935.dat +0 -0
- data/spec/fixtures/timestamp_9.3.dat +0 -0
- data/spec/fixtures/timestamp_big.dat +0 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/verify_data_formats_spec.rb +64 -0
- data/spec/verify_decoder_spec.rb +290 -0
- metadata +25 -19
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0b19a299f91517f76fbcefc9698f35b227553c3b
|
4
|
+
data.tar.gz: 9b8eb4e9ad16d91064ad597eda6ba6fcd8f55436
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f0746ac331e9479f80ad608507d724e8705f6e569ada612663b394270004a89f04bb8fe5aadec2aad1c0186d390f9d377f2c7d6b0edc8336fd576ab4ae163d6d
|
7
|
+
data.tar.gz: 5685336f89acf111f1a1a907a968ba99d726cef7c50fbb1395246a3d34a45776840f8ac42da26a9b781ffb004e78ef28adff174eed95b90ed9886108d47b3f69
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
require 'stringio'
|
3
|
+
module PgDataEncoder
|
4
|
+
|
5
|
+
class Decoder
|
6
|
+
def initialize(options = {})
|
7
|
+
@options = options
|
8
|
+
@closed = false
|
9
|
+
if options[:column_types].kind_of?(Array)
|
10
|
+
map = {}
|
11
|
+
options[:column_types].each_with_index {|c, i|
|
12
|
+
map[i] = c
|
13
|
+
}
|
14
|
+
options[:column_types] = map
|
15
|
+
else
|
16
|
+
options[:column_types] ||= {}
|
17
|
+
end
|
18
|
+
@io = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def read_line
|
22
|
+
return nil if @closed
|
23
|
+
setup_io if !@io
|
24
|
+
row = []
|
25
|
+
bytes = @io.read(2)
|
26
|
+
#p bytes
|
27
|
+
column_count = bytes.unpack("n").first
|
28
|
+
if column_count == 65535
|
29
|
+
@closed = true
|
30
|
+
return nil
|
31
|
+
end
|
32
|
+
#@io.write([row.size].pack("n"))
|
33
|
+
0.upto(column_count - 1).each {|index|
|
34
|
+
field = decode_field(@io)
|
35
|
+
if field == nil
|
36
|
+
row[index] = field
|
37
|
+
elsif @options[:column_types][index]
|
38
|
+
row[index] = map_field(field, @options[:column_types][index])
|
39
|
+
else
|
40
|
+
row[index] = field
|
41
|
+
end
|
42
|
+
}
|
43
|
+
row
|
44
|
+
end
|
45
|
+
|
46
|
+
def each
|
47
|
+
loop do
|
48
|
+
result = read_line
|
49
|
+
if result
|
50
|
+
yield result
|
51
|
+
else
|
52
|
+
break
|
53
|
+
end
|
54
|
+
|
55
|
+
if @closed
|
56
|
+
break
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def setup_io
|
65
|
+
if @options[:file]
|
66
|
+
@io = File.open(@options[:file], "r:ASCII-8BIT")
|
67
|
+
elsif !@options[:io].nil?
|
68
|
+
@io = @options[:io]
|
69
|
+
else
|
70
|
+
raise "NO io present"
|
71
|
+
end
|
72
|
+
header = "PGCOPY\n\377\r\n\0".force_encoding("ASCII-8BIT")
|
73
|
+
result = @io.read(header.bytesize)
|
74
|
+
if result != header
|
75
|
+
raise "invalid format"
|
76
|
+
end
|
77
|
+
#p @io.read(10)
|
78
|
+
|
79
|
+
@io.read(2) #blank
|
80
|
+
@io.read(6) #blank
|
81
|
+
end
|
82
|
+
|
83
|
+
def decode_field(io)
|
84
|
+
|
85
|
+
bytes = io.read(4)
|
86
|
+
|
87
|
+
if bytes == "\xFF\xFF\xFF\xFF".force_encoding("ASCII-8BIT")
|
88
|
+
return nil
|
89
|
+
else
|
90
|
+
io.read(bytes.unpack("N").first)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def map_field(data, type)
|
95
|
+
#p [type, data]
|
96
|
+
|
97
|
+
case type
|
98
|
+
when :int, :integer
|
99
|
+
data.unpack("N").first
|
100
|
+
when :bytea
|
101
|
+
data
|
102
|
+
when :bigint
|
103
|
+
data.unpack("Q>").first
|
104
|
+
when :float
|
105
|
+
data.unpack("G").first
|
106
|
+
when :boolean
|
107
|
+
v = data.unpack("C").first
|
108
|
+
v == 1
|
109
|
+
when :string, :text, :character
|
110
|
+
data.force_encoding("UTF-8")
|
111
|
+
when :json
|
112
|
+
JSON.load(data)
|
113
|
+
when :uuid
|
114
|
+
r = data.unpack('H*').first
|
115
|
+
"#{r[0..7]}-#{r[8..11]}-#{r[12..15]}-#{r[16..19]}-#{r[20..-1]}"
|
116
|
+
when :uuid_raw
|
117
|
+
r = data.unpack('H*').first
|
118
|
+
when :array, :"integer[]", :"uuid[]", :"character[]"
|
119
|
+
io = StringIO.new(data)
|
120
|
+
io.read(4) #unknown
|
121
|
+
io.read(4) #unknown
|
122
|
+
atype = io.read(4).unpack("N").first #string type?
|
123
|
+
size = io.read(4).unpack("N").first
|
124
|
+
io.read(4) # should be 1 for dimension
|
125
|
+
#p [atype, size]
|
126
|
+
#p data
|
127
|
+
case atype
|
128
|
+
when 2950 #uuid
|
129
|
+
0.upto(size - 1).map {|i|
|
130
|
+
io.read(4) # size
|
131
|
+
r = io.read(16).unpack("H*").first
|
132
|
+
"#{r[0..7]}-#{r[8..11]}-#{r[12..15]}-#{r[16..19]}-#{r[20..-1]}"
|
133
|
+
}
|
134
|
+
when 1043 #string
|
135
|
+
0.upto(size - 1).map {|i|
|
136
|
+
size = io.read(4).unpack("N").first
|
137
|
+
io.read(size)
|
138
|
+
}
|
139
|
+
when 23 #int
|
140
|
+
0.upto(size - 1).map {|i|
|
141
|
+
size = io.read(4).unpack("N").first
|
142
|
+
bytes = io.read(size)
|
143
|
+
bytes.unpack("N").first
|
144
|
+
}
|
145
|
+
else
|
146
|
+
raise "Unsupported Array type #{atype}"
|
147
|
+
end
|
148
|
+
when :hstore, :hash
|
149
|
+
io = StringIO.new(data)
|
150
|
+
fields = io.read(4).unpack("N").first
|
151
|
+
h = {}
|
152
|
+
0.upto(fields - 1).each {|i|
|
153
|
+
key_size = io.read(4).unpack("N").first
|
154
|
+
key = io.read(key_size).force_encoding("UTF-8")
|
155
|
+
value_size = io.read(4).unpack("N").first
|
156
|
+
value = io.read(value_size).force_encoding("UTF-8")
|
157
|
+
h[key] = value
|
158
|
+
#p h
|
159
|
+
}
|
160
|
+
raise "remaining hstore bytes!" if io.pos != io.size
|
161
|
+
h
|
162
|
+
when :time, :timestamp
|
163
|
+
d = data.unpack("L!>").first
|
164
|
+
Time.at((d + POSTGRES_EPOCH_TIME) / 1_000_000.0).utc
|
165
|
+
when :date
|
166
|
+
# couldn't find another way to get signed network byte order
|
167
|
+
m = 0b0111_1111_1111_1111_1111_1111_1111_1111
|
168
|
+
d = data.unpack("N").first
|
169
|
+
if data.bytes[0] & 0b1000_0000 > 0 # negative number
|
170
|
+
d = (d & m) - m - 1
|
171
|
+
end
|
172
|
+
|
173
|
+
#p [data, d, Date.jd(d + Date.new(2000,1,1).jd)]
|
174
|
+
Date.jd(d + Date.new(2000,1,1).jd)
|
175
|
+
else
|
176
|
+
raise "Unsupported format #{format}"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
require 'tempfile'
|
2
2
|
require 'stringio'
|
3
3
|
module PgDataEncoder
|
4
|
-
POSTGRES_EPOCH_TIME = (Time.utc(2000,1,1).to_f * 1_000_000).to_i
|
5
|
-
|
6
4
|
|
7
5
|
class EncodeForCopy
|
8
6
|
def initialize(options = {})
|
@@ -178,7 +176,7 @@ module PgDataEncoder
|
|
178
176
|
hash_io.write(buf.to_s)
|
179
177
|
encode_field(hash_io, val.nil? ? val : val.to_s, index, depth + 1)
|
180
178
|
}
|
181
|
-
io.write([hash_io.pos].pack("N")) #
|
179
|
+
io.write([hash_io.pos].pack("N")) # size of hstore data
|
182
180
|
io.write(hash_io.string)
|
183
181
|
when Time
|
184
182
|
buf = [(field.to_f * 1_000_000 - POSTGRES_EPOCH_TIME).to_i].pack("L!>")
|
data/lib/pg_data_encoder.rb
CHANGED
@@ -2,7 +2,9 @@ require "pg_data_encoder/version"
|
|
2
2
|
|
3
3
|
require 'pg_data_encoder/temp_buffer'
|
4
4
|
require 'pg_data_encoder/encode_for_copy'
|
5
|
+
require 'pg_data_encoder/decoder'
|
5
6
|
|
6
7
|
module PgDataEncoder
|
7
8
|
# Your code goes here...
|
9
|
+
POSTGRES_EPOCH_TIME = (Time.utc(2000,1,1).to_f * 1_000_000).to_i
|
8
10
|
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/spec/spec_helper.rb
CHANGED
@@ -175,6 +175,57 @@ describe "generating data" do
|
|
175
175
|
str.should == existing_data
|
176
176
|
end
|
177
177
|
|
178
|
+
it 'should encode multiple 2015 dates' do
|
179
|
+
encoder = PgDataEncoder::EncodeForCopy.new
|
180
|
+
encoder.add [Date.parse("2015-04-08"), nil, Date.parse("2015-04-13")]
|
181
|
+
encoder.close
|
182
|
+
io = encoder.get_io
|
183
|
+
existing_data = filedata("dates.dat")
|
184
|
+
str = io.read
|
185
|
+
io.class.name.should == "StringIO"
|
186
|
+
str.force_encoding("ASCII-8BIT")
|
187
|
+
str.should == existing_data
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'should encode timestamp data correctly' do
|
191
|
+
encoder = PgDataEncoder::EncodeForCopy.new
|
192
|
+
encoder.add [Time.parse("2013-06-11 15:03:54.62605 UTC")]
|
193
|
+
encoder.close
|
194
|
+
io = encoder.get_io
|
195
|
+
existing_data = filedata("timestamp.dat")
|
196
|
+
str = io.read
|
197
|
+
io.class.name.should == "StringIO"
|
198
|
+
str.force_encoding("ASCII-8BIT")
|
199
|
+
#File.open("spec/fixtures/output.dat", "w:ASCII-8BIT") {|out| out.write(str) }
|
200
|
+
str.should == existing_data
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'should encode dates and times in pg 9.2.4' do
|
204
|
+
encoder = PgDataEncoder::EncodeForCopy.new
|
205
|
+
encoder.add [Date.parse('2015-04-08'), nil, Time.parse("2015-02-13 16:13:57.732772 UTC")]
|
206
|
+
encoder.close
|
207
|
+
io = encoder.get_io
|
208
|
+
existing_data = filedata("dates_p924.dat")
|
209
|
+
str = io.read
|
210
|
+
io.class.name.should == "StringIO"
|
211
|
+
str.force_encoding("ASCII-8BIT")
|
212
|
+
#File.open("spec/fixtures/output.dat", "w:ASCII-8BIT") {|out| out.write(str) }
|
213
|
+
str.should == existing_data
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'should encode dates and times in pg 9.3.5' do
|
217
|
+
encoder = PgDataEncoder::EncodeForCopy.new
|
218
|
+
encoder.add [Date.parse('2015-04-08'), nil, Time.parse("2015-02-13 16:13:57.732772 UTC")]
|
219
|
+
encoder.close
|
220
|
+
io = encoder.get_io
|
221
|
+
existing_data = filedata("dates_pg935.dat")
|
222
|
+
str = io.read
|
223
|
+
io.class.name.should == "StringIO"
|
224
|
+
str.force_encoding("ASCII-8BIT")
|
225
|
+
#File.open("spec/fixtures/output.dat", "w:ASCII-8BIT") {|out| out.write(str) }
|
226
|
+
str.should == existing_data
|
227
|
+
end
|
228
|
+
|
178
229
|
it 'should encode timestamp data correctly' do
|
179
230
|
encoder = PgDataEncoder::EncodeForCopy.new
|
180
231
|
encoder.add [Time.parse("2013-06-11 15:03:54.62605 UTC")]
|
@@ -188,6 +239,19 @@ describe "generating data" do
|
|
188
239
|
str.should == existing_data
|
189
240
|
end
|
190
241
|
|
242
|
+
it 'should encode big timestamp data correctly' do
|
243
|
+
encoder = PgDataEncoder::EncodeForCopy.new
|
244
|
+
encoder.add [Time.parse("2014-12-02 16:01:22.437311 UTC")]
|
245
|
+
encoder.close
|
246
|
+
io = encoder.get_io
|
247
|
+
existing_data = filedata("timestamp_9.3.dat")
|
248
|
+
str = io.read
|
249
|
+
io.class.name.should == "StringIO"
|
250
|
+
str.force_encoding("ASCII-8BIT")
|
251
|
+
#File.open("spec/fixtures/output.dat", "w:ASCII-8BIT") {|out| out.write(str) }
|
252
|
+
str.should == existing_data
|
253
|
+
end
|
254
|
+
|
191
255
|
it 'should encode float correctly from tempfile' do
|
192
256
|
encoder = PgDataEncoder::EncodeForCopy.new(:use_tempfile => true)
|
193
257
|
encoder.add [Time.parse("2013-06-11 15:03:54.62605 UTC")]
|
@@ -0,0 +1,290 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
3
|
+
|
4
|
+
describe "parsing data" do
|
5
|
+
|
6
|
+
it 'should walk through each line and stop' do
|
7
|
+
decoder = PgDataEncoder::Decoder.new(
|
8
|
+
io: fileio("hstore_utf8.dat"),
|
9
|
+
column_types: {0 => :hstore}
|
10
|
+
)
|
11
|
+
lines = []
|
12
|
+
decoder.each do |l|
|
13
|
+
lines << l
|
14
|
+
end
|
15
|
+
lines.should == [
|
16
|
+
[{'test' => "Ekström"}],
|
17
|
+
[{'test' => "Dueñas"}],
|
18
|
+
[{"account_first_name"=>"asdfasdf asñas", "testtesttesttesttesttestest"=>"" , "aasdfasdfasdfasdfasdfasdfasdfasdfasfasfasdfs"=>""}]
|
19
|
+
]
|
20
|
+
end
|
21
|
+
it 'should handle getting called after running out of data' do
|
22
|
+
decoder = PgDataEncoder::Decoder.new(
|
23
|
+
io: fileio("3_col_hstore.dat"),
|
24
|
+
column_types: {0 => :int, 1=> :string, 2 => :hstore}
|
25
|
+
)
|
26
|
+
r = decoder.read_line
|
27
|
+
r.should == [1, "text", {'a' => "1", "b" => "asdf"}]
|
28
|
+
decoder.read_line.should == nil
|
29
|
+
decoder.read_line.should == nil
|
30
|
+
|
31
|
+
|
32
|
+
end
|
33
|
+
it 'should encode hstore data correctly' do
|
34
|
+
decoder = PgDataEncoder::Decoder.new(
|
35
|
+
io: fileio("3_col_hstore.dat"),
|
36
|
+
column_types: {0 => :int, 1=> :string, 2 => :hstore}
|
37
|
+
)
|
38
|
+
r = decoder.read_line
|
39
|
+
r.should == [1, "text", {'a' => "1", "b" => "asdf"}]
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should return nil if past data' do
|
44
|
+
decoder = PgDataEncoder::Decoder.new(
|
45
|
+
io: fileio("3_col_hstore.dat"),
|
46
|
+
column_types: {0 => :int, 1=> :string, 2 => :hstore}
|
47
|
+
)
|
48
|
+
r = decoder.read_line
|
49
|
+
r.should == [1, "text", {'a' => "1", "b" => "asdf"}]
|
50
|
+
r = decoder.read_line
|
51
|
+
r.should == nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should encode hstore with utf8 data correctly from tempfile' do
|
55
|
+
decoder = PgDataEncoder::Decoder.new(
|
56
|
+
io: fileio("hstore_utf8.dat"),
|
57
|
+
column_types: {0 => :hstore}
|
58
|
+
)
|
59
|
+
r = decoder.read_line
|
60
|
+
r.should == [{'test' => "Ekström"}]
|
61
|
+
r = decoder.read_line
|
62
|
+
r.should == [{'test' => "Dueñas"}]
|
63
|
+
r = decoder.read_line
|
64
|
+
r.should == [{"account_first_name"=>"asdfasdf asñas", "testtesttesttesttesttestest"=>"" , "aasdfasdfasdfasdfasdfasdfasdfasdfasfasfasdfs"=>""}]
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should encode TrueClass data correctly' do
|
69
|
+
decoder = PgDataEncoder::Decoder.new(
|
70
|
+
io: fileio("trueclass.dat"),
|
71
|
+
column_types: {0 => :boolean}
|
72
|
+
)
|
73
|
+
r = decoder.read_line
|
74
|
+
r.should == [true]
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should encode FalseClass data correctly' do
|
78
|
+
decoder = PgDataEncoder::Decoder.new(
|
79
|
+
io: fileio("falseclass.dat"),
|
80
|
+
column_types: {0 => :boolean}
|
81
|
+
)
|
82
|
+
r = decoder.read_line
|
83
|
+
r.should == [false]
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should encode array data correctly' do
|
87
|
+
decoder = PgDataEncoder::Decoder.new(
|
88
|
+
io: fileio("array_with_two2.dat"),
|
89
|
+
column_types: {0 => :array}
|
90
|
+
)
|
91
|
+
r = decoder.read_line
|
92
|
+
r.should == [["hi", "jim"]]
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should encode string array data correctly' do
|
97
|
+
decoder = PgDataEncoder::Decoder.new(
|
98
|
+
io: fileio("big_str_array.dat"),
|
99
|
+
column_types: {0 => :array}
|
100
|
+
)
|
101
|
+
r = decoder.read_line
|
102
|
+
r.should == [['asdfasdfasdfasdf', 'asdfasdfasdfasdfadsfadf', '1123423423423']]
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should encode string array with big string int' do
|
107
|
+
decoder = PgDataEncoder::Decoder.new(
|
108
|
+
io: fileio("just_an_array2.dat"),
|
109
|
+
column_types: {0 => :array}
|
110
|
+
)
|
111
|
+
r = decoder.read_line
|
112
|
+
r.should == [["182749082739172"]]
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should encode string array data correctly' do
|
117
|
+
decoder = PgDataEncoder::Decoder.new(
|
118
|
+
io: fileio("big_str_array2.dat"),
|
119
|
+
column_types: {0 => :array}
|
120
|
+
)
|
121
|
+
r = decoder.read_line
|
122
|
+
r.should == [['asdfasdfasdfasdf', 'asdfasdfasdfasdfadsfadf']]
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
#it 'should encode array data from tempfile correctly' do
|
127
|
+
# encoder = PgDataEncoder::EncodeForCopy.new(:use_tempfile => true)
|
128
|
+
# encoder.add [1, "hi", ["hi", "there", "rubyist"]]
|
129
|
+
# encoder.close
|
130
|
+
# io = encoder.get_io
|
131
|
+
# existing_data = filedata("3_column_array.dat")
|
132
|
+
# str = io.read_line
|
133
|
+
# io.class.name.should == "Tempfile"
|
134
|
+
# str.force_encoding("ASCII-8BIT")
|
135
|
+
# str.should == existing_data
|
136
|
+
#end
|
137
|
+
|
138
|
+
it 'should encode integer array data from tempfile correctly' do
|
139
|
+
decoder = PgDataEncoder::Decoder.new(
|
140
|
+
io: fileio("intarray.dat"),
|
141
|
+
column_types: {0 => :array}
|
142
|
+
)
|
143
|
+
r = decoder.read_line
|
144
|
+
r.should == [[1,2,3]]
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should encode old date data correctly' do
|
148
|
+
decoder = PgDataEncoder::Decoder.new(
|
149
|
+
io: fileio("date.dat"),
|
150
|
+
column_types: {0 => :date}
|
151
|
+
)
|
152
|
+
r = decoder.read_line
|
153
|
+
r.should == [Date.parse("1900-12-03")]
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'should encode date data correctly for years > 2000' do
|
158
|
+
decoder = PgDataEncoder::Decoder.new(
|
159
|
+
io: fileio("date2000.dat"),
|
160
|
+
column_types: {0 => :date}
|
161
|
+
)
|
162
|
+
r = decoder.read_line
|
163
|
+
r.should == [Date.parse("2033-01-12")]
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should encode date data correctly in the 70s' do
|
168
|
+
decoder = PgDataEncoder::Decoder.new(
|
169
|
+
io: fileio("date2.dat"),
|
170
|
+
column_types: {0 => :date}
|
171
|
+
)
|
172
|
+
r = decoder.read_line
|
173
|
+
r.should == [Date.parse("1971-12-11")]
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'should encode multiple 2015 dates' do
|
178
|
+
decoder = PgDataEncoder::Decoder.new(
|
179
|
+
io: fileio("dates.dat"),
|
180
|
+
column_types: {0 => :date, 1 => :date, 2 => :date}
|
181
|
+
)
|
182
|
+
r = decoder.read_line
|
183
|
+
r.should == [Date.parse("2015-04-08"), nil, Date.parse("2015-04-13")]
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'should encode timestamp data correctly' do
|
188
|
+
decoder = PgDataEncoder::Decoder.new(
|
189
|
+
io: fileio("timestamp.dat"),
|
190
|
+
column_types: {0 => :time}
|
191
|
+
)
|
192
|
+
r = decoder.read_line
|
193
|
+
r.map(&:to_f).should == [Time.parse("2013-06-11 15:03:54.62605 UTC")].map(&:to_f)
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'should encode dates and times in pg 9.2.4' do
|
198
|
+
decoder = PgDataEncoder::Decoder.new(
|
199
|
+
io: fileio("dates_p924.dat"),
|
200
|
+
column_types: {0 => :date, 2 => :time}
|
201
|
+
)
|
202
|
+
r = decoder.read_line
|
203
|
+
r.map {|f| f.kind_of?(Time) ? f.to_f : f}.should == [Date.parse('2015-04-08'), nil, Time.parse("2015-02-13 16:13:57.732772 UTC")].map {|f| f.kind_of?(Time) ? f.to_f : f}
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'should encode dates and times in pg 9.3.5' do
|
208
|
+
decoder = PgDataEncoder::Decoder.new(
|
209
|
+
io: fileio("dates_pg935.dat"),
|
210
|
+
column_types: {0 => :date, 2 => :time}
|
211
|
+
)
|
212
|
+
r = decoder.read_line
|
213
|
+
r.map {|f| f.kind_of?(Time) ? f.to_f : f}.should == [Date.parse('2015-04-08'), nil, Time.parse("2015-02-13 16:13:57.732772 UTC")].map {|f| f.kind_of?(Time) ? f.to_f : f}
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
it 'should encode big timestamp data correctly' do
|
219
|
+
decoder = PgDataEncoder::Decoder.new(
|
220
|
+
io: fileio("timestamp_9.3.dat"),
|
221
|
+
column_types: {0 => :time}
|
222
|
+
)
|
223
|
+
r = decoder.read_line
|
224
|
+
r.map {|f| f.kind_of?(Time) ? f.to_f : f}.should == [Time.parse("2014-12-02 16:01:22.437311 UTC")].map {|f| f.kind_of?(Time) ? f.to_f : f}
|
225
|
+
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'should encode float data correctly' do
|
229
|
+
decoder = PgDataEncoder::Decoder.new(
|
230
|
+
io: fileio("float.dat"),
|
231
|
+
column_types: {0 => :float}
|
232
|
+
)
|
233
|
+
r = decoder.read_line
|
234
|
+
r.should == [1234567.1234567]
|
235
|
+
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'should encode uuid correctly from tempfile' do
|
239
|
+
decoder = PgDataEncoder::Decoder.new(
|
240
|
+
io: fileio("uuid.dat"),
|
241
|
+
column_types: {0 => :uuid}
|
242
|
+
)
|
243
|
+
r = decoder.read_line
|
244
|
+
r.should == ['e876eef5-a116-4a27-b71f-bac4a1dcd20e']
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'should encode null uuid correctly from tempfile' do
|
249
|
+
decoder = PgDataEncoder::Decoder.new(
|
250
|
+
io: fileio("empty_uuid.dat"),
|
251
|
+
column_types: {0 => :string, 1 => :uuid, 2 => :uuid, 3 => :integer}
|
252
|
+
)
|
253
|
+
r = decoder.read_line
|
254
|
+
r.should == ['before2', nil, nil, 123423423]
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
it 'should encode uuid correctly from tempfile' do
|
260
|
+
decoder = PgDataEncoder::Decoder.new(
|
261
|
+
io: fileio("uuid_array.dat"),
|
262
|
+
column_types: {0 => :array}
|
263
|
+
)
|
264
|
+
r = decoder.read_line
|
265
|
+
r.should == [['6272bd7d-adae-44b7-bba1-dca871c2a6fd', '7dc8431f-fcce-4d4d-86f3-6857cba47d38']]
|
266
|
+
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
it 'should encode utf8 string correctly' do
|
271
|
+
decoder = PgDataEncoder::Decoder.new(
|
272
|
+
io: fileio("utf8.dat"),
|
273
|
+
column_types: {0 => :string}
|
274
|
+
)
|
275
|
+
r = decoder.read_line
|
276
|
+
r.should == ["Ekström"]
|
277
|
+
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'should encode bigint as int correctly from tempfile' do
|
281
|
+
decoder = PgDataEncoder::Decoder.new(
|
282
|
+
io: fileio("bigint.dat"),
|
283
|
+
column_types: {0 => :bigint, 1 => :string}
|
284
|
+
)
|
285
|
+
r = decoder.read_line
|
286
|
+
r.should == [23372036854775808, 'test']
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
end
|
metadata
CHANGED
@@ -1,46 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_data_encoder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.7
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Pete Brumm
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2015-03-19 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rspec
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: 2.12.0
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: 2.12.0
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rspec-core
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: 2.12.0
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: 2.12.0
|
46
41
|
description: Creates a binary data file that can be imported into postgres's copy
|
@@ -51,13 +46,14 @@ executables: []
|
|
51
46
|
extensions: []
|
52
47
|
extra_rdoc_files: []
|
53
48
|
files:
|
54
|
-
- .gitignore
|
49
|
+
- ".gitignore"
|
55
50
|
- Gemfile
|
56
51
|
- LICENSE.txt
|
57
52
|
- README.md
|
58
53
|
- Rakefile
|
59
54
|
- examples/fast_load.rb
|
60
55
|
- lib/pg_data_encoder.rb
|
56
|
+
- lib/pg_data_encoder/decoder.rb
|
61
57
|
- lib/pg_data_encoder/encode_for_copy.rb
|
62
58
|
- lib/pg_data_encoder/temp_buffer.rb
|
63
59
|
- lib/pg_data_encoder/version.rb
|
@@ -76,6 +72,9 @@ files:
|
|
76
72
|
- spec/fixtures/date.dat
|
77
73
|
- spec/fixtures/date2.dat
|
78
74
|
- spec/fixtures/date2000.dat
|
75
|
+
- spec/fixtures/dates.dat
|
76
|
+
- spec/fixtures/dates_p924.dat
|
77
|
+
- spec/fixtures/dates_pg935.dat
|
79
78
|
- spec/fixtures/empty_uuid.dat
|
80
79
|
- spec/fixtures/falseclass.dat
|
81
80
|
- spec/fixtures/float.dat
|
@@ -86,6 +85,8 @@ files:
|
|
86
85
|
- spec/fixtures/multiline_hstore.dat
|
87
86
|
- spec/fixtures/output.dat
|
88
87
|
- spec/fixtures/timestamp.dat
|
88
|
+
- spec/fixtures/timestamp_9.3.dat
|
89
|
+
- spec/fixtures/timestamp_big.dat
|
89
90
|
- spec/fixtures/trueclass.dat
|
90
91
|
- spec/fixtures/utf8.dat
|
91
92
|
- spec/fixtures/uuid.dat
|
@@ -93,30 +94,30 @@ files:
|
|
93
94
|
- spec/multiline_spec.rb
|
94
95
|
- spec/spec_helper.rb
|
95
96
|
- spec/verify_data_formats_spec.rb
|
97
|
+
- spec/verify_decoder_spec.rb
|
96
98
|
homepage: https://github.com/pbrumm/pg_data_encoder
|
97
99
|
licenses:
|
98
100
|
- MIT
|
101
|
+
metadata: {}
|
99
102
|
post_install_message:
|
100
103
|
rdoc_options: []
|
101
104
|
require_paths:
|
102
105
|
- lib
|
103
106
|
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
-
none: false
|
105
107
|
requirements:
|
106
|
-
- -
|
108
|
+
- - ">="
|
107
109
|
- !ruby/object:Gem::Version
|
108
110
|
version: '0'
|
109
111
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
-
none: false
|
111
112
|
requirements:
|
112
|
-
- -
|
113
|
+
- - ">="
|
113
114
|
- !ruby/object:Gem::Version
|
114
115
|
version: '0'
|
115
116
|
requirements: []
|
116
117
|
rubyforge_project:
|
117
|
-
rubygems_version:
|
118
|
+
rubygems_version: 2.2.2
|
118
119
|
signing_key:
|
119
|
-
specification_version:
|
120
|
+
specification_version: 4
|
120
121
|
summary: for faster input of data into postgres you can use this to generate the binary
|
121
122
|
import and run COPY FROM
|
122
123
|
test_files:
|
@@ -134,6 +135,9 @@ test_files:
|
|
134
135
|
- spec/fixtures/date.dat
|
135
136
|
- spec/fixtures/date2.dat
|
136
137
|
- spec/fixtures/date2000.dat
|
138
|
+
- spec/fixtures/dates.dat
|
139
|
+
- spec/fixtures/dates_p924.dat
|
140
|
+
- spec/fixtures/dates_pg935.dat
|
137
141
|
- spec/fixtures/empty_uuid.dat
|
138
142
|
- spec/fixtures/falseclass.dat
|
139
143
|
- spec/fixtures/float.dat
|
@@ -144,6 +148,8 @@ test_files:
|
|
144
148
|
- spec/fixtures/multiline_hstore.dat
|
145
149
|
- spec/fixtures/output.dat
|
146
150
|
- spec/fixtures/timestamp.dat
|
151
|
+
- spec/fixtures/timestamp_9.3.dat
|
152
|
+
- spec/fixtures/timestamp_big.dat
|
147
153
|
- spec/fixtures/trueclass.dat
|
148
154
|
- spec/fixtures/utf8.dat
|
149
155
|
- spec/fixtures/uuid.dat
|
@@ -151,4 +157,4 @@ test_files:
|
|
151
157
|
- spec/multiline_spec.rb
|
152
158
|
- spec/spec_helper.rb
|
153
159
|
- spec/verify_data_formats_spec.rb
|
154
|
-
|
160
|
+
- spec/verify_decoder_spec.rb
|