pg_data_encoder 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|