torque-postgresql 1.1.8 → 2.0.0

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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/lib/torque/postgresql.rb +0 -2
  3. data/lib/torque/postgresql/adapter.rb +0 -1
  4. data/lib/torque/postgresql/adapter/database_statements.rb +4 -15
  5. data/lib/torque/postgresql/adapter/schema_creation.rb +13 -23
  6. data/lib/torque/postgresql/adapter/schema_definitions.rb +7 -21
  7. data/lib/torque/postgresql/adapter/schema_dumper.rb +71 -11
  8. data/lib/torque/postgresql/adapter/schema_statements.rb +2 -12
  9. data/lib/torque/postgresql/associations.rb +0 -3
  10. data/lib/torque/postgresql/associations/association.rb +0 -4
  11. data/lib/torque/postgresql/associations/association_scope.rb +18 -60
  12. data/lib/torque/postgresql/associations/belongs_to_many_association.rb +12 -15
  13. data/lib/torque/postgresql/associations/preloader.rb +0 -32
  14. data/lib/torque/postgresql/associations/preloader/association.rb +13 -10
  15. data/lib/torque/postgresql/autosave_association.rb +4 -4
  16. data/lib/torque/postgresql/auxiliary_statement.rb +1 -13
  17. data/lib/torque/postgresql/coder.rb +1 -2
  18. data/lib/torque/postgresql/config.rb +0 -6
  19. data/lib/torque/postgresql/inheritance.rb +13 -17
  20. data/lib/torque/postgresql/reflection/abstract_reflection.rb +19 -25
  21. data/lib/torque/postgresql/reflection/belongs_to_many_reflection.rb +4 -38
  22. data/lib/torque/postgresql/relation.rb +11 -16
  23. data/lib/torque/postgresql/relation/auxiliary_statement.rb +2 -8
  24. data/lib/torque/postgresql/relation/distinct_on.rb +1 -1
  25. data/lib/torque/postgresql/version.rb +1 -1
  26. data/spec/en.yml +19 -0
  27. data/spec/factories/authors.rb +6 -0
  28. data/spec/factories/comments.rb +13 -0
  29. data/spec/factories/posts.rb +6 -0
  30. data/spec/factories/tags.rb +5 -0
  31. data/spec/factories/texts.rb +5 -0
  32. data/spec/factories/users.rb +6 -0
  33. data/spec/factories/videos.rb +5 -0
  34. data/spec/mocks/cache_query.rb +16 -0
  35. data/spec/mocks/create_table.rb +35 -0
  36. data/spec/models/activity.rb +3 -0
  37. data/spec/models/activity_book.rb +4 -0
  38. data/spec/models/activity_post.rb +7 -0
  39. data/spec/models/activity_post/sample.rb +4 -0
  40. data/spec/models/author.rb +4 -0
  41. data/spec/models/author_journalist.rb +4 -0
  42. data/spec/models/comment.rb +3 -0
  43. data/spec/models/course.rb +2 -0
  44. data/spec/models/geometry.rb +2 -0
  45. data/spec/models/guest_comment.rb +4 -0
  46. data/spec/models/post.rb +6 -0
  47. data/spec/models/tag.rb +2 -0
  48. data/spec/models/text.rb +2 -0
  49. data/spec/models/time_keeper.rb +2 -0
  50. data/spec/models/user.rb +8 -0
  51. data/spec/models/video.rb +2 -0
  52. data/spec/schema.rb +141 -0
  53. data/spec/spec_helper.rb +59 -0
  54. data/spec/tests/arel_spec.rb +72 -0
  55. data/spec/tests/auxiliary_statement_spec.rb +593 -0
  56. data/spec/tests/belongs_to_many_spec.rb +240 -0
  57. data/spec/tests/coder_spec.rb +367 -0
  58. data/spec/tests/collector_spec.rb +59 -0
  59. data/spec/tests/distinct_on_spec.rb +65 -0
  60. data/spec/tests/enum_set_spec.rb +306 -0
  61. data/spec/tests/enum_spec.rb +621 -0
  62. data/spec/tests/geometric_builder_spec.rb +221 -0
  63. data/spec/tests/has_many_spec.rb +390 -0
  64. data/spec/tests/interval_spec.rb +167 -0
  65. data/spec/tests/lazy_spec.rb +24 -0
  66. data/spec/tests/period_spec.rb +954 -0
  67. data/spec/tests/quoting_spec.rb +24 -0
  68. data/spec/tests/range_spec.rb +36 -0
  69. data/spec/tests/relation_spec.rb +57 -0
  70. data/spec/tests/table_inheritance_spec.rb +403 -0
  71. metadata +103 -15
  72. data/lib/torque/postgresql/associations/join_dependency/join_association.rb +0 -15
  73. data/lib/torque/postgresql/schema_dumper.rb +0 -101
