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.
- data/README +50 -0
- data/examples/contains_example.rb +23 -0
- data/examples/count_and_insert_example.rb +20 -0
- data/examples/select_example.rb +27 -0
- data/html/classes/ExpectedResultSet.html +220 -0
- data/html/classes/ExpectedResultSet.src/M000001.html +18 -0
- data/html/classes/ExpectedResultSet.src/M000002.html +18 -0
- data/html/classes/ExpectedResultSet.src/M000003.html +18 -0
- data/html/classes/ExpectedResultSet.src/M000004.html +18 -0
- data/html/classes/Marjoree.html +568 -0
- data/html/classes/Marjoree.src/M000022.html +19 -0
- data/html/classes/Marjoree.src/M000023.html +20 -0
- data/html/classes/Marjoree.src/M000024.html +22 -0
- data/html/classes/Marjoree.src/M000025.html +18 -0
- data/html/classes/Marjoree.src/M000026.html +20 -0
- data/html/classes/Marjoree.src/M000027.html +18 -0
- data/html/classes/Marjoree.src/M000028.html +18 -0
- data/html/classes/Marjoree.src/M000029.html +21 -0
- data/html/classes/Marjoree.src/M000030.html +20 -0
- data/html/classes/Marjoree.src/M000031.html +19 -0
- data/html/classes/Marjoree.src/M000032.html +18 -0
- data/html/classes/Marjoree.src/M000033.html +18 -0
- data/html/classes/Marjoree.src/M000034.html +19 -0
- data/html/classes/Marjoree.src/M000035.html +21 -0
- data/html/classes/Marjoree.src/M000036.html +26 -0
- data/html/classes/Marjoree.src/M000037.html +22 -0
- data/html/classes/Marjoree.src/M000038.html +23 -0
- data/html/classes/Marjoree.src/M000039.html +24 -0
- data/html/classes/Marjoree.src/M000040.html +18 -0
- data/html/classes/Marjoree.src/M000041.html +18 -0
- data/html/classes/Marjoree.src/M000042.html +25 -0
- data/html/classes/ODBC/Error.html +152 -0
- data/html/classes/ODBC/Error.src/M000020.html +21 -0
- data/html/classes/ODBC/Error.src/M000021.html +18 -0
- data/html/classes/ODBC/TimeStamp.html +182 -0
- data/html/classes/ODBC/TimeStamp.src/M000017.html +18 -0
- data/html/classes/ODBC/TimeStamp.src/M000018.html +22 -0
- data/html/classes/ODBC/TimeStamp.src/M000019.html +19 -0
- data/html/classes/ODBC.html +108 -0
- data/html/classes/ResultSetWrapper.html +345 -0
- data/html/classes/ResultSetWrapper.src/M000005.html +27 -0
- data/html/classes/ResultSetWrapper.src/M000006.html +24 -0
- data/html/classes/ResultSetWrapper.src/M000007.html +23 -0
- data/html/classes/ResultSetWrapper.src/M000008.html +18 -0
- data/html/classes/ResultSetWrapper.src/M000009.html +18 -0
- data/html/classes/ResultSetWrapper.src/M000010.html +18 -0
- data/html/classes/ResultSetWrapper.src/M000011.html +18 -0
- data/html/classes/ResultSetWrapper.src/M000012.html +20 -0
- data/html/classes/ResultSetWrapper.src/M000013.html +18 -0
- data/html/classes/ResultSetWrapper.src/M000014.html +22 -0
- data/html/classes/ResultSetWrapper.src/M000015.html +23 -0
- data/html/classes/ResultSetWrapper.src/M000016.html +27 -0
- data/html/created.rid +1 -0
- data/html/files/README.html +159 -0
- data/html/files/lib/expected_result_set_rb.html +116 -0
- data/html/files/lib/marjoree_rb.html +110 -0
- data/html/files/lib/odbc_overrides_rb.html +101 -0
- data/html/files/lib/result_set_wrapper_rb.html +101 -0
- data/html/fr_class_index.html +32 -0
- data/html/fr_file_index.html +31 -0
- data/html/fr_method_index.html +68 -0
- data/html/index.html +24 -0
- data/html/rdoc-style.css +208 -0
- data/lib/expected_result_set.rb +35 -0
- data/lib/marjoree.rb +344 -0
- data/lib/odbc_overrides.rb +33 -0
- data/lib/result_set_wrapper.rb +193 -0
- data/rakefile.rb +38 -0
- data/tests/all_tests.rb +15 -0
- data/tests/sprocs/test_error_sproc.sp +11 -0
- data/tests/sprocs/test_sproc.sp +5 -0
- data/tests/sprocs/test_sproc_with_mixed_params.sp +15 -0
- data/tests/sprocs/test_sproc_with_output_params.sp +10 -0
- data/tests/sprocs/test_sproc_with_params.sp +9 -0
- data/tests/sprocs/test_sproc_with_select_and_ops.sp +12 -0
- data/tests/test_contains.rb +27 -0
- data/tests/test_delete.rb +47 -0
- data/tests/test_expected_result_set.rb +40 -0
- data/tests/test_insert.rb +47 -0
- data/tests/test_marjoree.rb +91 -0
- data/tests/test_num_rows.rb +32 -0
- data/tests/test_result_set_wrapper.rb +162 -0
- data/tests/test_select.rb +30 -0
- data/tests/test_sproc.rb +99 -0
- data/tests/test_time_stamp.rb +52 -0
- data/tests/test_truncate.rb +31 -0
- data/tests/test_update.rb +56 -0
- 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>
|
data/html/rdoc-style.css
ADDED
|
@@ -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
|