add :cast_booleans option for automatically casting tinyint(1) fields into true/false for ruby
This commit is contained in:
parent
12c022c8aa
commit
2514fafa53
|
@ -9,7 +9,8 @@ VALUE cBigDecimal, cDate, cDateTime;
|
||||||
extern VALUE mMysql2, cMysql2Client, cMysql2Error;
|
extern VALUE mMysql2, cMysql2Client, cMysql2Error;
|
||||||
static VALUE intern_encoding_from_charset;
|
static VALUE intern_encoding_from_charset;
|
||||||
static ID intern_new, intern_utc, intern_local, intern_encoding_from_charset_code;
|
static ID intern_new, intern_utc, intern_local, intern_encoding_from_charset_code;
|
||||||
static ID sym_symbolize_keys, sym_as, sym_array, sym_timezone, sym_local, sym_utc;
|
static ID sym_symbolize_keys, sym_as, sym_array, sym_timezone, sym_local, sym_utc,
|
||||||
|
sym_cast_booleans;
|
||||||
static ID intern_merge;
|
static ID intern_merge;
|
||||||
|
|
||||||
static void rb_mysql_result_mark(void * wrapper) {
|
static void rb_mysql_result_mark(void * wrapper) {
|
||||||
|
@ -86,7 +87,7 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int
|
||||||
return rb_field;
|
return rb_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE rb_mysql_result_fetch_row(VALUE self, ID timezone, int symbolizeKeys, int asArray) {
|
static VALUE rb_mysql_result_fetch_row(VALUE self, ID timezone, int symbolizeKeys, int asArray, int castBool) {
|
||||||
VALUE rowVal;
|
VALUE rowVal;
|
||||||
mysql2_result_wrapper * wrapper;
|
mysql2_result_wrapper * wrapper;
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
|
@ -131,6 +132,10 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID timezone, int symbolizeKey
|
||||||
val = rb_str_new(row[i], fieldLengths[i]);
|
val = rb_str_new(row[i], fieldLengths[i]);
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_TINY: // TINYINT field
|
case MYSQL_TYPE_TINY: // TINYINT field
|
||||||
|
if (castBool && fields[i].length == 1) {
|
||||||
|
val = *row[i] == '1' ? Qtrue : Qfalse;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case MYSQL_TYPE_SHORT: // SMALLINT field
|
case MYSQL_TYPE_SHORT: // SMALLINT field
|
||||||
case MYSQL_TYPE_LONG: // INTEGER field
|
case MYSQL_TYPE_LONG: // INTEGER field
|
||||||
case MYSQL_TYPE_INT24: // MEDIUMINT field
|
case MYSQL_TYPE_INT24: // MEDIUMINT field
|
||||||
|
@ -266,7 +271,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
||||||
ID timezone;
|
ID timezone;
|
||||||
mysql2_result_wrapper * wrapper;
|
mysql2_result_wrapper * wrapper;
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
int symbolizeKeys = 0, asArray = 0;
|
int symbolizeKeys = 0, asArray = 0, castBool = 0;
|
||||||
|
|
||||||
GetMysql2Result(self, wrapper);
|
GetMysql2Result(self, wrapper);
|
||||||
|
|
||||||
|
@ -285,6 +290,10 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
||||||
asArray = 1;
|
asArray = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rb_hash_aref(opts, sym_cast_booleans) == Qtrue) {
|
||||||
|
castBool = 1;
|
||||||
|
}
|
||||||
|
|
||||||
timezoneVal = rb_hash_aref(opts, sym_timezone);
|
timezoneVal = rb_hash_aref(opts, sym_timezone);
|
||||||
if (timezoneVal == sym_local) {
|
if (timezoneVal == sym_local) {
|
||||||
timezone = intern_local;
|
timezone = intern_local;
|
||||||
|
@ -318,7 +327,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
||||||
if (i < rowsProcessed) {
|
if (i < rowsProcessed) {
|
||||||
row = rb_ary_entry(wrapper->rows, i);
|
row = rb_ary_entry(wrapper->rows, i);
|
||||||
} else {
|
} else {
|
||||||
row = rb_mysql_result_fetch_row(self, timezone, symbolizeKeys, asArray);
|
row = rb_mysql_result_fetch_row(self, timezone, symbolizeKeys, asArray, castBool);
|
||||||
rb_ary_store(wrapper->rows, i, row);
|
rb_ary_store(wrapper->rows, i, row);
|
||||||
wrapper->lastRowProcessed++;
|
wrapper->lastRowProcessed++;
|
||||||
}
|
}
|
||||||
|
@ -381,6 +390,7 @@ void init_mysql2_result() {
|
||||||
sym_timezone = ID2SYM(rb_intern("timezone"));
|
sym_timezone = ID2SYM(rb_intern("timezone"));
|
||||||
sym_local = ID2SYM(rb_intern("local"));
|
sym_local = ID2SYM(rb_intern("local"));
|
||||||
sym_utc = ID2SYM(rb_intern("utc"));
|
sym_utc = ID2SYM(rb_intern("utc"));
|
||||||
|
sym_cast_booleans = ID2SYM(rb_intern("cast_booleans"));
|
||||||
|
|
||||||
#ifdef HAVE_RUBY_ENCODING_H
|
#ifdef HAVE_RUBY_ENCODING_H
|
||||||
binaryEncoding = rb_enc_find("binary");
|
binaryEncoding = rb_enc_find("binary");
|
||||||
|
|
|
@ -5,7 +5,8 @@ module Mysql2
|
||||||
:symbolize_keys => false,
|
:symbolize_keys => false,
|
||||||
:async => false,
|
:async => false,
|
||||||
:as => :hash,
|
:as => :hash,
|
||||||
:timezone => :local
|
:timezone => :local,
|
||||||
|
:cast_booleans => false
|
||||||
}
|
}
|
||||||
|
|
||||||
def initialize(opts = {})
|
def initialize(opts = {})
|
||||||
|
|
|
@ -71,65 +71,9 @@ describe Mysql2::Result do
|
||||||
context "row data type mapping" do
|
context "row data type mapping" do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
@client.query "USE test"
|
@client.query "USE test"
|
||||||
@client.query %[
|
|
||||||
CREATE TABLE IF NOT EXISTS mysql2_test (
|
|
||||||
id MEDIUMINT NOT NULL AUTO_INCREMENT,
|
|
||||||
null_test VARCHAR(10),
|
|
||||||
bit_test BIT(64),
|
|
||||||
tiny_int_test TINYINT,
|
|
||||||
small_int_test SMALLINT,
|
|
||||||
medium_int_test MEDIUMINT,
|
|
||||||
int_test INT,
|
|
||||||
big_int_test BIGINT,
|
|
||||||
float_test FLOAT(10,3),
|
|
||||||
double_test DOUBLE(10,3),
|
|
||||||
decimal_test DECIMAL(10,3),
|
|
||||||
date_test DATE,
|
|
||||||
date_time_test DATETIME,
|
|
||||||
timestamp_test TIMESTAMP,
|
|
||||||
time_test TIME,
|
|
||||||
year_test YEAR(4),
|
|
||||||
char_test CHAR(10),
|
|
||||||
varchar_test VARCHAR(10),
|
|
||||||
binary_test BINARY(10),
|
|
||||||
varbinary_test VARBINARY(10),
|
|
||||||
tiny_blob_test TINYBLOB,
|
|
||||||
tiny_text_test TINYTEXT,
|
|
||||||
blob_test BLOB,
|
|
||||||
text_test TEXT,
|
|
||||||
medium_blob_test MEDIUMBLOB,
|
|
||||||
medium_text_test MEDIUMTEXT,
|
|
||||||
long_blob_test LONGBLOB,
|
|
||||||
long_text_test LONGTEXT,
|
|
||||||
enum_test ENUM('val1', 'val2'),
|
|
||||||
set_test SET('val1', 'val2'),
|
|
||||||
PRIMARY KEY (id)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
@client.query %[
|
|
||||||
INSERT INTO mysql2_test (
|
|
||||||
null_test, bit_test, tiny_int_test, small_int_test, medium_int_test, int_test, big_int_test,
|
|
||||||
float_test, double_test, decimal_test, date_test, date_time_test, timestamp_test, time_test,
|
|
||||||
year_test, char_test, varchar_test, binary_test, varbinary_test, tiny_blob_test,
|
|
||||||
tiny_text_test, blob_test, text_test, medium_blob_test, medium_text_test,
|
|
||||||
long_blob_test, long_text_test, enum_test, set_test
|
|
||||||
)
|
|
||||||
|
|
||||||
VALUES (
|
|
||||||
NULL, b'101', 1, 10, 10, 10, 10,
|
|
||||||
10.3, 10.3, 10.3, '2010-4-4', '2010-4-4 11:44:00', '2010-4-4 11:44:00', '11:44:00',
|
|
||||||
2009, "test", "test", "test", "test", "test",
|
|
||||||
"test", "test", "test", "test", "test",
|
|
||||||
"test", "test", 'val1', 'val1,val2'
|
|
||||||
)
|
|
||||||
]
|
|
||||||
@test_result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
@test_result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first
|
||||||
end
|
end
|
||||||
|
|
||||||
after(:all) do
|
|
||||||
@client.query("DELETE FROM mysql2_test WHERE id=#{@test_result['id']}")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return nil for a NULL value" do
|
it "should return nil for a NULL value" do
|
||||||
@test_result['null_test'].class.should eql(NilClass)
|
@test_result['null_test'].class.should eql(NilClass)
|
||||||
@test_result['null_test'].should eql(nil)
|
@test_result['null_test'].should eql(nil)
|
||||||
|
@ -145,6 +89,20 @@ describe Mysql2::Result do
|
||||||
@test_result['tiny_int_test'].should eql(1)
|
@test_result['tiny_int_test'].should eql(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should return TrueClass or FalseClass for a TINYINT value if :cast_booleans is enabled" do
|
||||||
|
@client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (1)'
|
||||||
|
id1 = @client.last_id
|
||||||
|
@client.query 'INSERT INTO mysql2_test (bool_cast_test) VALUES (0)'
|
||||||
|
id2 = @client.last_id
|
||||||
|
|
||||||
|
result1 = @client.query 'SELECT bool_cast_test FROM mysql2_test WHERE bool_cast_test = 1 LIMIT 1', :cast_booleans => true
|
||||||
|
result2 = @client.query 'SELECT bool_cast_test FROM mysql2_test WHERE bool_cast_test = 0 LIMIT 1', :cast_booleans => true
|
||||||
|
result1.first['bool_cast_test'].should be_true
|
||||||
|
result2.first['bool_cast_test'].should be_false
|
||||||
|
|
||||||
|
@client.query "DELETE from mysql2_test WHERE id IN(#{id1},#{id2})"
|
||||||
|
end
|
||||||
|
|
||||||
it "should return Fixnum for a SMALLINT value" do
|
it "should return Fixnum for a SMALLINT value" do
|
||||||
[Fixnum, Bignum].should include(@test_result['small_int_test'].class)
|
[Fixnum, Bignum].should include(@test_result['small_int_test'].class)
|
||||||
@test_result['small_int_test'].should eql(10)
|
@test_result['small_int_test'].should eql(10)
|
||||||
|
|
|
@ -3,3 +3,62 @@ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/..')
|
||||||
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
||||||
|
|
||||||
require 'mysql2'
|
require 'mysql2'
|
||||||
|
|
||||||
|
Spec::Runner.configure do |config|
|
||||||
|
config.before(:all) do
|
||||||
|
client = Mysql2::Client.new :database => 'test'
|
||||||
|
client.query %[
|
||||||
|
CREATE TABLE IF NOT EXISTS mysql2_test (
|
||||||
|
id MEDIUMINT NOT NULL AUTO_INCREMENT,
|
||||||
|
null_test VARCHAR(10),
|
||||||
|
bit_test BIT(64),
|
||||||
|
tiny_int_test TINYINT,
|
||||||
|
bool_cast_test TINYINT(1),
|
||||||
|
small_int_test SMALLINT,
|
||||||
|
medium_int_test MEDIUMINT,
|
||||||
|
int_test INT,
|
||||||
|
big_int_test BIGINT,
|
||||||
|
float_test FLOAT(10,3),
|
||||||
|
double_test DOUBLE(10,3),
|
||||||
|
decimal_test DECIMAL(10,3),
|
||||||
|
date_test DATE,
|
||||||
|
date_time_test DATETIME,
|
||||||
|
timestamp_test TIMESTAMP,
|
||||||
|
time_test TIME,
|
||||||
|
year_test YEAR(4),
|
||||||
|
char_test CHAR(10),
|
||||||
|
varchar_test VARCHAR(10),
|
||||||
|
binary_test BINARY(10),
|
||||||
|
varbinary_test VARBINARY(10),
|
||||||
|
tiny_blob_test TINYBLOB,
|
||||||
|
tiny_text_test TINYTEXT,
|
||||||
|
blob_test BLOB,
|
||||||
|
text_test TEXT,
|
||||||
|
medium_blob_test MEDIUMBLOB,
|
||||||
|
medium_text_test MEDIUMTEXT,
|
||||||
|
long_blob_test LONGBLOB,
|
||||||
|
long_text_test LONGTEXT,
|
||||||
|
enum_test ENUM('val1', 'val2'),
|
||||||
|
set_test SET('val1', 'val2'),
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
client.query %[
|
||||||
|
INSERT INTO mysql2_test (
|
||||||
|
null_test, bit_test, tiny_int_test, bool_cast_test, small_int_test, medium_int_test, int_test, big_int_test,
|
||||||
|
float_test, double_test, decimal_test, date_test, date_time_test, timestamp_test, time_test,
|
||||||
|
year_test, char_test, varchar_test, binary_test, varbinary_test, tiny_blob_test,
|
||||||
|
tiny_text_test, blob_test, text_test, medium_blob_test, medium_text_test,
|
||||||
|
long_blob_test, long_text_test, enum_test, set_test
|
||||||
|
)
|
||||||
|
|
||||||
|
VALUES (
|
||||||
|
NULL, b'101', 1, 1, 10, 10, 10, 10,
|
||||||
|
10.3, 10.3, 10.3, '2010-4-4', '2010-4-4 11:44:00', '2010-4-4 11:44:00', '11:44:00',
|
||||||
|
2009, "test", "test", "test", "test", "test",
|
||||||
|
"test", "test", "test", "test", "test",
|
||||||
|
"test", "test", 'val1', 'val1,val2'
|
||||||
|
)
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue