rdo-postgres 0.0.1
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.
- data/.gitignore +20 -0
- data/.rspec +1 -0
- data/Gemfile +9 -0
- data/LICENSE +22 -0
- data/README.md +94 -0
- data/Rakefile +14 -0
- data/ext/rdo_postgres/casts.c +134 -0
- data/ext/rdo_postgres/casts.h +16 -0
- data/ext/rdo_postgres/driver.c +169 -0
- data/ext/rdo_postgres/driver.h +20 -0
- data/ext/rdo_postgres/extconf.rb +39 -0
- data/ext/rdo_postgres/macros.h +180 -0
- data/ext/rdo_postgres/params.c +106 -0
- data/ext/rdo_postgres/params.h +15 -0
- data/ext/rdo_postgres/rdo_postgres.c +18 -0
- data/ext/rdo_postgres/statements.c +237 -0
- data/ext/rdo_postgres/statements.h +15 -0
- data/ext/rdo_postgres/tuples.c +85 -0
- data/ext/rdo_postgres/tuples.h +20 -0
- data/lib/rdo-postgres.rb +1 -0
- data/lib/rdo/postgres.rb +16 -0
- data/lib/rdo/postgres/driver.rb +68 -0
- data/lib/rdo/postgres/version.rb +12 -0
- data/rdo-postgres.gemspec +23 -0
- data/spec/postgres/bind_params_spec.rb +902 -0
- data/spec/postgres/driver_spec.rb +285 -0
- data/spec/postgres/type_cast_spec.rb +272 -0
- data/spec/spec_helper.rb +10 -0
- metadata +126 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* RDO Postgres Driver.
|
3
|
+
* Copyright © 2012 Chris Corbyn.
|
4
|
+
*
|
5
|
+
* See LICENSE file for details.
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include <stdio.h>
|
9
|
+
#include <ruby.h>
|
10
|
+
|
11
|
+
/** Factory to create a new StatementExecutor */
|
12
|
+
VALUE rdo_postgres_statement_executor_new(VALUE driver, VALUE cmd, VALUE name);
|
13
|
+
|
14
|
+
/** Initializer for the statements framework */
|
15
|
+
void Init_rdo_postgres_statements(void);
|
@@ -0,0 +1,85 @@
|
|
1
|
+
/*
|
2
|
+
* RDO Postgres Driver.
|
3
|
+
* Copyright © 2012 Chris Corbyn.
|
4
|
+
*
|
5
|
+
* See LICENSE file for details.
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include "tuples.h"
|
9
|
+
#include "casts.h"
|
10
|
+
#include <stdlib.h>
|
11
|
+
|
12
|
+
/** Wrapper for the TupleList class */
|
13
|
+
typedef struct {
|
14
|
+
PGresult * res;
|
15
|
+
int encoding;
|
16
|
+
} RDOPostgresTupleList;
|
17
|
+
|
18
|
+
/** class RDO::Postgres::TupleList */
|
19
|
+
static VALUE rdo_postgres_cTupleList;
|
20
|
+
|
21
|
+
/** Used to free the struct wrapped by TupleList during GC */
|
22
|
+
static void rdo_postgres_tuple_list_free(RDOPostgresTupleList * list) {
|
23
|
+
PQclear(list->res);
|
24
|
+
free(list);
|
25
|
+
}
|
26
|
+
|
27
|
+
/** Factory to return a new instance of TupleList for a result */
|
28
|
+
VALUE rdo_postgres_tuple_list_new(PGresult * res, int encoding) {
|
29
|
+
RDOPostgresTupleList * list = malloc(sizeof(RDOPostgresTupleList));
|
30
|
+
list->res = res;
|
31
|
+
list->encoding = encoding;
|
32
|
+
|
33
|
+
VALUE obj = Data_Wrap_Struct(rdo_postgres_cTupleList, 0,
|
34
|
+
rdo_postgres_tuple_list_free, list);
|
35
|
+
|
36
|
+
rb_obj_call_init(obj, 0, NULL);
|
37
|
+
|
38
|
+
return obj;
|
39
|
+
}
|
40
|
+
|
41
|
+
/** Allow iteration over all tuples, yielding Hashes into a block */
|
42
|
+
static VALUE rdo_postgres_tuple_list_each(VALUE self) {
|
43
|
+
if (!rb_block_given_p()) {
|
44
|
+
return self;
|
45
|
+
}
|
46
|
+
|
47
|
+
RDOPostgresTupleList * list;
|
48
|
+
Data_Get_Struct(self, RDOPostgresTupleList, list);
|
49
|
+
|
50
|
+
int i = 0;
|
51
|
+
int ntups = PQntuples(list->res);
|
52
|
+
|
53
|
+
for (; i < ntups; ++i) {
|
54
|
+
VALUE hash = rb_hash_new();
|
55
|
+
int j = 0;
|
56
|
+
int nfields = PQnfields(list->res);
|
57
|
+
|
58
|
+
for (; j < nfields; ++j) {
|
59
|
+
rb_hash_aset(hash,
|
60
|
+
ID2SYM(rb_intern(PQfname(list->res, j))),
|
61
|
+
rdo_postgres_cast_value(list->res, i, j, list->encoding));
|
62
|
+
}
|
63
|
+
|
64
|
+
rb_yield(hash);
|
65
|
+
}
|
66
|
+
|
67
|
+
return self;
|
68
|
+
}
|
69
|
+
|
70
|
+
/**
|
71
|
+
* Invoked during driver initialization to set up the TupleList.
|
72
|
+
*/
|
73
|
+
void Init_rdo_postgres_tuples(void) {
|
74
|
+
VALUE mPostgres = rb_path2class("RDO::Postgres");
|
75
|
+
|
76
|
+
rdo_postgres_cTupleList = rb_define_class_under(mPostgres,
|
77
|
+
"TupleList", rb_cObject);
|
78
|
+
|
79
|
+
rb_define_method(rdo_postgres_cTupleList,
|
80
|
+
"each", rdo_postgres_tuple_list_each, 0);
|
81
|
+
|
82
|
+
rb_include_module(rdo_postgres_cTupleList, rb_mEnumerable);
|
83
|
+
|
84
|
+
Init_rdo_postgres_casts();
|
85
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
/*
|
2
|
+
* RDO Postgres Driver.
|
3
|
+
* Copyright © 2012 Chris Corbyn.
|
4
|
+
*
|
5
|
+
* See LICENSE file for details.
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include <stdio.h>
|
9
|
+
#include <ruby.h>
|
10
|
+
#include <libpq-fe.h>
|
11
|
+
|
12
|
+
/**
|
13
|
+
* Create a new RDO::Postgres::TupleList.
|
14
|
+
*/
|
15
|
+
VALUE rdo_postgres_tuple_list_new(PGresult * res, int encoding);
|
16
|
+
|
17
|
+
/**
|
18
|
+
* Called during driver initialization to define needed tuple classes.
|
19
|
+
*/
|
20
|
+
void Init_rdo_postgres_tuples(void);
|
data/lib/rdo-postgres.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "rdo/postgres"
|
data/lib/rdo/postgres.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
##
|
2
|
+
# RDO PostgreSQL driver.
|
3
|
+
# Copyright © 2012 Chris Corbyn.
|
4
|
+
#
|
5
|
+
# See LICENSE file for details.
|
6
|
+
##
|
7
|
+
|
8
|
+
require "rdo"
|
9
|
+
require "rdo/postgres/version"
|
10
|
+
require "rdo/postgres/driver"
|
11
|
+
require "rdo/rdo_postgres" # c ext
|
12
|
+
|
13
|
+
# Register name variants for postgresql schemes
|
14
|
+
%w[postgres postgresql].each do |name|
|
15
|
+
RDO::Connection.register_driver(name, RDO::Postgres::Driver)
|
16
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
##
|
2
|
+
# RDO PostgreSQL driver.
|
3
|
+
# Copyright © 2012 Chris Corbyn.
|
4
|
+
#
|
5
|
+
# See LICENSE file for details.
|
6
|
+
##
|
7
|
+
|
8
|
+
module RDO
|
9
|
+
module Postgres
|
10
|
+
# Driver for the Postgres server.
|
11
|
+
#
|
12
|
+
# All default behaviour is overloaded.
|
13
|
+
class Driver < RDO::Driver
|
14
|
+
# most implementation defined by C extension
|
15
|
+
|
16
|
+
# Internally this driver uses prepared statements.
|
17
|
+
#
|
18
|
+
# @param [String] stmt
|
19
|
+
# the statement to execute
|
20
|
+
#
|
21
|
+
# @param [Object...] *args
|
22
|
+
# bind parameters to execute with
|
23
|
+
#
|
24
|
+
# @return [RDO::Result]
|
25
|
+
# a result containing any tuples and query info
|
26
|
+
def execute(stmt, *args)
|
27
|
+
prepare(stmt).execute(*args)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# Passed to PQconnectdb().
|
33
|
+
#
|
34
|
+
# e.g. "host=localhost user=bob password=secret dbname=bobs_db"
|
35
|
+
def connect_db_string
|
36
|
+
{
|
37
|
+
host: options[:host],
|
38
|
+
port: options[:port],
|
39
|
+
dbname: options[:database],
|
40
|
+
user: options[:user],
|
41
|
+
password: options[:password],
|
42
|
+
connect_timeout: options[:connect_timeout]
|
43
|
+
}.reject{|k,v| v.nil?}.map{|pair| pair.join("=")}.join(" ")
|
44
|
+
end
|
45
|
+
|
46
|
+
def after_open
|
47
|
+
set_time_zone
|
48
|
+
set_encoding
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_time_zone
|
52
|
+
if options[:time_zone]
|
53
|
+
execute("SET TIME ZONE '#{quote(options[:time_zone])}'")
|
54
|
+
else
|
55
|
+
execute("SET TIME ZONE interval '#{quote(RDO::Util.system_time_zone)}' hour to minute")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def set_encoding
|
60
|
+
execute("SET NAMES '#{quote(encoding)}'")
|
61
|
+
end
|
62
|
+
|
63
|
+
def encoding
|
64
|
+
options.fetch(:encoding, "utf-8")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/rdo/postgres/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["d11wtq"]
|
6
|
+
gem.email = ["chris@w3style.co.uk"]
|
7
|
+
gem.description = "Provides access to PostgreSQL using the RDO interface"
|
8
|
+
gem.summary = "PostgreSQL Adapter for RDO"
|
9
|
+
gem.homepage = "https://github.com/d11wtq/rdo-postgres"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "rdo-postgres"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = RDO::Postgres::VERSION
|
17
|
+
gem.extensions = ["ext/rdo_postgres/extconf.rb"]
|
18
|
+
|
19
|
+
gem.add_runtime_dependency "rdo", ">= 0.0.1"
|
20
|
+
|
21
|
+
gem.add_development_dependency "rspec"
|
22
|
+
gem.add_development_dependency "rake-compiler"
|
23
|
+
end
|
@@ -0,0 +1,902 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "bigdecimal"
|
3
|
+
require "date"
|
4
|
+
|
5
|
+
describe RDO::Postgres::Driver, "bind parameter support" do
|
6
|
+
let(:connection) { RDO.connect(connection_uri) }
|
7
|
+
let(:table) { "" }
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
connection.execute("DROP SCHEMA IF EXISTS rdo_test CASCADE")
|
11
|
+
connection.execute("CREATE SCHEMA rdo_test")
|
12
|
+
connection.execute("SET search_path = rdo_test")
|
13
|
+
connection.execute(table)
|
14
|
+
end
|
15
|
+
|
16
|
+
after(:each) do
|
17
|
+
begin
|
18
|
+
connection.execute("DROP SCHEMA IF EXISTS rdo_test CASCADE")
|
19
|
+
rescue RDO::Exception => e
|
20
|
+
# accept that tests may fail for other reasons, don't also fail on cleanup
|
21
|
+
ensure
|
22
|
+
connection.close rescue nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "String param" do
|
27
|
+
context "against a text field" do
|
28
|
+
let(:table) { "CREATE TABLE test (id serial primary key, name text)" }
|
29
|
+
let(:tuple) do
|
30
|
+
connection.execute(
|
31
|
+
"INSERT INTO test (name) VALUES (?) RETURNING *",
|
32
|
+
"Fern Cotton"
|
33
|
+
).first
|
34
|
+
end
|
35
|
+
|
36
|
+
it "is inferred correctly" do
|
37
|
+
tuple.should == {id: 1, name: "Fern Cotton"}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "against an integer field" do
|
42
|
+
let(:table) { "CREATE TABLE test (id serial primary key, age integer)" }
|
43
|
+
let(:tuple) do
|
44
|
+
connection.execute("INSERT INTO test (age) VALUES (?) RETURNING *", "32").first
|
45
|
+
end
|
46
|
+
|
47
|
+
it "is inferred correctly" do
|
48
|
+
tuple.should == {id: 1, age: 32}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "against a boolean field" do
|
53
|
+
let(:table) { "CREATE TABLE test (id serial primary key, rad boolean)" }
|
54
|
+
let(:tuple) do
|
55
|
+
connection.execute("INSERT INTO test (rad) VALUES (?) RETURNING *", "true").first
|
56
|
+
end
|
57
|
+
|
58
|
+
it "is inferred correctly" do
|
59
|
+
tuple.should == {id: 1, rad: true}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "against a float field" do
|
64
|
+
let(:table) { "CREATE TABLE test (id serial primary key, score float)" }
|
65
|
+
let(:tuple) do
|
66
|
+
connection.execute("INSERT INTO test (score) VALUES (?) RETURNING *", "85.4").first
|
67
|
+
end
|
68
|
+
|
69
|
+
it "is inferred correctly" do
|
70
|
+
tuple.should == {id: 1, score: 85.4}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "against a decimal field" do
|
75
|
+
let(:table) { "CREATE TABLE test (id serial primary key, score decimal)" }
|
76
|
+
let(:tuple) do
|
77
|
+
connection.execute("INSERT INTO test (score) VALUES (?) RETURNING *", "85.4").first
|
78
|
+
end
|
79
|
+
|
80
|
+
it "is inferred correctly" do
|
81
|
+
tuple.should == {id: 1, score: BigDecimal("85.4")}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "against a date field" do
|
86
|
+
let(:table) { "CREATE TABLE test (id serial primary key, dob date)" }
|
87
|
+
let(:tuple) do
|
88
|
+
connection.execute("INSERT INTO test (dob) VALUES (?) RETURNING *", "1983-05-03").first
|
89
|
+
end
|
90
|
+
|
91
|
+
it "is inferred correctly" do
|
92
|
+
tuple.should == {id: 1, dob: Date.new(1983, 5, 3)}
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "against a timestamp field" do
|
97
|
+
let(:table) { "CREATE TABLE test (id serial primary key, created_at timestamp)" }
|
98
|
+
let(:tuple) do
|
99
|
+
connection.execute(
|
100
|
+
"INSERT INTO test (created_at) VALUES (?) RETURNING *",
|
101
|
+
"2012-09-22 10:00:05"
|
102
|
+
).first
|
103
|
+
end
|
104
|
+
|
105
|
+
it "is inferred correctly" do
|
106
|
+
tuple.should == {id: 1, created_at: DateTime.new(2012, 9, 22, 10, 0, 5, DateTime.now.zone)}
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "against a timestamptz field" do
|
111
|
+
let(:table) { "CREATE TABLE test (id serial primary key, created_at timestamptz)" }
|
112
|
+
let(:tuple) do
|
113
|
+
connection.execute(
|
114
|
+
"INSERT INTO test (created_at) VALUES (?) RETURNING *",
|
115
|
+
"2012-09-22 10:00:05 -5"
|
116
|
+
).first
|
117
|
+
end
|
118
|
+
|
119
|
+
it "is inferred correctly" do
|
120
|
+
tuple.should == {id: 1, created_at: DateTime.new(2012, 9, 22, 10, 0, 5, "-5")}
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "against a bytea field" do
|
125
|
+
let(:table) { "CREATE TABLE test (id serial primary key, salt bytea)" }
|
126
|
+
let(:tuple) do
|
127
|
+
connection.execute(
|
128
|
+
"INSERT INTO test (salt) VALUES (?) RETURNING *", "\x00\x01\x02"
|
129
|
+
).first
|
130
|
+
end
|
131
|
+
|
132
|
+
it "is inferred correctly" do
|
133
|
+
tuple.should == {id: 1, salt: "\x00\x01\x02"}
|
134
|
+
end
|
135
|
+
|
136
|
+
context "that is empty" do
|
137
|
+
let(:table) { "CREATE TABLE test (id serial primary key, salt bytea)" }
|
138
|
+
let(:tuple) do
|
139
|
+
connection.execute(
|
140
|
+
"INSERT INTO test (salt) VALUES (?) RETURNING *", ""
|
141
|
+
).first
|
142
|
+
end
|
143
|
+
|
144
|
+
it "is inferred correctly" do
|
145
|
+
tuple.should == {id: 1, salt: ""}
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "Fixnum param" do
|
152
|
+
context "against an integer field" do
|
153
|
+
let(:table) { "CREATE TABLE test (id serial primary key, age integer)" }
|
154
|
+
let(:tuple) do
|
155
|
+
connection.execute(
|
156
|
+
"INSERT INTO test (age) VALUES (?) RETURNING *",
|
157
|
+
42
|
158
|
+
).first
|
159
|
+
end
|
160
|
+
|
161
|
+
it "is inferred correctly" do
|
162
|
+
tuple.should == {id: 1, age: 42}
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "against a text field" do
|
167
|
+
let(:table) { "CREATE TABLE test (id serial primary key, name text)" }
|
168
|
+
let(:tuple) do
|
169
|
+
connection.execute(
|
170
|
+
"INSERT INTO test (name) VALUES (?) RETURNING *",
|
171
|
+
42
|
172
|
+
).first
|
173
|
+
end
|
174
|
+
|
175
|
+
it "is inferred correctly" do
|
176
|
+
tuple.should == {id: 1, name: "42"}
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context "against a float field" do
|
181
|
+
let(:table) { "CREATE TABLE test (id serial primary key, score float)" }
|
182
|
+
let(:tuple) do
|
183
|
+
connection.execute(
|
184
|
+
"INSERT INTO test (score) VALUES (?) RETURNING *",
|
185
|
+
42
|
186
|
+
).first
|
187
|
+
end
|
188
|
+
|
189
|
+
it "is inferred correctly" do
|
190
|
+
tuple.should == {id: 1, score: 42.0}
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context "agsinst a decimal field" do
|
195
|
+
let(:table) { "CREATE TABLE test (id serial primary key, score decimal)" }
|
196
|
+
let(:tuple) do
|
197
|
+
connection.execute(
|
198
|
+
"INSERT INTO test (score) VALUES (?) RETURNING *",
|
199
|
+
42
|
200
|
+
).first
|
201
|
+
end
|
202
|
+
|
203
|
+
it "is inferred correctly" do
|
204
|
+
tuple.should == {id: 1, score: BigDecimal("42")}
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context "against a boolean field" do
|
209
|
+
let(:table) { "CREATE TABLE test (id serial primary key, rad boolean)" }
|
210
|
+
|
211
|
+
context "when it is 0" do
|
212
|
+
let(:tuple) do
|
213
|
+
connection.execute(
|
214
|
+
"INSERT INTO test (rad) VALUES (?) RETURNING *",
|
215
|
+
0
|
216
|
+
).first
|
217
|
+
end
|
218
|
+
|
219
|
+
it "is inferred correctly (false)" do
|
220
|
+
tuple.should == {id: 1, rad: false}
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
context "when it is 1" do
|
225
|
+
let(:tuple) do
|
226
|
+
connection.execute(
|
227
|
+
"INSERT INTO test (rad) VALUES (?) RETURNING *",
|
228
|
+
1
|
229
|
+
).first
|
230
|
+
end
|
231
|
+
|
232
|
+
it "is inferred correctly (true)" do
|
233
|
+
tuple.should == {id: 1, rad: true}
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
context "against a bytea field" do
|
239
|
+
let(:table) { "CREATE TABLE test (id serial primary key, salt bytea)" }
|
240
|
+
let(:tuple) do
|
241
|
+
connection.execute(
|
242
|
+
"INSERT INTO test (salt) VALUES (?) RETURNING *",
|
243
|
+
42
|
244
|
+
).first
|
245
|
+
end
|
246
|
+
|
247
|
+
it "is inferred correctly" do
|
248
|
+
tuple.should == {id: 1, salt: "42"}
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
describe "Float param" do
|
254
|
+
context "against a float field" do
|
255
|
+
let(:table) { "CREATE TABLE test (id serial primary key, score float)" }
|
256
|
+
|
257
|
+
context "when it is NaN" do
|
258
|
+
let(:tuple) do
|
259
|
+
connection.execute(
|
260
|
+
"INSERT INTO test (score) VALUES (?) RETURNING *",
|
261
|
+
Float::NAN
|
262
|
+
).first
|
263
|
+
end
|
264
|
+
|
265
|
+
it "is inferred correctly" do
|
266
|
+
tuple.should == {id: 1, score: Float::NAN}
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
context "when it is Infinity" do
|
271
|
+
let(:tuple) do
|
272
|
+
connection.execute(
|
273
|
+
"INSERT INTO test (score) VALUES (?) RETURNING *",
|
274
|
+
Float::INFINITY
|
275
|
+
).first
|
276
|
+
end
|
277
|
+
|
278
|
+
it "is inferred correctly" do
|
279
|
+
tuple.should == {id: 1, score: Float::INFINITY}
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
context "when it is -Infinity" do
|
284
|
+
let(:tuple) do
|
285
|
+
connection.execute(
|
286
|
+
"INSERT INTO test (score) VALUES (?) RETURNING *",
|
287
|
+
-Float::INFINITY
|
288
|
+
).first
|
289
|
+
end
|
290
|
+
|
291
|
+
it "is inferred correctly" do
|
292
|
+
tuple.should == {id: 1, score: -Float::INFINITY}
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
context "when it is a real number" do
|
297
|
+
let(:tuple) do
|
298
|
+
connection.execute(
|
299
|
+
"INSERT INTO test (score) VALUES (?) RETURNING *",
|
300
|
+
12.5
|
301
|
+
).first
|
302
|
+
end
|
303
|
+
|
304
|
+
it "is inferred correctly" do
|
305
|
+
tuple.should == {id: 1, score: 12.5}
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
context "against a text field" do
|
311
|
+
let(:table) { "CREATE TABLE test (id serial primary key, name text)" }
|
312
|
+
let(:tuple) do
|
313
|
+
connection.execute(
|
314
|
+
"INSERT INTO test (name) VALUES (?) RETURNING *",
|
315
|
+
12.5
|
316
|
+
).first
|
317
|
+
end
|
318
|
+
|
319
|
+
it "is inferred correctly" do
|
320
|
+
tuple.should == {id: 1, name: "12.5"}
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
context "against a decimal field" do
|
325
|
+
let(:table) { "CREATE TABLE test (id serial primary key, score decimal)" }
|
326
|
+
let(:tuple) do
|
327
|
+
connection.execute(
|
328
|
+
"INSERT INTO test (score) VALUES (?) RETURNING *",
|
329
|
+
12.2
|
330
|
+
).first
|
331
|
+
end
|
332
|
+
|
333
|
+
it "is inferred correctly" do
|
334
|
+
tuple.should == {id: 1, score: BigDecimal("12.2")}
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
describe "BigDecimal param" do
|
340
|
+
context "against a decimal field" do
|
341
|
+
let(:table) { "CREATE TABLE test (id serial primary key, score decimal)" }
|
342
|
+
|
343
|
+
context "when it is NaN" do
|
344
|
+
let(:tuple) do
|
345
|
+
connection.execute(
|
346
|
+
"INSERT INTO test (score) VALUES (?) RETURNING *",
|
347
|
+
BigDecimal("NaN")
|
348
|
+
).first
|
349
|
+
end
|
350
|
+
|
351
|
+
it "is inferred correctly" do
|
352
|
+
tuple[:score].should be_a_kind_of(BigDecimal)
|
353
|
+
tuple[:score].should be_nan
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
context "when it is a real number" do
|
358
|
+
let(:tuple) do
|
359
|
+
connection.execute(
|
360
|
+
"INSERT INTO test (score) VALUES (?) RETURNING *",
|
361
|
+
BigDecimal("12.2")
|
362
|
+
).first
|
363
|
+
end
|
364
|
+
|
365
|
+
it "is inferred correctly" do
|
366
|
+
tuple.should == {id: 1, score: BigDecimal("12.2")}
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
context "against a text field" do
|
372
|
+
let(:table) { "CREATE TABLE test (id serial primary key, name text)" }
|
373
|
+
let(:tuple) do
|
374
|
+
connection.execute(
|
375
|
+
"INSERT INTO test (name) VALUES (?) RETURNING *",
|
376
|
+
BigDecimal("12.7")
|
377
|
+
).first
|
378
|
+
end
|
379
|
+
|
380
|
+
it "is inferred correctly" do
|
381
|
+
tuple.should == {id: 1, name: BigDecimal("12.7").to_s}
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
context "against a float field" do
|
386
|
+
let(:table) { "CREATE TABLE test (id serial primary key, score float)" }
|
387
|
+
let(:tuple) do
|
388
|
+
connection.execute(
|
389
|
+
"INSERT INTO test (score) VALUES (?) RETURNING *",
|
390
|
+
BigDecimal("12.7")
|
391
|
+
).first
|
392
|
+
end
|
393
|
+
|
394
|
+
it "is inferred correctly" do
|
395
|
+
tuple.should == {id: 1, score: 12.7}
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
describe "Date param" do
|
401
|
+
context "against a Date field" do
|
402
|
+
let(:table) { "CREATE TABLE test (id serial primary key, dob date)" }
|
403
|
+
let(:tuple) do
|
404
|
+
connection.execute(
|
405
|
+
"INSERT INTO test (dob) VALUES (?) RETURNING *",
|
406
|
+
Date.new(1983, 5, 3)
|
407
|
+
).first
|
408
|
+
end
|
409
|
+
|
410
|
+
it "is inferred correctly" do
|
411
|
+
tuple.should == {id: 1, dob: Date.new(1983, 5, 3)}
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
context "against a text field" do
|
416
|
+
let(:table) { "CREATE TABLE test (id serial primary key, name text)" }
|
417
|
+
let(:tuple) do
|
418
|
+
connection.execute(
|
419
|
+
"INSERT INTO test (name) VALUES (?) RETURNING *",
|
420
|
+
Date.new(1983, 5, 3)
|
421
|
+
).first
|
422
|
+
end
|
423
|
+
|
424
|
+
it "is inferred correctly" do
|
425
|
+
tuple.should == {id: 1, name: "1983-05-03"}
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
context "against a timestamp field" do
|
430
|
+
let(:table) { "CREATE TABLE test (id serial primary key, created_at timestamp)" }
|
431
|
+
let(:tuple) do
|
432
|
+
connection.execute(
|
433
|
+
"INSERT INTO test (created_at) VALUES (?) RETURNING *",
|
434
|
+
Date.new(1983, 5, 3)
|
435
|
+
).first
|
436
|
+
end
|
437
|
+
|
438
|
+
it "is inferred correctly" do
|
439
|
+
tuple.should == {id: 1, created_at: DateTime.new(1983, 5, 3, 0, 0, 0, DateTime.now.zone)}
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
context "against a timestamptz field" do
|
444
|
+
let(:table) { "CREATE TABLE test (id serial primary key, created_at timestamptz)" }
|
445
|
+
let(:tuple) do
|
446
|
+
connection.execute(
|
447
|
+
"INSERT INTO test (created_at) VALUES (?) RETURNING *",
|
448
|
+
Date.new(1983, 5, 3)
|
449
|
+
).first
|
450
|
+
end
|
451
|
+
|
452
|
+
it "is inferred correctly" do
|
453
|
+
tuple.should == {id: 1, created_at: DateTime.new(1983, 5, 3, 0, 0, 0, DateTime.now.zone)}
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
describe "Time param" do
|
459
|
+
context "against a timestamp field" do
|
460
|
+
let(:table) { "CREATE TABLE test (id serial primary key, created_at timestamp)" }
|
461
|
+
let(:tuple) do
|
462
|
+
connection.execute(
|
463
|
+
"INSERT INTO test (created_at) VALUES (?) RETURNING *",
|
464
|
+
Time.new(2012, 9, 22, 5, 16, 58)
|
465
|
+
).first
|
466
|
+
end
|
467
|
+
|
468
|
+
it "is inferred correctly" do
|
469
|
+
tuple.should == {id: 1, created_at: DateTime.new(2012, 9, 22, 5, 16, 58, DateTime.now.zone)}
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
context "against a timestamptz field" do
|
474
|
+
let(:table) { "CREATE TABLE test (id serial primary key, created_at timestamptz)" }
|
475
|
+
|
476
|
+
context "without a timezone given" do
|
477
|
+
let(:tuple) do
|
478
|
+
connection.execute(
|
479
|
+
"INSERT INTO test (created_at) VALUES (?) RETURNING *",
|
480
|
+
Time.new(2012, 9, 22, 5, 16, 58)
|
481
|
+
).first
|
482
|
+
end
|
483
|
+
|
484
|
+
it "is inferred correctly" do
|
485
|
+
tuple.should == {id: 1, created_at: DateTime.new(2012, 9, 22, 5, 16, 58, DateTime.now.zone)}
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
context "with a timezone given" do
|
490
|
+
let(:tuple) do
|
491
|
+
connection.execute(
|
492
|
+
"INSERT INTO test (created_at) VALUES (?) RETURNING *",
|
493
|
+
Time.new(2012, 9, 22, 5, 16, 58, "-07:00")
|
494
|
+
).first
|
495
|
+
end
|
496
|
+
|
497
|
+
it "is inferred correctly" do
|
498
|
+
tuple.should == {id: 1, created_at: DateTime.new(2012, 9, 22, 5, 16, 58, "-07:00")}
|
499
|
+
end
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
context "against a date field" do
|
504
|
+
let(:table) { "CREATE TABLE test (id serial primary key, dob date)" }
|
505
|
+
let(:tuple) do
|
506
|
+
connection.execute(
|
507
|
+
"INSERT INTO test (dob) VALUES (?) RETURNING *",
|
508
|
+
Time.new(1983, 5, 3, 6, 13, 0)
|
509
|
+
).first
|
510
|
+
end
|
511
|
+
|
512
|
+
it "is inferred correctly" do
|
513
|
+
tuple.should == {id: 1, dob: Date.new(1983, 5, 3)}
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
context "against a text field" do
|
518
|
+
let(:table) { "CREATE TABLE test (id serial primary key, name text)" }
|
519
|
+
let(:tuple) do
|
520
|
+
connection.execute(
|
521
|
+
"INSERT INTO test (name) VALUES (?) RETURNING *",
|
522
|
+
Time.new(2012, 9, 22, 5, 16, 58)
|
523
|
+
).first
|
524
|
+
end
|
525
|
+
|
526
|
+
it "is inferred correctly" do
|
527
|
+
tuple.should == {id: 1, name: Time.new(2012, 9, 22, 5, 16, 58).to_s}
|
528
|
+
end
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
describe "DateTime param" do
|
533
|
+
context "against a timestamp field" do
|
534
|
+
let(:table) { "CREATE TABLE test (id serial primary key, created_at timestamp)" }
|
535
|
+
let(:tuple) do
|
536
|
+
connection.execute(
|
537
|
+
"INSERT INTO test (created_at) VALUES (?) RETURNING *",
|
538
|
+
DateTime.new(1983, 5, 3, 6, 13, 0)
|
539
|
+
).first
|
540
|
+
end
|
541
|
+
|
542
|
+
it "is inferred correctly" do
|
543
|
+
tuple.should == {id: 1, created_at: DateTime.new(1983, 5, 3, 6, 13, 0, DateTime.now.zone)}
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
context "against a timestamptz field" do
|
548
|
+
let(:table) { "CREATE TABLE test (id serial primary key, created_at timestamptz)" }
|
549
|
+
|
550
|
+
context "with a time zone given" do
|
551
|
+
let(:tuple) do
|
552
|
+
connection.execute(
|
553
|
+
"INSERT INTO test (created_at) VALUES (?) RETURNING *",
|
554
|
+
DateTime.new(1983, 5, 3, 6, 13, 0, "-07:00")
|
555
|
+
).first
|
556
|
+
end
|
557
|
+
|
558
|
+
it "is inferred correctly" do
|
559
|
+
tuple.should == {id: 1, created_at: DateTime.new(1983, 5, 3, 6, 13, 0, "-07:00")}
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
context "without a time zone given" do
|
564
|
+
let(:tuple) do
|
565
|
+
connection.execute(
|
566
|
+
"INSERT INTO test (created_at) VALUES (?) RETURNING *",
|
567
|
+
DateTime.new(1983, 5, 3, 6, 13, 0)
|
568
|
+
).first
|
569
|
+
end
|
570
|
+
|
571
|
+
it "is inferred correctly" do
|
572
|
+
tuple.should == {id: 1, created_at: DateTime.new(1983, 5, 3, 6, 13, 0)}
|
573
|
+
end
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
context "against a date field" do
|
578
|
+
let(:table) { "CREATE TABLE test (id serial primary key, dob date)" }
|
579
|
+
let(:tuple) do
|
580
|
+
connection.execute(
|
581
|
+
"INSERT INTO test (dob) VALUES (?) RETURNING *",
|
582
|
+
DateTime.new(1983, 5, 3, 6, 13, 0)
|
583
|
+
).first
|
584
|
+
end
|
585
|
+
|
586
|
+
it "is inferred correctly" do
|
587
|
+
tuple.should == {id: 1, dob: Date.new(1983, 5, 3)}
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
context "against a text field" do
|
592
|
+
let(:table) { "CREATE TABLE test (id serial primary key, name text)" }
|
593
|
+
let(:tuple) do
|
594
|
+
connection.execute(
|
595
|
+
"INSERT INTO test (name) VALUES (?) RETURNING *",
|
596
|
+
DateTime.new(1983, 5, 3, 6, 13, 0)
|
597
|
+
).first
|
598
|
+
end
|
599
|
+
|
600
|
+
it "is inferred correctly" do
|
601
|
+
tuple.should == {id: 1, name: DateTime.new(1983, 5, 3, 6, 13, 0).to_s}
|
602
|
+
end
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
606
|
+
describe "nil param" do
|
607
|
+
context "against a text field" do
|
608
|
+
let(:table) { "CREATE TABLE test (id serial primary key, name text)" }
|
609
|
+
let(:tuple) do
|
610
|
+
connection.execute("INSERT INTO test (name) VALUES (?) RETURNING *", nil).first
|
611
|
+
end
|
612
|
+
|
613
|
+
it "is inferred correctly" do
|
614
|
+
tuple.should == {id: 1, name: nil}
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
618
|
+
context "against an integer field" do
|
619
|
+
let(:table) { "CREATE TABLE test (id serial primary key, age integer)" }
|
620
|
+
let(:tuple) do
|
621
|
+
connection.execute("INSERT INTO test (age) VALUES (?) RETURNING *", nil).first
|
622
|
+
end
|
623
|
+
|
624
|
+
it "is inferred correctly" do
|
625
|
+
tuple.should == {id: 1, age: nil}
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
context "against a float field" do
|
630
|
+
let(:table) { "CREATE TABLE test (id serial primary key, score float)" }
|
631
|
+
let(:tuple) do
|
632
|
+
connection.execute("INSERT INTO test (score) VALUES (?) RETURNING *", nil).first
|
633
|
+
end
|
634
|
+
|
635
|
+
it "is inferred correctly" do
|
636
|
+
tuple.should == {id: 1, score: nil}
|
637
|
+
end
|
638
|
+
end
|
639
|
+
|
640
|
+
context "against a decimal field" do
|
641
|
+
let(:table) { "CREATE TABLE test (id serial primary key, score decimal)" }
|
642
|
+
let(:tuple) do
|
643
|
+
connection.execute("INSERT INTO test (score) VALUES (?) RETURNING *", nil).first
|
644
|
+
end
|
645
|
+
|
646
|
+
it "is inferred correctly" do
|
647
|
+
tuple.should == {id: 1, score: nil}
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
context "against a boolean field" do
|
652
|
+
let(:table) { "CREATE TABLE test (id serial primary key, rad boolean)" }
|
653
|
+
let(:tuple) do
|
654
|
+
connection.execute("INSERT INTO test (rad) VALUES (?) RETURNING *", nil).first
|
655
|
+
end
|
656
|
+
|
657
|
+
it "is inferred correctly" do
|
658
|
+
tuple.should == {id: 1, rad: nil}
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
context "against a date field" do
|
663
|
+
let(:table) { "CREATE TABLE test (id serial primary key, dob date)" }
|
664
|
+
let(:tuple) do
|
665
|
+
connection.execute("INSERT INTO test (dob) VALUES (?) RETURNING *", nil).first
|
666
|
+
end
|
667
|
+
|
668
|
+
it "is inferred correctly" do
|
669
|
+
tuple.should == {id: 1, dob: nil}
|
670
|
+
end
|
671
|
+
end
|
672
|
+
|
673
|
+
context "against a timestamp field" do
|
674
|
+
let(:table) { "CREATE TABLE test (id serial primary key, created_at timestamp)" }
|
675
|
+
let(:tuple) do
|
676
|
+
connection.execute("INSERT INTO test (created_at) VALUES (?) RETURNING *", nil).first
|
677
|
+
end
|
678
|
+
|
679
|
+
it "is inferred correctly" do
|
680
|
+
tuple.should == {id: 1, created_at: nil}
|
681
|
+
end
|
682
|
+
end
|
683
|
+
|
684
|
+
context "against a timestamptz field" do
|
685
|
+
let(:table) { "CREATE TABLE test (id serial primary key, created_at timestamptz)" }
|
686
|
+
let(:tuple) do
|
687
|
+
connection.execute("INSERT INTO test (created_at) VALUES (?) RETURNING *", nil).first
|
688
|
+
end
|
689
|
+
|
690
|
+
it "is inferred correctly" do
|
691
|
+
tuple.should == {id: 1, created_at: nil}
|
692
|
+
end
|
693
|
+
end
|
694
|
+
|
695
|
+
context "against a bytea field" do
|
696
|
+
let(:table) { "CREATE TABLE test (id serial primary key, salt bytea)" }
|
697
|
+
let(:tuple) do
|
698
|
+
connection.execute("INSERT INTO test (salt) VALUES (?) RETURNING *", nil).first
|
699
|
+
end
|
700
|
+
|
701
|
+
it "is inferred correctly" do
|
702
|
+
tuple.should == {id: 1, salt: nil}
|
703
|
+
end
|
704
|
+
end
|
705
|
+
end
|
706
|
+
|
707
|
+
describe "arbitrary Object param" do
|
708
|
+
context "against a text field" do
|
709
|
+
let(:value) { Object.new }
|
710
|
+
let(:table) { "CREATE TABLE test (id serial primary key, name text)" }
|
711
|
+
let(:tuple) do
|
712
|
+
connection.execute("INSERT INTO test (name) VALUES (?) RETURNING *", value).first
|
713
|
+
end
|
714
|
+
|
715
|
+
it "is inferred correctly (via #to_s)" do
|
716
|
+
tuple.should == {id: 1, name: value.to_s}
|
717
|
+
end
|
718
|
+
end
|
719
|
+
end
|
720
|
+
|
721
|
+
describe "multiple params" do
|
722
|
+
let(:table) do
|
723
|
+
<<-SQL
|
724
|
+
CREATE TABLE test (
|
725
|
+
id serial primary key,
|
726
|
+
name text,
|
727
|
+
age integer,
|
728
|
+
admin boolean,
|
729
|
+
created_at timestamptz
|
730
|
+
)
|
731
|
+
SQL
|
732
|
+
end
|
733
|
+
|
734
|
+
let(:tuple) do
|
735
|
+
connection.execute(<<-SQL, "bob", 17, false, Time.new(2012, 9, 22, 6, 34)).first
|
736
|
+
INSERT INTO test (
|
737
|
+
name, age, admin, created_at
|
738
|
+
) VALUES (
|
739
|
+
?, ?, ?, ?
|
740
|
+
) RETURNING *
|
741
|
+
SQL
|
742
|
+
end
|
743
|
+
|
744
|
+
it "interprets them individually" do
|
745
|
+
tuple.should == {
|
746
|
+
id: 1,
|
747
|
+
name: "bob",
|
748
|
+
age: 17,
|
749
|
+
admin: false,
|
750
|
+
created_at: DateTime.new(2012, 9, 22, 6, 34, 0, DateTime.now.zone)
|
751
|
+
}
|
752
|
+
end
|
753
|
+
end
|
754
|
+
|
755
|
+
describe "when a bind marker is contained in a string literal" do
|
756
|
+
let(:table) do
|
757
|
+
<<-SQL
|
758
|
+
CREATE TABLE test (
|
759
|
+
id serial primary key,
|
760
|
+
name text,
|
761
|
+
age integer
|
762
|
+
)
|
763
|
+
SQL
|
764
|
+
end
|
765
|
+
|
766
|
+
context "without quoted apostrophes" do
|
767
|
+
let(:tuple) do
|
768
|
+
connection.execute(<<-SQL, 17).first
|
769
|
+
INSERT INTO test (
|
770
|
+
name, age
|
771
|
+
) VALUES (
|
772
|
+
'?', ?
|
773
|
+
) RETURNING *
|
774
|
+
SQL
|
775
|
+
end
|
776
|
+
|
777
|
+
it "does not consider the quoted marker" do
|
778
|
+
tuple.should == {id: 1, name: "?", age: 17}
|
779
|
+
end
|
780
|
+
end
|
781
|
+
|
782
|
+
context "with quoted apostrophes" do
|
783
|
+
let(:tuple) do
|
784
|
+
connection.execute(<<-SQL, 17).first
|
785
|
+
INSERT INTO test (
|
786
|
+
name, age
|
787
|
+
) VALUES (
|
788
|
+
'you say ''hello?''', ?
|
789
|
+
) RETURNING *
|
790
|
+
SQL
|
791
|
+
end
|
792
|
+
|
793
|
+
it "does not consider the quoted marker" do
|
794
|
+
tuple.should == {id: 1, name: "you say 'hello?'", age: 17}
|
795
|
+
end
|
796
|
+
end
|
797
|
+
end
|
798
|
+
|
799
|
+
describe "when a bind marker is contained in a multi-line comment" do
|
800
|
+
let(:table) do
|
801
|
+
<<-SQL
|
802
|
+
CREATE TABLE test (
|
803
|
+
id serial primary key,
|
804
|
+
name text,
|
805
|
+
age integer
|
806
|
+
)
|
807
|
+
SQL
|
808
|
+
end
|
809
|
+
|
810
|
+
context "without nesting" do
|
811
|
+
let(:tuple) do
|
812
|
+
connection.execute(<<-SQL, "jim", 17).first
|
813
|
+
INSERT INTO test (
|
814
|
+
name, age
|
815
|
+
) VALUES (
|
816
|
+
/*
|
817
|
+
Are these are the values you're looking for?
|
818
|
+
*/
|
819
|
+
?, ?
|
820
|
+
) RETURNING *
|
821
|
+
SQL
|
822
|
+
end
|
823
|
+
|
824
|
+
it "does not consider the commented marker" do
|
825
|
+
tuple.should == {id: 1, name: "jim", age: 17}
|
826
|
+
end
|
827
|
+
end
|
828
|
+
|
829
|
+
context "with nesting" do
|
830
|
+
let(:tuple) do
|
831
|
+
connection.execute(<<-SQL, "jim", 17).first
|
832
|
+
INSERT INTO test (
|
833
|
+
name, age
|
834
|
+
) VALUES (
|
835
|
+
/*
|
836
|
+
Are these the /* nested */ values you're looking for?
|
837
|
+
*/
|
838
|
+
?, ?
|
839
|
+
) RETURNING *
|
840
|
+
SQL
|
841
|
+
end
|
842
|
+
|
843
|
+
it "does not consider the commented marker" do
|
844
|
+
tuple.should == {id: 1, name: "jim", age: 17}
|
845
|
+
end
|
846
|
+
end
|
847
|
+
end
|
848
|
+
|
849
|
+
context "when a bind marker is contained in a single line comment" do
|
850
|
+
let(:table) do
|
851
|
+
<<-SQL
|
852
|
+
CREATE TABLE test (
|
853
|
+
id serial primary key,
|
854
|
+
name text,
|
855
|
+
age integer
|
856
|
+
)
|
857
|
+
SQL
|
858
|
+
end
|
859
|
+
|
860
|
+
let(:tuple) do
|
861
|
+
connection.execute(<<-SQL, "jim", 17).first
|
862
|
+
INSERT INTO test (
|
863
|
+
name, age
|
864
|
+
) VALUES (
|
865
|
+
-- Are these are the values you're looking for? choker! /*
|
866
|
+
?, ?
|
867
|
+
) RETURNING *
|
868
|
+
SQL
|
869
|
+
end
|
870
|
+
|
871
|
+
it "does not consider the commented marker" do
|
872
|
+
tuple.should == {id: 1, name: "jim", age: 17}
|
873
|
+
end
|
874
|
+
end
|
875
|
+
|
876
|
+
context "when a bind parameter is quoted as an identifier" do
|
877
|
+
let(:table) do
|
878
|
+
<<-SQL
|
879
|
+
CREATE TABLE test (
|
880
|
+
id serial primary key,
|
881
|
+
name text,
|
882
|
+
age integer,
|
883
|
+
"admin?" boolean
|
884
|
+
)
|
885
|
+
SQL
|
886
|
+
end
|
887
|
+
|
888
|
+
let(:tuple) do
|
889
|
+
connection.execute(<<-SQL, "jim", 17, true).first
|
890
|
+
INSERT INTO test (
|
891
|
+
name, age, "admin?"
|
892
|
+
) VALUES (
|
893
|
+
?, ?, ?
|
894
|
+
) RETURNING *
|
895
|
+
SQL
|
896
|
+
end
|
897
|
+
|
898
|
+
it "does not confuse the quoted identifier" do
|
899
|
+
tuple.should == {id: 1, name: "jim", age: 17, admin?: true}
|
900
|
+
end
|
901
|
+
end
|
902
|
+
end
|