@@ -0,0 +1,240 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'BelongsToMany' do
4
+ context 'on model' do
5
+ let(:model) { Video }
6
+ let(:builder) { Torque::PostgreSQL::Associations::Builder::BelongsToMany }
7
+ let(:reflection) { Torque::PostgreSQL::Reflection::BelongsToManyReflection }
8
+ after { model._reflections = {} }
9
+
10
+ it 'has the builder method' do
11
+ expect(model).to respond_to(:belongs_to_many)
12
+ end
13
+
14
+ it 'triggers the correct builder and relation' do
15
+ expect(builder).to receive(:build).with(anything, :tests, nil, {}) do |_, name, _, _|
16
+ ActiveRecord::Reflection.create(:belongs_to_many, name, nil, {}, model)
17
+ end
18
+
19
+ expect(reflection).to receive(:new).with(:tests, nil, {}, model)
20
+
21
+ model.belongs_to_many(:tests)
22
+ end
23
+ end
24
+
25
+ context 'on association' do
26
+ let(:other) { Tag }
27
+ let(:initial) { FactoryBot.create(:tag) }
28
+
29
+ before { Video.belongs_to_many :tags }
30
+ subject { Video.create(title: 'A') }
31
+ after { Video._reflections = {} }
32
+
33
+ it 'has the method' do
34
+ expect(subject).to respond_to(:tags)
35
+ expect(subject._reflections).to include('tags')
36
+ end
37
+
38
+ it 'loads associated records' do
39
+ subject.update(tag_ids: [initial.id])
40
+ expect(subject.tags.to_sql).to be_eql(<<-SQL.squish)
41
+ SELECT "tags".* FROM "tags" WHERE "tags"."id" IN (#{initial.id})
42
+ SQL
43
+
44
+ expect(subject.tags.load).to be_a(ActiveRecord::Associations::CollectionProxy)
45
+ expect(subject.tags.to_a).to be_eql([initial])
46
+ end
47
+
48
+ it 'can be marked as loaded' do
49
+ expect(subject.tags.loaded?).to be_eql(false)
50
+ expect(subject.tags).to respond_to(:load_target)
51
+ expect(subject.tags.load_target).to be_eql([])
52
+ expect(subject.tags.loaded?).to be_eql(true)
53
+ end
54
+
55
+ it 'can find specific records' do
56
+ records = FactoryBot.create_list(:tag, 10)
57
+ subject.update(tag_ids: records.map(&:id))
58
+ ids = records.map(&:id).sample(5)
59
+
60
+ expect(subject.tags).to respond_to(:find)
61
+ records = subject.tags.find(*ids)
62
+
63
+ expect(records.size).to be_eql(5)
64
+ expect(records.map(&:id).sort).to be_eql(ids.sort)
65
+ end
66
+
67
+ it 'can return last n records' do
68
+ records = FactoryBot.create_list(:tag, 10)
69
+ subject.update(tag_ids: records.map(&:id))
70
+ ids = records.map(&:id).last(5)
71
+
72
+ expect(subject.tags).to respond_to(:last)
73
+ records = subject.tags.last(5)
74
+
75
+ expect(records.size).to be_eql(5)
76
+ expect(records.map(&:id).sort).to be_eql(ids.sort)
77
+ end
78
+
79
+ it 'can return first n records' do
80
+ records = FactoryBot.create_list(:tag, 10)
81
+ subject.update(tag_ids: records.map(&:id))
82
+ ids = records.map(&:id).first(5)
83
+
84
+ expect(subject.tags).to respond_to(:take)
85
+ records = subject.tags.take(5)
86
+
87
+ expect(records.size).to be_eql(5)
88
+ expect(records.map(&:id).sort).to be_eql(ids.sort)
89
+ end
90
+
91
+ it 'can build an associated record' do
92
+ record = subject.tags.build(name: 'Test')
93
+ expect(record).to be_a(other)
94
+ expect(record).not_to be_persisted
95
+ expect(record.name).to be_eql('Test')
96
+
97
+ expect(subject.save).to be_truthy
98
+ expect(subject.tag_ids).to be_eql([record.id])
99
+ expect(subject.tags.size).to be_eql(1)
100
+ end
101
+
102
+ it 'can create an associated record' do
103
+ record = subject.tags.create(name: 'Test')
104
+ expect(subject.tags).to respond_to(:create!)
105
+
106
+ expect(record).to be_a(other)
107
+ expect(record).to be_persisted
108
+ expect(record.name).to be_eql('Test')
109
+ expect(subject.tag_ids).to be_eql([record.id])
110
+ end
111
+
112
+ it 'can concat records' do
113
+ record = FactoryBot.create(:tag)
114
+ subject.update(tag_ids: [record.id])
115
+ expect(subject.tags.size).to be_eql(1)
116
+
117
+ subject.tags.concat(other.new(name: 'Test'))
118
+ subject.tags.reload
119
+ expect(subject.tags.size).to be_eql(2)
120
+ expect(subject.tag_ids.size).to be_eql(2)
121
+ expect(subject.tags.last.name).to be_eql('Test')
122
+ end
123
+
124
+ it 'can replace records' do
125
+ subject.tags << FactoryBot.create(:tag)
126
+ expect(subject.tags.size).to be_eql(1)
127
+
128
+ subject.tags.replace([other.new(name: 'Test 1'), other.new(name: 'Test 2')])
129
+ expect(subject.tags.size).to be_eql(2)
130
+ expect(subject.tags[0].name).to be_eql('Test 1')
131
+ expect(subject.tags[1].name).to be_eql('Test 2')
132
+ end
133
+
134
+ it 'can delete all records' do
135
+ subject.tags.concat(FactoryBot.create_list(:tag, 5))
136
+ expect(subject.tags.size).to be_eql(5)
137
+
138
+ subject.tags.delete_all
139
+ expect(subject.tags.size).to be_eql(0)
140
+ end
141
+
142
+ it 'can destroy all records' do
143
+ subject.tags.concat(FactoryBot.create_list(:tag, 5))
144
+ expect(subject.tags.size).to be_eql(5)
145
+
146
+ subject.tags.destroy_all
147
+ expect(subject.tags.size).to be_eql(0)
148
+ end
149
+
150
+ it 'can have sum operations' do
151
+ records = FactoryBot.create_list(:tag, 5)
152
+ subject.tags.concat(records)
153
+
154
+ result = records.map(&:id).reduce(:+)
155
+ expect(subject.tags).to respond_to(:sum)
156
+ expect(subject.tags.sum(:id)).to be_eql(result)
157
+ end
158
+
159
+ it 'can have a pluck operation' do
160
+ records = FactoryBot.create_list(:tag, 5)
161
+ subject.tags.concat(records)
162
+
163
+ result = records.map(&:name).sort
164
+ expect(subject.tags).to respond_to(:pluck)
165
+ expect(subject.tags.pluck(:name).sort).to be_eql(result)
166
+ end
167
+
168
+ it 'can be markes as empty' do
169
+ expect(subject.tags).to respond_to(:empty?)
170
+ expect(subject.tags.empty?).to be_truthy
171
+
172
+ subject.tags << FactoryBot.create(:tag)
173
+ expect(subject.tags.empty?).to be_falsey
174
+ end
175
+
176
+ it 'can check if a record is included on the list' do
177
+ outside = FactoryBot.create(:tag)
178
+ inside = FactoryBot.create(:tag)
179
+ subject.tags << inside
180
+
181
+ expect(subject.tags).to respond_to(:include?)
182
+ expect(subject.tags.include?(inside)).to be_truthy
183
+ expect(subject.tags.include?(outside)).to be_falsey
184
+ end
185
+
186
+ it 'can append records' do
187
+ subject.tags << other.new(name: 'Test 1')
188
+ expect(subject.tags.size).to be_eql(1)
189
+
190
+ subject.tags << other.new(name: 'Test 2')
191
+ expect(subject.tags.size).to be_eql(2)
192
+ expect(subject.tags.last.name).to be_eql('Test 2')
193
+ end
194
+
195
+ it 'can clear records' do
196
+ subject.tags << FactoryBot.create(:tag)
197
+ expect(subject.tags.size).to be_eql(1)
198
+
199
+ subject.tags.clear
200
+ expect(subject.tags.size).to be_eql(0)
201
+ end
202
+
203
+ it 'can reload records' do
204
+ expect(subject.tags.size).to be_eql(0)
205
+ subject.tags << FactoryBot.create(:tag)
206
+
207
+ subject.tags.reload
208
+ expect(subject.tags.size).to be_eql(1)
209
+ end
210
+
211
+ it 'can preload records' do
212
+ records = FactoryBot.create_list(:tag, 5)
213
+ subject.tags.concat(records)
214
+
215
+ entries = Video.all.includes(:tags).load
216
+
217
+ expect(entries.size).to be_eql(1)
218
+ expect(entries.first.tags).to be_loaded
219
+ expect(entries.first.tags.size).to be_eql(5)
220
+ end
221
+
222
+ it 'can joins records' do
223
+ query = Video.all.joins(:tags)
224
+ expect(query.to_sql).to match(/INNER JOIN "tags"/)
225
+ expect { query.load }.not_to raise_error
226
+ end
227
+
228
+ context "When record is not persisted" do
229
+ let(:initial) { FactoryBot.create(:tag) }
230
+ before { Video.belongs_to_many :tags }
231
+ subject { Video.new(title: 'A', tags: [initial]) }
232
+ after { Video._reflections = {} }
233
+
234
+ it 'loads associated records' do
235
+ expect(subject.tags.load).to be_a(ActiveRecord::Associations::CollectionProxy)
236
+ expect(subject.tags.to_a).to be_eql([initial])
237
+ end
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,367 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Complex coder', type: :helper do
4
+ let(:coder) { Torque::PostgreSQL::Coder }
5
+
6
+ context 'on decode' do
7
+
8
+ context 'one dimensional arrays' do
9
+ it 'returns an empty array' do
10
+ expect(coder.decode(%[{}])).to eql []
11
+ end
12
+
13
+ it 'returns an array of strings' do
14
+ expect(coder.decode(%[{1,2,3}])).to eql ['1','2','3']
15
+ end
16
+
17
+ it 'returns an array of strings, with nils replacing NULL characters' do
18
+ expect(coder.decode(%[{1,,NULL}])).to eql ['1',nil,nil]
19
+ end
20
+
21
+ it 'returns an array with the word NULL' do
22
+ expect(coder.decode(%[{1,"NULL",3}])).to eql ['1','NULL','3']
23
+ end
24
+
25
+ it 'returns an array of strings when containing commas in a quoted string' do
26
+ expect(coder.decode(%[{1,"2,3",4}])).to eql ['1','2,3','4']
27
+ end
28
+
29
+ it 'returns an array of strings when containing an escaped quote' do
30
+ expect(coder.decode(%[{1,"2\\",3",4}])).to eql ['1','2",3','4']
31
+ end
32
+
33
+ it 'returns an array of strings when containing an escaped backslash' do
34
+ expect(coder.decode(%[{1,"2\\\\",3,4}])).to eql ['1','2\\','3','4']
35
+ expect(coder.decode(%[{1,"2\\\\\\",3",4}])).to eql ['1','2\\",3','4']
36
+ end
37
+
38
+ it 'returns an array containing empty strings' do
39
+ expect(coder.decode(%[{1,"",3,""}])).to eql ['1', '', '3', '']
40
+ end
41
+
42
+ it 'returns an array containing unicode strings' do
43
+ expect(coder.decode(%[{"Paragraph 399(b)(i) – “valid leave” – meaning"}])).to eq(['Paragraph 399(b)(i) – “valid leave” – meaning'])
44
+ end
45
+ end
46
+
47
+ context 'two dimensional arrays' do
48
+ it 'returns an empty array' do
49
+ expect(coder.decode(%[{{}}])).to eql [[]]
50
+ expect(coder.decode(%[{{},{}}])).to eql [[],[]]
51
+ end
52
+
53
+ it 'returns an array of strings with a sub array' do
54
+ expect(coder.decode(%[{1,{2,3},4}])).to eql ['1',['2','3'],'4']
55
+ end
56
+
57
+ it 'returns an array of strings with a sub array' do
58
+ expect(coder.decode(%[{1,{"2,3"},4}])).to eql ['1',['2,3'],'4']
59
+ end
60
+
61
+ it 'returns an array of strings with a sub array and a quoted }' do
62
+ expect(coder.decode(%[{1,{"2,}3",,NULL},4}])).to eql ['1',['2,}3',nil,nil],'4']
63
+ end
64
+
65
+ it 'returns an array of strings with a sub array and a quoted {' do
66
+ expect(coder.decode(%[{1,{"2,{3"},4}])).to eql ['1',['2,{3'],'4']
67
+ end
68
+
69
+ it 'returns an array of strings with a sub array and a quoted { and escaped quote' do
70
+ expect(coder.decode(%[{1,{"2\\",{3"},4}])).to eql ['1',['2",{3'],'4']
71
+ end
72
+
73
+ it 'returns an array of strings with a sub array with empty strings' do
74
+ expect(coder.decode(%[{1,{""},4,{""}}])).to eql ['1',[''],'4',['']]
75
+ end
76
+ end
77
+
78
+ context 'three dimensional arrays' do
79
+ it 'returns an empty array' do
80
+ expect(coder.decode(%[{{{}}}])).to eql [[[]]]
81
+ expect(coder.decode(%[{{{},{}},{{},{}}}])).to eql [[[],[]],[[],[]]]
82
+ end
83
+
84
+ it 'returns an array of strings with sub arrays' do
85
+ expect(coder.decode(%[{1,{2,{3,4}},{NULL,,6},7}])).to eql ['1',['2',['3','4']],[nil,nil,'6'],'7']
86
+ end
87
+ end
88
+
89
+ context 'record syntax' do
90
+ it 'returns an empty array' do
91
+ expect(coder.decode(%[()])).to eql []
92
+ end
93
+
94
+ it 'returns an array of strings' do
95
+ expect(coder.decode(%[(1,2,3)])).to eql ['1','2','3']
96
+ end
97
+
98
+ it 'returns an array of strings, with nils replacing NULL characters' do
99
+ expect(coder.decode(%[(1,,NULL)])).to eql ['1',nil,nil]
100
+ end
101
+
102
+ it 'returns an array with the word NULL' do
103
+ expect(coder.decode(%[(1,"NULL",3)])).to eql ['1','NULL','3']
104
+ end
105
+
106
+ it 'returns an array of strings when containing commas in a quoted string' do
107
+ expect(coder.decode(%[(1,"2,3",4)])).to eql ['1','2,3','4']
108
+ end
109
+
110
+ it 'returns an array of strings when containing an escaped quote' do
111
+ expect(coder.decode(%[(1,"2\\",3",4)])).to eql ['1','2",3','4']
112
+ end
113
+
114
+ it 'returns an array of strings when containing an escaped backslash' do
115
+ expect(coder.decode(%[(1,"2\\\\",3,4)])).to eql ['1','2\\','3','4']
116
+ expect(coder.decode(%[(1,"2\\\\\\",3",4)])).to eql ['1','2\\",3','4']
117
+ end
118
+
119
+ it 'returns an array containing empty strings' do
120
+ expect(coder.decode(%[(1,"",3,"")])).to eql ['1', '', '3', '']
121
+ end
122
+
123
+ it 'returns an array containing unicode strings' do
124
+ expect(coder.decode(%[("Paragraph 399(b)(i) – “valid leave” – meaning")])).to eq(['Paragraph 399(b)(i) – “valid leave” – meaning'])
125
+ end
126
+ end
127
+
128
+ context 'array of records' do
129
+ it 'returns an empty array' do
130
+ expect(coder.decode(%[{()}])).to eql [[]]
131
+ expect(coder.decode(%[{(),()}])).to eql [[],[]]
132
+ end
133
+
134
+ it 'returns an array of strings with a sub array' do
135
+ expect(coder.decode(%[{1,(2,3),4}])).to eql ['1',['2','3'],'4']
136
+ end
137
+
138
+ it 'returns an array of strings with a sub array' do
139
+ expect(coder.decode(%[{1,("2,3"),4}])).to eql ['1',['2,3'],'4']
140
+ end
141
+
142
+ it 'returns an array of strings with a sub array and a quoted }' do
143
+ expect(coder.decode(%[{1,("2,}3",,NULL),4}])).to eql ['1',['2,}3',nil,nil],'4']
144
+ end
145
+
146
+ it 'returns an array of strings with a sub array and a quoted {' do
147
+ expect(coder.decode(%[{1,("2,{3"),4}])).to eql ['1',['2,{3'],'4']
148
+ end
149
+
150
+ it 'returns an array of strings with a sub array and a quoted { and escaped quote' do
151
+ expect(coder.decode(%[{1,("2\\",{3"),4}])).to eql ['1',['2",{3'],'4']
152
+ end
153
+
154
+ it 'returns an array of strings with a sub array with empty strings' do
155
+ expect(coder.decode(%[{1,(""),4,("")}])).to eql ['1',[''],'4',['']]
156
+ end
157
+ end
158
+
159
+ context 'mix of record and array' do
160
+ it 'returns an empty array' do
161
+ expect(coder.decode(%[({()})])).to eql [[[]]]
162
+ expect(coder.decode(%[{({},{}),{(),{}}}])).to eql [[[],[]],[[],[]]]
163
+ end
164
+
165
+ it 'returns an array of strings with sub arrays' do
166
+ expect(coder.decode(%[{1,(2,{3,4}),(NULL,,6),7}])).to eql ['1',['2',['3','4']],[nil,nil,'6'],'7']
167
+ end
168
+ end
169
+
170
+ context 'record complex sample' do
171
+ it 'may have double double quotes translate to single double quotes' do
172
+ expect(coder.decode(%[("Test with double "" quoutes")])).to eql ['Test with double " quoutes']
173
+ end
174
+
175
+ it 'double double quotes may occur any number of times' do
176
+ expect(coder.decode(%[("Only one ""","Now "" two "".",""",""{""}","""""")])).to eql ['Only one "', 'Now " two ".', '","{"}', '""']
177
+ end
178
+
179
+ it 'may have any kind of value' do
180
+ expect(coder.decode(%[(String,123456,false,true,"2016-01-01 12:00:00",{1,2,3})])).to eql ['String', '123456', 'false', 'true', '2016-01-01 12:00:00', ['1', '2', '3']]
181
+ end
182
+ end
183
+
184
+ end
185
+
186
+ context 'on encode' do
187
+ let(:record) { Torque::PostgreSQL::Coder::Record }
188
+
189
+ context 'one dimensional arrays' do
190
+ it 'receives an empty array' do
191
+ expect(coder.encode([])).to eql %[{}]
192
+ end
193
+
194
+ it 'receives an array of strings' do
195
+ expect(coder.encode(['1','2','3'])).to eql %[{1,2,3}]
196
+ end
197
+
198
+ it 'receives an array of strings, with nils replacing NULL characters' do
199
+ expect(coder.encode(['1',nil,nil])).to eql %[{1,NULL,NULL}]
200
+ end
201
+
202
+ it 'receives an array with the word NULL' do
203
+ expect(coder.encode(['1','NULL','3'])).to eql %[{1,"NULL",3}]
204
+ end
205
+
206
+ it 'receives an array of strings when containing commas in a quoted string' do
207
+ expect(coder.encode(['1','2,3','4'])).to eql %[{1,"2,3",4}]
208
+ end
209
+
210
+ it 'receives an array of strings when containing an escaped quote' do
211
+ expect(coder.encode(['1','2",3','4'])).to eql %[{1,"2\\",3",4}]
212
+ end
213
+
214
+ it 'receives an array of strings when containing an escaped backslash' do
215
+ expect(coder.encode(['1','2\\','3','4'])).to eql %[{1,"2\\\\",3,4}]
216
+ expect(coder.encode(['1','2\\",3','4'])).to eql %[{1,"2\\\\\\",3",4}]
217
+ end
218
+
219
+ it 'receives an array containing empty strings' do
220
+ expect(coder.encode(['1', '', '3', ''])).to eql %[{1,"",3,""}]
221
+ end
222
+
223
+ it 'receives an array containing unicode strings' do
224
+ expect(coder.encode(['Paragraph 399(b)(i) – “valid leave” – meaning'])).to eql %[{"Paragraph 399(b)(i) – “valid leave” – meaning"}]
225
+ end
226
+ end
227
+
228
+ context 'two dimensional arrays' do
229
+ it 'receives an empty array' do
230
+ expect(coder.encode([[]])).to eql %[{{}}]
231
+ expect(coder.encode([[],[]])).to eql %[{{},{}}]
232
+ end
233
+
234
+ it 'receives an array of strings with a sub array' do
235
+ expect(coder.encode(['1',['2','3'],'4'])).to eql %[{1,{2,3},4}]
236
+ end
237
+
238
+ it 'receives an array of strings with a sub array' do
239
+ expect(coder.encode(['1',['2,3'],'4'])).to eql %[{1,{"2,3"},4}]
240
+ end
241
+
242
+ it 'receives an array of strings with a sub array and a quoted }' do
243
+ expect(coder.encode(['1',['2,}3',nil,nil],'4'])).to eql %[{1,{"2,}3",NULL,NULL},4}]
244
+ end
245
+
246
+ it 'receives an array of strings with a sub array and a quoted {' do
247
+ expect(coder.encode(['1',['2,{3'],'4'])).to eql %[{1,{"2,{3"},4}]
248
+ end
249
+
250
+ it 'receives an array of strings with a sub array and a quoted { and escaped quote' do
251
+ expect(coder.encode(['1',['2",{3'],'4'])).to eql %[{1,{"2\\",{3"},4}]
252
+ end
253
+
254
+ it 'receives an array of strings with a sub array with empty strings' do
255
+ expect(coder.encode(['1',[''],'4',['']])).to eql %[{1,{""},4,{""}}]
256
+ end
257
+ end
258
+
259
+ context 'three dimensional arrays' do
260
+ it 'receives an empty array' do
261
+ expect(coder.encode([[[]]])).to eql %[{{{}}}]
262
+ expect(coder.encode([[[],[]],[[],[]]])).to eql %[{{{},{}},{{},{}}}]
263
+ end
264
+
265
+ it 'receives an array of strings with sub arrays' do
266
+ expect(coder.encode(['1',['2',['3','4']],[nil,nil,'6'],'7'])).to eql %[{1,{2,{3,4}},{NULL,NULL,6},7}]
267
+ end
268
+ end
269
+
270
+ context 'record syntax' do
271
+ it 'receives an empty array' do
272
+ expect(coder.encode( record.new )).to eql %[()]
273
+ end
274
+
275
+ it 'receives an array of strings' do
276
+ expect(coder.encode( record.new(['1','2','3']) )).to eql %[(1,2,3)]
277
+ end
278
+
279
+ it 'receives an array of strings, with nils replacing NULL characters' do
280
+ expect(coder.encode( record.new(['1',nil,nil]) )).to eql %[(1,,)]
281
+ end
282
+
283
+ it 'receives an array with the word NULL' do
284
+ expect(coder.encode( record.new(['1','NULL','3']) )).to eql %[(1,"NULL",3)]
285
+ end
286
+
287
+ it 'receives an array of strings when containing commas in a quoted string' do
288
+ expect(coder.encode( record.new(['1','2,3','4']) )).to eql %[(1,"2,3",4)]
289
+ end
290
+
291
+ it 'receives an array of strings when containing an escaped quote' do
292
+ expect(coder.encode( record.new(['1','2",3','4']) )).to eql %[(1,"2\\",3",4)]
293
+ end
294
+
295
+ it 'receives an array of strings when containing an escaped backslash' do
296
+ expect(coder.encode( record.new(['1','2\\','3','4']) )).to eql %[(1,"2\\\\",3,4)]
297
+ expect(coder.encode( record.new(['1','2\\",3','4']) )).to eql %[(1,"2\\\\\\",3",4)]
298
+ end
299
+
300
+ it 'receives an array containing empty strings' do
301
+ expect(coder.encode( record.new(['1', '', '3', '']) )).to eql %[(1,"",3,"")]
302
+ end
303
+
304
+ it 'receives an array containing unicode strings' do
305
+ expect(coder.encode( record.new(['Paragraph 399(b)(i) – “valid leave” – meaning']) )).to eql %[("Paragraph 399(b)(i) – “valid leave” – meaning")]
306
+ end
307
+ end
308
+
309
+ context 'array of records' do
310
+ it 'receives an empty array' do
311
+ expect(coder.encode([record.new])).to eql %[{()}]
312
+ expect(coder.encode([record.new,record.new])).to eql %[{(),()}]
313
+ end
314
+
315
+ it 'receives an array of strings with a sub array' do
316
+ expect(coder.encode(['1',record.new(['2','3']),'4'])).to eql %[{1,(2,3),4}]
317
+ end
318
+
319
+ it 'receives an array of strings with a sub array' do
320
+ expect(coder.encode(['1',record.new(['2,3']),'4'])).to eql %[{1,("2,3"),4}]
321
+ end
322
+
323
+ it 'receives an array of strings with a sub array and a quoted }' do
324
+ expect(coder.encode(['1',record.new(['2,}3',nil,nil]),'4'])).to eql %[{1,("2,}3",,),4}]
325
+ end
326
+
327
+ it 'receives an array of strings with a sub array and a quoted {' do
328
+ expect(coder.encode(['1',record.new(['2,{3']),'4'])).to eql %[{1,("2,{3"),4}]
329
+ end
330
+
331
+ it 'receives an array of strings with a sub array and a quoted { and escaped quote' do
332
+ expect(coder.encode(['1',record.new(['2",{3']),'4'])).to eql %[{1,("2\\",{3"),4}]
333
+ end
334
+
335
+ it 'receives an array of strings with a sub array with empty strings' do
336
+ expect(coder.encode(['1',record.new(['']),'4',record.new([''])])).to eql %[{1,(""),4,("")}]
337
+ end
338
+ end
339
+
340
+ context 'mix of record and array' do
341
+ it 'receives an empty array' do
342
+ expect(coder.encode( record.new([[record.new,nil]]) )).to eql %[({(),NULL})]
343
+ expect(coder.encode( [record.new([[], []]),[record.new,[]]] )).to eql %[{({},{}),{(),{}}}]
344
+ end
345
+
346
+ it 'receives an array of strings with sub arrays' do
347
+ expect(coder.encode(['1',record.new(['2',['3','4']]),record.new([nil,nil,'6']),'7'])).to eql %[{1,(2,{3,4}),(,,6),7}]
348
+ end
349
+ end
350
+
351
+ context 'record complex sample' do
352
+ it 'may have double double quotes translate to single double quotes' do
353
+ expect(coder.encode( record.new(['Test with double " quoutes']) )).to eql %[("Test with double \\" quoutes")]
354
+ end
355
+
356
+ it 'double double quotes may occur any number of times' do
357
+ expect(coder.encode( record.new(['Only one "', 'Now " two ".', '","{"}', '""']) )).to eql %[("Only one \\"","Now \\" two \\".","\\",\\"{\\"}","\\"\\"")]
358
+ end
359
+
360
+ it 'may have any kind of value' do
361
+ expect(coder.encode( record.new(['String', '123456', 'false', 'true', '2016-01-01 12:00:00', ['1', '2', '3']]) )).to eql %[(String,123456,false,true,"2016-01-01 12:00:00",{1,2,3})]
362
+ end
363
+ end
364
+
365
+ end
366
+
367
+ end