marjoree 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.
Files changed (88) hide show
  1. data/README +50 -0
  2. data/examples/contains_example.rb +23 -0
  3. data/examples/count_and_insert_example.rb +20 -0
  4. data/examples/select_example.rb +27 -0
  5. data/html/classes/ExpectedResultSet.html +220 -0
  6. data/html/classes/ExpectedResultSet.src/M000001.html +18 -0
  7. data/html/classes/ExpectedResultSet.src/M000002.html +18 -0
  8. data/html/classes/ExpectedResultSet.src/M000003.html +18 -0
  9. data/html/classes/ExpectedResultSet.src/M000004.html +18 -0
  10. data/html/classes/Marjoree.html +568 -0
  11. data/html/classes/Marjoree.src/M000022.html +19 -0
  12. data/html/classes/Marjoree.src/M000023.html +20 -0
  13. data/html/classes/Marjoree.src/M000024.html +22 -0
  14. data/html/classes/Marjoree.src/M000025.html +18 -0
  15. data/html/classes/Marjoree.src/M000026.html +20 -0
  16. data/html/classes/Marjoree.src/M000027.html +18 -0
  17. data/html/classes/Marjoree.src/M000028.html +18 -0
  18. data/html/classes/Marjoree.src/M000029.html +21 -0
  19. data/html/classes/Marjoree.src/M000030.html +20 -0
  20. data/html/classes/Marjoree.src/M000031.html +19 -0
  21. data/html/classes/Marjoree.src/M000032.html +18 -0
  22. data/html/classes/Marjoree.src/M000033.html +18 -0
  23. data/html/classes/Marjoree.src/M000034.html +19 -0
  24. data/html/classes/Marjoree.src/M000035.html +21 -0
  25. data/html/classes/Marjoree.src/M000036.html +26 -0
  26. data/html/classes/Marjoree.src/M000037.html +22 -0
  27. data/html/classes/Marjoree.src/M000038.html +23 -0
  28. data/html/classes/Marjoree.src/M000039.html +24 -0
  29. data/html/classes/Marjoree.src/M000040.html +18 -0
  30. data/html/classes/Marjoree.src/M000041.html +18 -0
  31. data/html/classes/Marjoree.src/M000042.html +25 -0
  32. data/html/classes/ODBC/Error.html +152 -0
  33. data/html/classes/ODBC/Error.src/M000020.html +21 -0
  34. data/html/classes/ODBC/Error.src/M000021.html +18 -0
  35. data/html/classes/ODBC/TimeStamp.html +182 -0
  36. data/html/classes/ODBC/TimeStamp.src/M000017.html +18 -0
  37. data/html/classes/ODBC/TimeStamp.src/M000018.html +22 -0
  38. data/html/classes/ODBC/TimeStamp.src/M000019.html +19 -0
  39. data/html/classes/ODBC.html +108 -0
  40. data/html/classes/ResultSetWrapper.html +345 -0
  41. data/html/classes/ResultSetWrapper.src/M000005.html +27 -0
  42. data/html/classes/ResultSetWrapper.src/M000006.html +24 -0
  43. data/html/classes/ResultSetWrapper.src/M000007.html +23 -0
  44. data/html/classes/ResultSetWrapper.src/M000008.html +18 -0
  45. data/html/classes/ResultSetWrapper.src/M000009.html +18 -0
  46. data/html/classes/ResultSetWrapper.src/M000010.html +18 -0
  47. data/html/classes/ResultSetWrapper.src/M000011.html +18 -0
  48. data/html/classes/ResultSetWrapper.src/M000012.html +20 -0
  49. data/html/classes/ResultSetWrapper.src/M000013.html +18 -0
  50. data/html/classes/ResultSetWrapper.src/M000014.html +22 -0
  51. data/html/classes/ResultSetWrapper.src/M000015.html +23 -0
  52. data/html/classes/ResultSetWrapper.src/M000016.html +27 -0
  53. data/html/created.rid +1 -0
  54. data/html/files/README.html +159 -0
  55. data/html/files/lib/expected_result_set_rb.html +116 -0
  56. data/html/files/lib/marjoree_rb.html +110 -0
  57. data/html/files/lib/odbc_overrides_rb.html +101 -0
  58. data/html/files/lib/result_set_wrapper_rb.html +101 -0
  59. data/html/fr_class_index.html +32 -0
  60. data/html/fr_file_index.html +31 -0
  61. data/html/fr_method_index.html +68 -0
  62. data/html/index.html +24 -0
  63. data/html/rdoc-style.css +208 -0
  64. data/lib/expected_result_set.rb +35 -0
  65. data/lib/marjoree.rb +344 -0
  66. data/lib/odbc_overrides.rb +33 -0
  67. data/lib/result_set_wrapper.rb +193 -0
  68. data/rakefile.rb +38 -0
  69. data/tests/all_tests.rb +15 -0
  70. data/tests/sprocs/test_error_sproc.sp +11 -0
  71. data/tests/sprocs/test_sproc.sp +5 -0
  72. data/tests/sprocs/test_sproc_with_mixed_params.sp +15 -0
  73. data/tests/sprocs/test_sproc_with_output_params.sp +10 -0
  74. data/tests/sprocs/test_sproc_with_params.sp +9 -0
  75. data/tests/sprocs/test_sproc_with_select_and_ops.sp +12 -0
  76. data/tests/test_contains.rb +27 -0
  77. data/tests/test_delete.rb +47 -0
  78. data/tests/test_expected_result_set.rb +40 -0
  79. data/tests/test_insert.rb +47 -0
  80. data/tests/test_marjoree.rb +91 -0
  81. data/tests/test_num_rows.rb +32 -0
  82. data/tests/test_result_set_wrapper.rb +162 -0
  83. data/tests/test_select.rb +30 -0
  84. data/tests/test_sproc.rb +99 -0
  85. data/tests/test_time_stamp.rb +52 -0
  86. data/tests/test_truncate.rb +31 -0
  87. data/tests/test_update.rb +56 -0
  88. metadata +137 -0
