From ef53a5bf15a3080015e589c79816d8b1b2b49580 Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Thu, 9 Jan 2025 01:02:34 +0900 Subject: [PATCH] Fix mysql2 gem types (#764) - Add `Mysql2::Client#affected_rows` - Full support `Mysql2::row_value_type` - Add `BigDecimal`, `Float`, `Time`, `Date` - Add `Mysql2::Result#size` and `Mysql2::Result#count` --- gems/mysql2/0.5/_test/client.rb | 8 +++ gems/mysql2/0.5/_test/result.rb | 3 + gems/mysql2/0.5/_test/row_value_type.rb | 82 +++++++++++++++++++++++++ gems/mysql2/0.5/client.rbs | 2 + gems/mysql2/0.5/manifest.yaml | 8 +++ gems/mysql2/0.5/result.rbs | 16 ++++- 6 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 gems/mysql2/0.5/_test/client.rb create mode 100644 gems/mysql2/0.5/_test/result.rb create mode 100644 gems/mysql2/0.5/_test/row_value_type.rb create mode 100644 gems/mysql2/0.5/manifest.yaml diff --git a/gems/mysql2/0.5/_test/client.rb b/gems/mysql2/0.5/_test/client.rb new file mode 100644 index 000000000..fd9e1ee33 --- /dev/null +++ b/gems/mysql2/0.5/_test/client.rb @@ -0,0 +1,8 @@ +client = Mysql2::Client.new + +client.query("UPDATE users SET age = age + 1 WHERE name = 'John'") +if client.affected_rows == 0 + puts "No rows were updated" +else + puts "Updated #{client.affected_rows} rows" +end diff --git a/gems/mysql2/0.5/_test/result.rb b/gems/mysql2/0.5/_test/result.rb new file mode 100644 index 000000000..371d9f0e3 --- /dev/null +++ b/gems/mysql2/0.5/_test/result.rb @@ -0,0 +1,3 @@ +client = Mysql2::Client.new +result = client.query("SELECT * FROM users WHERE age > 10") +result.size diff --git a/gems/mysql2/0.5/_test/row_value_type.rb b/gems/mysql2/0.5/_test/row_value_type.rb new file mode 100644 index 000000000..c5798f04f --- /dev/null +++ b/gems/mysql2/0.5/_test/row_value_type.rb @@ -0,0 +1,82 @@ +client = Mysql2::Client.new + +client.query %[ + CREATE TABLE IF NOT EXISTS mysql2_test ( + id MEDIUMINT NOT NULL AUTO_INCREMENT, + null_test VARCHAR(10), + bit_test BIT(64), + single_bit_test BIT(1), + 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), + float_zero_test FLOAT(10,3), + double_test DOUBLE(10,3), + decimal_test DECIMAL(10,3), + decimal_zero_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 "DELETE FROM mysql2_test;" +client.query %[ + INSERT INTO mysql2_test ( + null_test, bit_test, single_bit_test, tiny_int_test, bool_cast_test, small_int_test, medium_int_test, int_test, big_int_test, + float_test, float_zero_test, double_test, decimal_test, decimal_zero_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', b'1', 1, 1, 10, 10, 10, 10, + 10.3, 0, 10.3, 10.3, 0, '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 || raise + +# NULL => nil +test_result['null_test'] #: nil +# BIT(64) => String +test_result['bit_test'] #: String +# TINYINT => Integer +test_result['tiny_int_test'] #: Integer +# INT => Integer +test_result['int_test'] #: Integer +# DECIMAL => BigDecimal +test_result['decimal_test'] #: BigDecimal +# FLOAT => Float +test_result['float_test'] #: Float +# DATETIME => Time +test_result['date_time_test'] #: Time +# TIMESTAMP => Time +test_result['timestamp_test'] #: Time +# DATE => Date +test_result['date_test'] #: Date +# ENUM => String +test_result['enum_test'] #: String diff --git a/gems/mysql2/0.5/client.rbs b/gems/mysql2/0.5/client.rbs index d5263d952..cb6c10407 100644 --- a/gems/mysql2/0.5/client.rbs +++ b/gems/mysql2/0.5/client.rbs @@ -44,6 +44,8 @@ module Mysql2 def last_id: () -> Integer + def affected_rows: () -> Integer + private def self.local_offset: () -> untyped diff --git a/gems/mysql2/0.5/manifest.yaml b/gems/mysql2/0.5/manifest.yaml new file mode 100644 index 000000000..e38f243fb --- /dev/null +++ b/gems/mysql2/0.5/manifest.yaml @@ -0,0 +1,8 @@ +# manifest.yaml describes dependencies which do not appear in the gemspec. +# If this gem includes such dependencies, comment-out the following lines and +# declare the dependencies. +# If all dependencies appear in the gemspec, you should remove this file. +# +dependencies: + - name: bigdecimal + - name: date diff --git a/gems/mysql2/0.5/result.rbs b/gems/mysql2/0.5/result.rbs index 9753c247c..fb719fe74 100644 --- a/gems/mysql2/0.5/result.rbs +++ b/gems/mysql2/0.5/result.rbs @@ -1,12 +1,20 @@ module Mysql2 - type row_value_type = String | Integer | nil + type row_value_type = String | Integer | BigDecimal | Float | Time | Date | nil class ResultAsHash attr_reader server_flags: untyped - include Enumerable[Hash[Symbol, row_value_type]] + # NOTE: + # The type of key is controlled by `symbolize_keys` option of `Mysql2::Client.new`. + # It can be expressed using a type argument such as `Client[ResultType]`, + # but since the state becomes complicated. So `String | Symbol` is allowed. + type key_type = String | Symbol - def each: () { (Hash[Symbol, row_value_type]) -> void } -> void + include Enumerable[Hash[key_type, row_value_type]] + + def each: () { (Hash[key_type, row_value_type]) -> void } -> void + def count: () -> Integer + alias size count end class ResultAsArray @@ -15,5 +23,7 @@ module Mysql2 include Enumerable[Array[row_value_type]] def each: () { (Array[row_value_type]) -> void } -> void + def count: () -> Integer + alias size count end end