Skip to content

Commit cd7c774

Browse files
committed
TinyTds::Client.new now accepts keyword arguments instead of a hash
1 parent 654570a commit cd7c774

File tree

7 files changed

+70
-102
lines changed

7 files changed

+70
-102
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
* `TinyTds::Result` is now a pure Ruby class
88
* `#execute`: Replaced `opts` hash with keyword arguments
99
* Removed `symbolize_keys` and `cache_rows` from `#default_query_options`
10+
* `TinyTds::Client.new` now accepts keyword arguments instead of a hash
11+
* Renamed `tds_version` and `tds_version_info` to `server_version` and `server_version_info`.
1012

1113
## 3.3.0
1214

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,15 @@ Connect to a database.
9898
client = TinyTds::Client.new username: 'sa', password: 'secret', host: 'mydb.host.net'
9999
```
100100

101-
Creating a new client takes a hash of options. For valid iconv encoding options, see the output of `iconv -l`. Only a few have been tested, and are highly recommended to leave blank for the UTF-8 default.
101+
Creating a new client takes keyword arguments. For valid iconv encoding options, see the output of `iconv -l`. Only a few have been tested, and are highly recommended to leave blank for the UTF-8 default.
102102

103103
* :username - The database server user.
104104
* :password - The user password.
105105
* :dataserver - Can be the name for your data server as defined in freetds.conf. Raw hostname or hostname:port will work here too. FreeTDS says that a named instance like 'localhost\SQLEXPRESS' will work too, but I highly suggest that you use the :host and :port options below. [Google how to find your host port if you are using named instances](http://bit.ly/xAf2jm) or [go here](http://msdn.microsoft.com/en-us/library/ms181087.aspx).
106106
* :host - Used if :dataserver blank. Can be an host name or IP.
107107
* :port - Defaults to 1433. Only used if :host is used.
108108
* :database - The default database to use.
109-
* :appname - Short string seen in SQL Servers process/activity window.
109+
* :app_name - Short string seen in SQL Servers process/activity window.
110110
* :tds_version - TDS version. Defaults to "7.3".
111111
* :login_timeout - Seconds to wait for login. Default to 60 seconds.
112112
* :timeout - Seconds to wait for a response to a SQL command. Default 5 seconds. Timeouts caused by network failure will raise a timeout error 1 second after the configured timeout limit is hit (see [#481](https://github.com/rails-sqlserver/tiny_tds/pull/481) for details).

ext/tiny_tds/client.c

Lines changed: 30 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
VALUE cTinyTdsClient;
66
extern VALUE mTinyTds, cTinyTdsError;
7-
static ID sym_username, sym_password, sym_dataserver, sym_database, sym_appname, sym_tds_version, sym_login_timeout, sym_timeout, sym_encoding, sym_azure, sym_contained, sym_use_utf16, sym_message_handler;
87
static ID intern_source_eql, intern_severity_eql, intern_db_error_number_eql, intern_os_error_number_eql;
98
static ID intern_new, intern_dup, intern_transpose_iconv_encoding, intern_local_offset, intern_gsub, intern_call;
109
VALUE opt_escape_regex, opt_escape_dblquote;
@@ -470,7 +469,7 @@ static VALUE allocate(VALUE klass)
470469

471470
// TinyTds::Client (public)
472471

473-
static VALUE rb_tinytds_tds_version(VALUE self)
472+
static VALUE rb_tinytds_server_version(VALUE self)
474473
{
475474
GET_CLIENT_WRAPPER(self);
476475
return INT2FIX(dbtds(cwrap->client));
@@ -925,25 +924,25 @@ static VALUE rb_tinytds_identity_sql(VALUE self)
925924

926925
// TinyTds::Client (protected)
927926

928-
static VALUE rb_tinytds_connect(VALUE self, VALUE opts)
927+
static VALUE rb_tinytds_connect(VALUE self)
929928
{
930929
/* Parsing options hash to local vars. */
931-
VALUE user, pass, dataserver, database, app, version, ltimeout, timeout, charset, azure, contained, use_utf16;
930+
VALUE username, password, dataserver, database, app_name, tds_version, login_timeout, timeout, charset, azure, contained, use_utf16;
932931
GET_CLIENT_WRAPPER(self);
933932

934-
user = rb_hash_aref(opts, sym_username);
935-
pass = rb_hash_aref(opts, sym_password);
936-
dataserver = rb_hash_aref(opts, sym_dataserver);
937-
database = rb_hash_aref(opts, sym_database);
938-
app = rb_hash_aref(opts, sym_appname);
939-
version = rb_hash_aref(opts, sym_tds_version);
940-
ltimeout = rb_hash_aref(opts, sym_login_timeout);
941-
timeout = rb_hash_aref(opts, sym_timeout);
942-
charset = rb_hash_aref(opts, sym_encoding);
943-
azure = rb_hash_aref(opts, sym_azure);
944-
contained = rb_hash_aref(opts, sym_contained);
945-
use_utf16 = rb_hash_aref(opts, sym_use_utf16);
946-
cwrap->userdata->message_handler = rb_hash_aref(opts, sym_message_handler);
933+
app_name = rb_iv_get(self, "@app_name");
934+
azure = rb_iv_get(self, "@azure");
935+
contained = rb_iv_get(self, "@contained");
936+
database = rb_iv_get(self, "@database");
937+
dataserver = rb_iv_get(self, "@dataserver");
938+
charset = rb_iv_get(self, "@encoding");
939+
login_timeout = rb_iv_get(self, "@login_timeout");
940+
password = rb_iv_get(self, "@password");
941+
tds_version = rb_iv_get(self, "@tds_version");
942+
timeout = rb_iv_get(self, "@timeout");
943+
username = rb_iv_get(self, "@username");
944+
use_utf16 = rb_iv_get(self, "@use_utf16");
945+
cwrap->userdata->message_handler = rb_iv_get(self, "@message_handler");
947946

948947
/* Dealing with options. */
949948
if (dbinit() == FAIL) {
@@ -955,24 +954,24 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts)
955954
dbmsghandle(tinytds_msg_handler);
956955
cwrap->login = dblogin();
957956

958-
if (!NIL_P(version)) {
959-
dbsetlversion(cwrap->login, NUM2INT(version));
957+
if (!NIL_P(tds_version)) {
958+
dbsetlversion(cwrap->login, NUM2INT(tds_version));
960959
}
961960

962-
if (!NIL_P(user)) {
963-
dbsetluser(cwrap->login, StringValueCStr(user));
961+
if (!NIL_P(username)) {
962+
dbsetluser(cwrap->login, StringValueCStr(username));
964963
}
965964

966-
if (!NIL_P(pass)) {
967-
dbsetlpwd(cwrap->login, StringValueCStr(pass));
965+
if (!NIL_P(password)) {
966+
dbsetlpwd(cwrap->login, StringValueCStr(password));
968967
}
969968

970-
if (!NIL_P(app)) {
971-
dbsetlapp(cwrap->login, StringValueCStr(app));
969+
if (!NIL_P(app_name)) {
970+
dbsetlapp(cwrap->login, StringValueCStr(app_name));
972971
}
973972

974-
if (!NIL_P(ltimeout)) {
975-
dbsetlogintime(NUM2INT(ltimeout));
973+
if (!NIL_P(login_timeout)) {
974+
dbsetlogintime(NUM2INT(login_timeout));
976975
}
977976

978977
if (!NIL_P(charset)) {
@@ -981,19 +980,7 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts)
981980

982981
if (!NIL_P(database)) {
983982
if (azure == Qtrue || contained == Qtrue) {
984-
#ifdef DBSETLDBNAME
985983
DBSETLDBNAME(cwrap->login, StringValueCStr(database));
986-
#else
987-
988-
if (azure == Qtrue) {
989-
rb_warn("TinyTds: :azure option is not supported in this version of FreeTDS.\n");
990-
}
991-
992-
if (contained == Qtrue) {
993-
rb_warn("TinyTds: :contained option is not supported in this version of FreeTDS.\n");
994-
}
995-
996-
#endif
997984
}
998985
}
999986

@@ -1017,8 +1004,8 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts)
10171004
cwrap->closed = 0;
10181005
cwrap->charset = charset;
10191006

1020-
if (!NIL_P(version)) {
1021-
dbsetversion(NUM2INT(version));
1007+
if (!NIL_P(tds_version)) {
1008+
dbsetversion(NUM2INT(tds_version));
10221009
}
10231010

10241011
if (!NIL_P(timeout)) {
@@ -1053,7 +1040,7 @@ void init_tinytds_client()
10531040
cTinyTdsClient = rb_define_class_under(mTinyTds, "Client", rb_cObject);
10541041
rb_define_alloc_func(cTinyTdsClient, allocate);
10551042
/* Define TinyTds::Client Public Methods */
1056-
rb_define_method(cTinyTdsClient, "tds_version", rb_tinytds_tds_version, 0);
1043+
rb_define_method(cTinyTdsClient, "server_version", rb_tinytds_server_version, 0);
10571044
rb_define_method(cTinyTdsClient, "close", rb_tinytds_close, 0);
10581045
rb_define_method(cTinyTdsClient, "closed?", rb_tinytds_closed, 0);
10591046
rb_define_method(cTinyTdsClient, "canceled?", rb_tinytds_canceled, 0);
@@ -1068,21 +1055,7 @@ void init_tinytds_client()
10681055
rb_define_method(cTinyTdsClient, "return_code", rb_tinytds_return_code, 0);
10691056
rb_define_method(cTinyTdsClient, "identity_sql", rb_tinytds_identity_sql, 0);
10701057
/* Define TinyTds::Client Protected Methods */
1071-
rb_define_protected_method(cTinyTdsClient, "connect", rb_tinytds_connect, 1);
1072-
/* Symbols For Connect */
1073-
sym_username = ID2SYM(rb_intern("username"));
1074-
sym_password = ID2SYM(rb_intern("password"));
1075-
sym_dataserver = ID2SYM(rb_intern("dataserver"));
1076-
sym_database = ID2SYM(rb_intern("database"));
1077-
sym_appname = ID2SYM(rb_intern("appname"));
1078-
sym_tds_version = ID2SYM(rb_intern("tds_version"));
1079-
sym_login_timeout = ID2SYM(rb_intern("login_timeout"));
1080-
sym_timeout = ID2SYM(rb_intern("timeout"));
1081-
sym_encoding = ID2SYM(rb_intern("encoding"));
1082-
sym_azure = ID2SYM(rb_intern("azure"));
1083-
sym_contained = ID2SYM(rb_intern("contained"));
1084-
sym_use_utf16 = ID2SYM(rb_intern("use_utf16"));
1085-
sym_message_handler = ID2SYM(rb_intern("message_handler"));
1058+
rb_define_protected_method(cTinyTdsClient, "connect", rb_tinytds_connect, 0);
10861059
/* Intern TinyTds::Error Accessors */
10871060
intern_source_eql = rb_intern("source=");
10881061
intern_severity_eql = rb_intern("severity=");

lib/tiny_tds/client.rb

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
module TinyTds
22
class Client
3+
attr_reader :app_name, :contained, :database, :dataserver, :encoding, :message_handler, :login_timeout, :password, :port, :tds_version, :timeout, :username, :use_utf16
4+
35
@default_query_options = {
46
as: :hash,
57
empty_sets: true,
68
timezone: :local
79
}
810

911
attr_reader :query_options
10-
attr_reader :message_handler
1112

1213
class << self
1314
attr_reader :default_query_options
@@ -29,37 +30,38 @@ def local_offset
2930
# rubocop:disable Metrics/MethodLength
3031
# rubocop:disable Metrics/CyclomaticComplexity
3132
# rubocop:disable Metrics/PerceivedComplexity
32-
def initialize(opts = {})
33-
if opts[:dataserver].to_s.empty? && opts[:host].to_s.empty?
33+
def initialize(app_name: "TinyTds", azure: false, contained: false, database: nil, dataserver: nil, encoding: "UTF-8", message_handler: nil, host: nil, login_timeout: 60, password: nil, port: 1433, tds_version: nil, timeout: 5, username: nil, use_utf16: true)
34+
if dataserver.to_s.empty? && host.to_s.empty?
3435
raise ArgumentError, "missing :host option if no :dataserver given"
3536
end
3637

37-
@message_handler = opts[:message_handler]
38-
if @message_handler && !@message_handler.respond_to?(:call)
38+
if message_handler && !message_handler.respond_to?(:call)
3939
raise ArgumentError, ":message_handler must implement `call` (eg, a Proc or a Method)"
40+
else
41+
@message_handler = message_handler
4042
end
4143

42-
opts[:username] = parse_username(opts)
43-
opts[:password] = opts[:password].to_s if opts[:password] && opts[:password].to_s.strip != ""
44-
opts[:appname] ||= "TinyTds"
45-
opts[:tds_version] = tds_versions_setter(opts)
46-
opts[:use_utf16] = opts[:use_utf16].nil? || ["true", "1", "yes"].include?(opts[:use_utf16].to_s)
47-
opts[:login_timeout] ||= 60
48-
opts[:timeout] ||= 5
49-
opts[:encoding] = (opts[:encoding].nil? || opts[:encoding].casecmp("utf8").zero?) ? "UTF-8" : opts[:encoding].upcase
50-
opts[:port] ||= 1433
51-
opts[:dataserver] = "#{opts[:host]}:#{opts[:port]}" if opts[:dataserver].to_s.empty?
52-
forced_integer_keys = [:login_timeout, :port, :timeout]
53-
forced_integer_keys.each { |k| opts[k] = opts[k].to_i if opts[k] }
54-
connect(opts)
44+
@app_name = app_name
45+
@database = database
46+
@dataserver = dataserver || "#{host}:#{port}"
47+
@encoding = (encoding.nil? || encoding.casecmp("utf8").zero?) ? "UTF-8" : encoding.upcase
48+
@login_timeout = login_timeout.to_i
49+
@password = password if password && password.to_s.strip != ""
50+
@port = port.to_i
51+
@timeout = timeout.to_i
52+
@tds_version = tds_versions_setter(tds_version:)
53+
@username = parse_username(azure:, host:, username:)
54+
@use_utf16 = use_utf16.nil? || ["true", "1", "yes"].include?(use_utf16.to_s)
55+
56+
connect
5557
end
5658

5759
def tds_73?
58-
tds_version >= 11
60+
server_version >= 11
5961
end
6062

61-
def tds_version_info
62-
info = TDS_VERSIONS_GETTERS[tds_version]
63+
def server_version_info
64+
info = TDS_VERSIONS_GETTERS[server_version]
6365
"#{info[:name]} - #{info[:description]}" if info
6466
end
6567

@@ -69,18 +71,16 @@ def active?
6971

7072
private
7173

72-
def parse_username(opts)
73-
host = opts[:host]
74-
username = opts[:username]
75-
return username if username.nil? || !opts[:azure]
74+
def parse_username(azure: false, host: nil, username:)
75+
return username if username.nil? || !azure
7676
return username if username.include?("@") && !username.include?("database.windows.net")
7777
user, domain = username.split("@")
7878
domain ||= host
7979
"#{user}@#{domain.split(".").first}"
8080
end
8181

82-
def tds_versions_setter(opts = {})
83-
v = opts[:tds_version] || ENV["TDSVER"] || "7.3"
82+
def tds_versions_setter(tds_version:)
83+
v = tds_version || ENV["TDSVER"] || "7.3"
8484
TDS_VERSIONS_SETTERS[v.to_s]
8585
end
8686

test/client_test.rb

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,9 @@ class ClientTest < TinyTds::TestCase
2626
end
2727
end
2828

29-
it "has getters for the tds version information (brittle since conf takes precedence)" do
30-
if @client.tds_73?
31-
assert_equal 11, @client.tds_version
32-
assert_equal "DBTDS_7_3 - Microsoft SQL Server 2008", @client.tds_version_info
33-
else
34-
assert_equal 9, @client.tds_version
35-
assert_equal "DBTDS_7_1/DBTDS_8_0 - Microsoft SQL Server 2000", @client.tds_version_info
36-
end
29+
it "has getters for the server version information (brittle since conf takes precedence)" do
30+
assert_equal 11, @client.server_version
31+
assert_equal "DBTDS_7_3 - Microsoft SQL Server 2008", @client.server_version_info
3732
end
3833

3934
it "uses UTF-8 client charset/encoding by default" do
@@ -82,8 +77,7 @@ class ClientTest < TinyTds::TestCase
8277
end
8378

8479
it "raises TinyTds exception with undefined :dataserver" do
85-
options = connection_options login_timeout: 1, dataserver: "DOESNOTEXIST"
86-
action = lambda { new_connection(options) }
80+
action = lambda { new_connection(login_timeout: 1, dataserver: "DOESNOTEXIST") }
8781
assert_raise_tinytds_error(action) do |e|
8882
# Not sure why tese are different.
8983
if ruby_darwin?
@@ -193,7 +187,7 @@ class ClientTest < TinyTds::TestCase
193187
it "raises TinyTds exception with wrong :username" do
194188
skip if ENV["CI"] && sqlserver_azure? # Some issue with db_error_number.
195189
options = connection_options username: "willnotwork"
196-
action = lambda { new_connection(options) }
190+
action = lambda { new_connection(**options) }
197191
assert_raise_tinytds_error(action) do |e|
198192
assert_equal 18456, e.db_error_number
199193
assert_equal 14, e.severity

test/result_test.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,8 @@ class ResultTest < TinyTds::TestCase
142142

143143
it "works in tandem with the client when needing to find out if client has sql sent and result is canceled or not" do
144144
# Default state.
145-
@client = TinyTds::Client.new(connection_options)
146145
_(@client.sqlsent?).must_equal false
147-
_(@client.canceled?).must_equal false
146+
_(@client.canceled?).must_equal true
148147
# With active result before and after cancel.
149148
@client.execute(@query1)
150149
_(@client.sqlsent?).must_equal false

test/test_helper.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ def close_client(client = @client)
4141
client.close if defined?(client) && client.is_a?(TinyTds::Client)
4242
end
4343

44-
def new_connection(options = {})
45-
client = TinyTds::Client.new(connection_options(options))
44+
def new_connection(**options)
45+
client = TinyTds::Client.new(**connection_options(options))
4646
if sqlserver_azure?
4747
client.do("SET ANSI_NULLS ON")
4848
client.do("SET CURSOR_CLOSE_ON_COMMIT OFF")
@@ -71,7 +71,7 @@ def connection_options(options = {})
7171
username: username,
7272
password: password,
7373
database: ENV["TINYTDS_UNIT_DATABASE"] || "tinytdstest",
74-
appname: "TinyTds Dev",
74+
app_name: "TinyTds Dev",
7575
login_timeout: 5,
7676
timeout: connection_timeout,
7777
azure: sqlserver_azure?}.merge(options)

0 commit comments

Comments
 (0)