@@ -0,0 +1,68 @@
1
+
2
+ <?xml version="1.0" encoding="iso-8859-1"?>
3
+ <!DOCTYPE html
4
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
5
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
+
7
+ <!--
8
+
9
+ Methods
10
+
11
+ -->
12
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13
+ <head>
14
+ <title>Methods</title>
15
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
16
+ <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
17
+ <base target="docwin" />
18
+ </head>
19
+ <body>
20
+ <div id="index">
21
+ <h1 class="section-bar">Methods</h1>
22
+ <div id="index-entries">
23
+ <a href="classes/ODBC/TimeStamp.html#M000017">== (ODBC::TimeStamp)</a><br />
24
+ <a href="classes/ResultSetWrapper.html#M000006">apply_output_params (ResultSetWrapper)</a><br />
25
+ <a href="classes/Marjoree.html#M000040">assert_contains (Marjoree)</a><br />
26
+ <a href="classes/Marjoree.html#M000037">assert_db_error (Marjoree)</a><br />
27
+ <a href="classes/Marjoree.html#M000041">assert_does_not_contain (Marjoree)</a><br />
28
+ <a href="classes/Marjoree.html#M000033">assert_empty (Marjoree)</a><br />
29
+ <a href="classes/Marjoree.html#M000036">assert_error_thrown (Marjoree)</a><br />
30
+ <a href="classes/Marjoree.html#M000035">assert_not_equal_results (Marjoree)</a><br />
31
+ <a href="classes/Marjoree.html#M000034">assert_results (Marjoree)</a><br />
32
+ <a href="classes/ResultSetWrapper.html#M000012">collect (ResultSetWrapper)</a><br />
33
+ <a href="classes/ExpectedResultSet.html#M000002">columns= (ExpectedResultSet)</a><br />
34
+ <a href="classes/Marjoree.html#M000022">connect (Marjoree)</a><br />
35
+ <a href="classes/Marjoree.html#M000028">contains? (Marjoree)</a><br />
36
+ <a href="classes/ResultSetWrapper.html#M000014">contains? (ResultSetWrapper)</a><br />
37
+ <a href="classes/ResultSetWrapper.html#M000015">contains_row? (ResultSetWrapper)</a><br />
38
+ <a href="classes/ResultSetWrapper.html#M000009">count (ResultSetWrapper)</a><br />
39
+ <a href="classes/Marjoree.html#M000027">count (Marjoree)</a><br />
40
+ <a href="classes/Marjoree.html#M000031">delete (Marjoree)</a><br />
41
+ <a href="classes/Marjoree.html#M000023">disconnect (Marjoree)</a><br />
42
+ <a href="classes/ResultSetWrapper.html#M000011">empty? (ResultSetWrapper)</a><br />
43
+ <a href="classes/ODBC/Error.html#M000020">error_code (ODBC::Error)</a><br />
44
+ <a href="classes/ODBC/Error.html#M000021">error_message (ODBC::Error)</a><br />
45
+ <a href="classes/Marjoree.html#M000042">execute (Marjoree)</a><br />
46
+ <a href="classes/ODBC/TimeStamp.html#M000019">from_date (ODBC::TimeStamp)</a><br />
47
+ <a href="classes/ResultSetWrapper.html#M000013">has? (ResultSetWrapper)</a><br />
48
+ <a href="classes/Marjoree.html#M000038">has_column_headers? (Marjoree)</a><br />
49
+ <a href="classes/Marjoree.html#M000039">has_correct_data? (Marjoree)</a><br />
50
+ <a href="classes/Marjoree.html#M000029">insert (Marjoree)</a><br />
51
+ <a href="classes/ResultSetWrapper.html#M000008">is_output_param? (ResultSetWrapper)</a><br />
52
+ <a href="classes/ResultSetWrapper.html#M000007">method_missing (ResultSetWrapper)</a><br />
53
+ <a href="classes/ResultSetWrapper.html#M000005">new (ResultSetWrapper)</a><br />
54
+ <a href="classes/ExpectedResultSet.html#M000001">new (ExpectedResultSet)</a><br />
55
+ <a href="classes/Marjoree.html#M000026">num_rows (Marjoree)</a><br />
56
+ <a href="classes/ExpectedResultSet.html#M000003">row_hash (ExpectedResultSet)</a><br />
57
+ <a href="classes/ExpectedResultSet.html#M000004">row_hashes (ExpectedResultSet)</a><br />
58
+ <a href="classes/Marjoree.html#M000024">run_sproc (Marjoree)</a><br />
59
+ <a href="classes/Marjoree.html#M000025">select (Marjoree)</a><br />
60
+ <a href="classes/ResultSetWrapper.html#M000010">size (ResultSetWrapper)</a><br />
61
+ <a href="classes/ODBC/TimeStamp.html#M000018">to_s (ODBC::TimeStamp)</a><br />
62
+ <a href="classes/ResultSetWrapper.html#M000016">to_s (ResultSetWrapper)</a><br />
63
+ <a href="classes/Marjoree.html#M000032">truncate (Marjoree)</a><br />
64
+ <a href="classes/Marjoree.html#M000030">update (Marjoree)</a><br />
65
+ </div>
66
+ </div>
67
+ </body>
68
+ </html>
data/html/index.html ADDED
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
5
+
6
+ <!--
7
+
8
+ RDoc Documentation
9
+
10
+ -->
11
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
12
+ <head>
13
+ <title>RDoc Documentation</title>
14
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
15
+ </head>
16
+ <frameset rows="20%, 80%">
17
+ <frameset cols="25%,35%,45%">
18
+ <frame src="fr_file_index.html" title="Files" name="Files" />
19
+ <frame src="fr_class_index.html" name="Classes" />
20
+ <frame src="fr_method_index.html" name="Methods" />
21
+ </frameset>
22
+ <frame src="files/README.html" name="docwin" />
23
+ </frameset>
24
+ </html>
@@ -0,0 +1,208 @@
1
+
2
+ body {
3
+ font-family: Verdana,Arial,Helvetica,sans-serif;
4
+ font-size: 90%;
5
+ margin: 0;
6
+ margin-left: 40px;
7
+ padding: 0;
8
+ background: white;
9
+ }
10
+
11
+ h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
12
+ h1 { font-size: 150%; }
13
+ h2,h3,h4 { margin-top: 1em; }
14
+
15
+ a { background: #eef; color: #039; text-decoration: none; }
16
+ a:hover { background: #039; color: #eef; }
17
+
18
+ /* Override the base stylesheet's Anchor inside a table cell */
19
+ td > a {
20
+ background: transparent;
21
+ color: #039;
22
+ text-decoration: none;
23
+ }
24
+
25
+ /* and inside a section title */
26
+ .section-title > a {
27
+ background: transparent;
28
+ color: #eee;
29
+ text-decoration: none;
30
+ }
31
+
32
+ /* === Structural elements =================================== */
33
+
34
+ div#index {
35
+ margin: 0;
36
+ margin-left: -40px;
37
+ padding: 0;
38
+ font-size: 90%;
39
+ }
40
+
41
+
42
+ div#index a {
43
+ margin-left: 0.7em;
44
+ }
45
+
46
+ div#index .section-bar {
47
+ margin-left: 0px;
48
+ padding-left: 0.7em;
49
+ background: #ccc;
50
+ font-size: small;
51
+ }
52
+
53
+
54
+ div#classHeader, div#fileHeader {
55
+ width: auto;
56
+ color: white;
57
+ padding: 0.5em 1.5em 0.5em 1.5em;
58
+ margin: 0;
59
+ margin-left: -40px;
60
+ border-bottom: 3px solid #006;
61
+ }
62
+
63
+ div#classHeader a, div#fileHeader a {
64
+ background: inherit;
65
+ color: white;
66
+ }
67
+
68
+ div#classHeader td, div#fileHeader td {
69
+ background: inherit;
70
+ color: white;
71
+ }
72
+
73
+
74
+ div#fileHeader {
75
+ background: #057;
76
+ }
77
+
78
+ div#classHeader {
79
+ background: #048;
80
+ }
81
+
82
+
83
+ .class-name-in-header {
84
+ font-size: 180%;
85
+ font-weight: bold;
86
+ }
87
+
88
+
89
+ div#bodyContent {
90
+ padding: 0 1.5em 0 1.5em;
91
+ }
92
+
93
+ div#description {
94
+ padding: 0.5em 1.5em;
95
+ background: #efefef;
96
+ border: 1px dotted #999;
97
+ }
98
+
99
+ div#description h1,h2,h3,h4,h5,h6 {
100
+ color: #125;;
101
+ background: transparent;
102
+ }
103
+
104
+ div#validator-badges {
105
+ text-align: center;
106
+ }
107
+ div#validator-badges img { border: 0; }
108
+
109
+ div#copyright {
110
+ color: #333;
111
+ background: #efefef;
112
+ font: 0.75em sans-serif;
113
+ margin-top: 5em;
114
+ margin-bottom: 0;
115
+ padding: 0.5em 2em;
116
+ }
117
+
118
+
119
+ /* === Classes =================================== */
120
+
121
+ table.header-table {
122
+ color: white;
123
+ font-size: small;
124
+ }
125
+
126
+ .type-note {
127
+ font-size: small;
128
+ color: #DEDEDE;
129
+ }
130
+
131
+ .xxsection-bar {
132
+ background: #eee;
133
+ color: #333;
134
+ padding: 3px;
135
+ }
136
+
137
+ .section-bar {
138
+ color: #333;
139
+ border-bottom: 1px solid #999;
140
+ margin-left: -20px;
141
+ }
142
+
143
+
144
+ .section-title {
145
+ background: #79a;
146
+ color: #eee;
147
+ padding: 3px;
148
+ margin-top: 2em;
149
+ margin-left: -30px;
150
+ border: 1px solid #999;
151
+ }
152
+
153
+ .top-aligned-row { vertical-align: top }
154
+ .bottom-aligned-row { vertical-align: bottom }
155
+
156
+ /* --- Context section classes ----------------------- */
157
+
158
+ .context-row { }
159
+ .context-item-name { font-family: monospace; font-weight: bold; color: black; }
160
+ .context-item-value { font-size: small; color: #448; }
161
+ .context-item-desc { color: #333; padding-left: 2em; }
162
+
163
+ /* --- Method classes -------------------------- */
164
+ .method-detail {
165
+ background: #efefef;
166
+ padding: 0;
167
+ margin-top: 0.5em;
168
+ margin-bottom: 1em;
169
+ border: 1px dotted #ccc;
170
+ }
171
+ .method-heading {
172
+ color: black;
173
+ background: #ccc;
174
+ border-bottom: 1px solid #666;
175
+ padding: 0.2em 0.5em 0 0.5em;
176
+ }
177
+ .method-signature { color: black; background: inherit; }
178
+ .method-name { font-weight: bold; }
179
+ .method-args { font-style: italic; }
180
+ .method-description { padding: 0 0.5em 0 0.5em; }
181
+
182
+ /* --- Source code sections -------------------- */
183
+
184
+ a.source-toggle { font-size: 90%; }
185
+ div.method-source-code {
186
+ background: #262626;
187
+ color: #ffdead;
188
+ margin: 1em;
189
+ padding: 0.5em;
190
+ border: 1px dashed #999;
191
+ overflow: hidden;
192
+ }
193
+
194
+ div.method-source-code pre { color: #ffdead; overflow: hidden; }
195
+
196
+ /* --- Ruby keyword styles --------------------- */
197
+
198
+ .standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
199
+
200
+ .ruby-constant { color: #7fffd4; background: transparent; }
201
+ .ruby-keyword { color: #00ffff; background: transparent; }
202
+ .ruby-ivar { color: #eedd82; background: transparent; }
203
+ .ruby-operator { color: #00ffee; background: transparent; }
204
+ .ruby-identifier { color: #ffdead; background: transparent; }
205
+ .ruby-node { color: #ffa07a; background: transparent; }
206
+ .ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
207
+ .ruby-regexp { color: #ffa07a; background: transparent; }
208
+ .ruby-value { color: #7fffd4; background: transparent; }
@@ -0,0 +1,35 @@
1
+ # A class, as the name suggests, to setup and expected result set.
2
+ #
3
+ # Typical usage
4
+ # expected = ExpectedResultSet.new
5
+ # expected.columns = ['first_column_name', 'second_column_name']
6
+ # expected.rows << [ 'first item', 1 ]
7
+ # expected.rows << [ 'second item', 2 ]
8
+ class ExpectedResultSet
9
+ attr_reader :rows, :columns
10
+
11
+ def initialize
12
+ @rows = []
13
+ end
14
+
15
+ # columns should be given an array of strings.
16
+ def columns=(value)
17
+ @columns = value.map {|entry| entry.to_s}
18
+ end
19
+
20
+ def row_hash(index)
21
+ return to_hash( @rows[index] )
22
+ end
23
+
24
+ def row_hashes
25
+ return rows.collect { |row| to_hash(row) }
26
+ end
27
+
28
+ private
29
+
30
+ def to_hash(row)
31
+ result = {}
32
+ columns.each_with_index { |column, i| result[column] = row[i] }
33
+ return result
34
+ end
35
+ end
data/lib/marjoree.rb ADDED
@@ -0,0 +1,344 @@
1
+ require 'odbc'
2
+ require 'result_set_wrapper'
3
+ require 'odbc_overrides'
4
+
5
+ #This is the main Marjoree mixin.
6
+ # Before you call anything you will need to call 'connect' or no messages will reach your DB :o)
7
+ # You might like to stick something like this in your test code to ensure the connection is dropped when you are finished.
8
+ # Kernel.at_exit { disconnect }
9
+ module Marjoree
10
+ # Establish a connection to dataserver.
11
+ def connect( odbc_name, username, password )
12
+ $db = ODBC.connect(odbc_name, username, password )
13
+ puts "Connected"
14
+ end
15
+
16
+ # Remove connection to dataserver.
17
+ def disconnect
18
+ $db.drop_all
19
+ $db.disconnect
20
+ puts "Disconnected"
21
+ end
22
+
23
+ # Run Store Procedure 'proc_name'
24
+ #
25
+ # The input_param_map takes the form of
26
+ # { :procedure_input_param_name => procedure_input_param_value }
27
+ # eg:
28
+ # result_set = EXEC 'proc_name' @procedure_input_param_name = procedure_input_param_value
29
+ #
30
+ # If a proc has output parameters these are automatically bound onto the ResultSetWrapper object.
31
+ # eg:
32
+ # assert_equal( expected_output_parameter_value, result_set.output_parameter_name )
33
+ def run_sproc( proc_name, input_param_map={} )
34
+ if has_output_params?( proc_name )
35
+ return run_complex_sproc( proc_name, input_param_map )
36
+ else
37
+ return run_simple_sproc( proc_name, input_param_map )
38
+ end
39
+ end
40
+
41
+ # Performs a select * on table_name
42
+ def select( table_name )
43
+ return ResultSetWrapper.new( execute( "SELECT * FROM #{table_name}" ) )
44
+ end
45
+
46
+ # Provides the number of rows in table 'table_name'.
47
+ #
48
+ # The where_map entries are AND'ed together eg:
49
+ # { :table_column_name_one => 1,
50
+ # :table_column_name_two => 2 }
51
+ # would produce
52
+ # SELECT
53
+ # *
54
+ # FROM
55
+ # table_name
56
+ # WHERE
57
+ # table_column_name_one = 1
58
+ # AND table_column_name_two = 2
59
+ def num_rows( table_name, where_map = nil )
60
+ where_clause = build_where_statement( where_map )
61
+ dbCall = execute( "SELECT COUNT(*) FROM #{table_name} #{where_clause}" )
62
+ return dbCall.to_a[0][0]
63
+ end
64
+
65
+ # Does the same as num_rows
66
+ def count( table_name, where_map = nil )
67
+ return num_rows( table_name, where_map )
68
+ end
69
+
70
+ # Returns true if table 'table_name' contains the data specified in the where_map.
71
+ #
72
+ # 'where_map' supplies column_name_as_sym => value
73
+ #
74
+ # These are AND'ed together.
75
+ def contains?( table_name, where_map={} )
76
+ return count( table_name, where_map ) > 0
77
+ end
78
+
79
+ # Performs an INSERT INTO 'table_name'.
80
+ # 'value_map' supplies column_name_as_sym => value
81
+ def insert( table_name, value_map={} )
82
+ columns = build_column_headers(value_map )
83
+ values = build_column_values( value_map)
84
+
85
+ execute( "INSERT INTO #{table_name} (#{columns}) VALUES (#{values})" )
86
+ end
87
+
88
+ # Performs an UPDATE 'table_name'
89
+ #
90
+ # 'where_map' supplies column_name_as_sym => value for the WHERE section of the UPDATE statement.
91
+ #
92
+ # These are AND'ed together.
93
+ #
94
+ # 'set_map' supplies column_name_as_sym => value for the SET section of the UPDATE statement.
95
+ def update( table_name, where_map={}, set_map={} )
96
+ where_clause = build_where_statement( where_map )
97
+ assignments = build_set_statement( set_map )
98
+ execute( "UPDATE #{table_name} SET #{assignments} #{where_clause}" )
99
+ end
100
+
101
+ # Performs an DELETE FROM 'table_name'
102
+ #
103
+ # 'where_map' supplies column_name_as_sym => value for the WHERE section of the UPDATE statement.
104
+ #
105
+ # These are AND'ed together.
106
+ def delete( table_name, where_map={} )
107
+ where_clause = build_where_statement( where_map )
108
+ execute( "DELETE FROM #{table_name} #{where_clause}" )
109
+ end
110
+
111
+ # Performs an TRUNCATE TABLE 'table_name'
112
+ def truncate( table_name )
113
+ execute( "TRUNCATE TABLE #{table_name}" )
114
+ end
115
+
116
+ # Asserts that the ResultSetWrapper is empty
117
+ def assert_empty( result_set )
118
+ assert_equal( 0, result_set.hashes.size )
119
+ end
120
+
121
+ # Asserts that the values in the ExpectedResultSet are contained within the actual ResultSetWrapper.
122
+ def assert_results( expected, result_set )
123
+ assert_column_headers( expected, result_set )
124
+ assert_row_data( expected, result_set )
125
+ end
126
+
127
+ # Asserts that the values in the ExpectedResultSet are NOT contained within the actual ResultSetWrapper.
128
+ def assert_not_equal_results( expected, result_set )
129
+ flag1 = !has_column_headers?(expected, result_set)
130
+ flag2 = !has_correct_data?(expected, result_set)
131
+
132
+ assert( !flag1 || !has_correct_data?(expected, result_set) )
133
+ end
134
+
135
+ # Asserts that an expected_error_code and error_message are returned when running the block.
136
+ def assert_error_thrown( expected_error_code, expected_error_message )
137
+ begin
138
+ yield
139
+ fail
140
+ rescue ODBC::Error
141
+ exception = $!
142
+
143
+ assert_equal( expected_error_code, exception.error_code )
144
+ assert_equal( expected_error_message, exception.error_message )
145
+ end
146
+ end
147
+
148
+ # Asserts when the DB throws an error.
149
+ #
150
+ # ie: Inserting into a table that does not exist.
151
+ def assert_db_error
152
+ begin
153
+ yield
154
+ fail
155
+ rescue ODBC::Error
156
+ end
157
+ end
158
+
159
+ def has_column_headers?( expected, result_set )
160
+ begin
161
+ assert_column_headers( expected, result_set )
162
+ return true
163
+ rescue
164
+ return false
165
+ end
166
+ end
167
+
168
+ def has_correct_data?( expected, result_set )
169
+
170
+ begin
171
+ assert_row_data( expected, result_set )
172
+ return true
173
+ rescue
174
+ return false
175
+ end
176
+ end
177
+
178
+ # Helpful Assert that wraps the contains? method.
179
+ def assert_contains( table_name, value_map )
180
+ assert( contains?( table_name, value_map ) )
181
+ end
182
+
183
+ # Helpful Assert that wraps the contains? method.
184
+ def assert_does_not_contain( table_name, value_map )
185
+ assert( !contains?( table_name, value_map ) )
186
+ end
187
+
188
+ # Executes raw sql against the db.
189
+ def execute( sql )
190
+ dbCall = $db.prepare( sql )
191
+ begin
192
+ dbCall.execute
193
+ rescue
194
+ raise ODBC::Error.new("Failed executing: #{sql}\nDue to: #{$!}")
195
+ end
196
+
197
+ return dbCall
198
+ end
199
+
200
+ private
201
+
202
+ def build_set_statement( map )
203
+ pairs = []
204
+ map.each { |key, value| pairs << "#{key} = #{value}" }
205
+ return pairs.join(", ")
206
+ end
207
+
208
+
209
+ def build_column_values( map )
210
+ return map.values.collect {|v| display_value_for v }.join(", ")
211
+ end
212
+
213
+
214
+ def build_input_parameter_statement( map )
215
+ pairs = []
216
+ map.each { |key, value| pairs << "@#{key.to_s} = #{display_value_for( value )}" }
217
+ return pairs.join(", ")
218
+ end
219
+
220
+ def build_column_headers( map )
221
+ return map.keys.join(", ")
222
+ end
223
+
224
+ def build_where_statement( map )
225
+ if map.nil?
226
+ return ''
227
+ end
228
+
229
+ pairs = []
230
+ map.each { |key, value| pairs << "#{key} = #{display_value_for( value ) }" }
231
+ expression = pairs.join(" AND ")
232
+ if map.size > 0
233
+ expression = " WHERE #{expression}"
234
+ end
235
+
236
+ return expression
237
+ end
238
+
239
+ def display_value_for( value )
240
+ return value.is_a?(Numeric) ? value : "'#{value}'"
241
+ end
242
+
243
+ def assert_column_headers( expected, result_set )
244
+ expected.columns.each do |expected_column_header|
245
+ actual_column_headers = result_set.columns.keys
246
+ formatted_actual_headers = actual_column_headers.join( " \n\t" )
247
+ errorMessage = "\nColumn Header: '#{expected_column_header}' does not exist.\nActual Column Headers available are \n\t#{formatted_actual_headers}\n"
248
+ assert( actual_column_headers.include?( expected_column_header ), errorMessage )
249
+ end
250
+ end
251
+
252
+ def assert_row_data( expected, result_set )
253
+ result = result_set.has?( expected )
254
+
255
+ possibleErrorMessage = "\nExpected: #{expected.row_hashes.inspect}\nActual: [#{actual_values( result_set )}]\n"
256
+
257
+ assert( result, possibleErrorMessage )
258
+ end
259
+
260
+ def actual_values( result_set )
261
+ actual_values = []
262
+ result_set.hashes.each { |hash| actual_values << hash.inspect }
263
+ formatted_actual_values = actual_values.join( ", " )
264
+ end
265
+
266
+ def has_output_params?( proc_name )
267
+ dbCall = $db.procedure_columns proc_name
268
+ result_set = ResultSetWrapper.new( dbCall )
269
+ return result_set.contains?( { :COLUMN_TYPE => 4 } )
270
+ end
271
+
272
+
273
+ def build_output_parameter_statement( list )
274
+ result = []
275
+ list.each { |hash| result << "#{hash[:COLUMN_NAME]} = #{hash[:COLUMN_NAME]} output" }
276
+ return result.join(", ")
277
+ end
278
+
279
+ def run_complex_sproc( proc_name, input_param_map )
280
+ output_param_data = get_output_params proc_name
281
+ output_params = output_param_names( output_param_data )
282
+
283
+ sql = build_sql_for_sproc_with_output_params( proc_name, input_param_map, output_param_data )
284
+
285
+ return ResultSetWrapper.new( execute( sql ), output_params )
286
+ end
287
+
288
+ def build_sql_for_sproc_with_output_params( proc_name, input_param_map, output_params )
289
+ sproc_input_param_text = build_input_parameter_statement( input_param_map )
290
+ sproc_output_param_text = build_output_parameter_statement( output_params )
291
+ sproc_input_param_text << "," unless input_param_map.empty?
292
+
293
+ sql = build_output_declarations( output_params )
294
+ sql << "EXEC #{proc_name} #{sproc_input_param_text} #{sproc_output_param_text}\n"
295
+ output_params.each { |hash| sql << "SELECT #{hash[:COLUMN_NAME]}\n" }
296
+
297
+ return sql
298
+ end
299
+
300
+ def output_param_names( output_params )
301
+ result = []
302
+ output_params.each{ |hash| result << hash[:COLUMN_NAME] }
303
+
304
+ return result
305
+ end
306
+
307
+ def build_output_declarations output_params
308
+ result = ""
309
+ output_params.each do |hash|
310
+ type_declaration = format_type_declaration( hash )
311
+ result << "DECLARE #{hash[:COLUMN_NAME]} #{type_declaration}\n"
312
+ end
313
+
314
+ return result
315
+ end
316
+
317
+ def format_type_declaration( hash )
318
+ column_type = hash[:TYPE_NAME]
319
+ if column_type == 'varchar'
320
+ return "#{column_type}(#{hash[:COLUMN_SIZE]})"
321
+ end
322
+
323
+ return column_type
324
+ end
325
+
326
+ def get_output_params( proc_name )
327
+ dbCall = $db.procedure_columns proc_name
328
+ result_set = ResultSetWrapper.new( dbCall )
329
+ result = []
330
+ result_set.collect do |hash|
331
+ if hash[:COLUMN_TYPE] == 4 #varchar
332
+ result << hash
333
+ end
334
+ end
335
+
336
+ return result
337
+ end
338
+
339
+ def run_simple_sproc( proc_name, map={} )
340
+ input_param_text = build_input_parameter_statement( map )
341
+ sql = "EXEC #{proc_name} #{input_param_text }"
342
+ return ResultSetWrapper.new( execute( sql ) )
343
+ end
344
+ end