slacker 1.0.14 → 1.0.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -4
- data/README.markdown +22 -22
- data/Rakefile +11 -11
- data/bin/slacker +32 -32
- data/bin/slacker_new +34 -34
- data/lib/slacker.rb +180 -175
- data/lib/slacker/application.rb +224 -214
- data/lib/slacker/command_line_formatter.rb +61 -61
- data/lib/slacker/configuration.rb +59 -59
- data/lib/slacker/formatter.rb +14 -14
- data/lib/slacker/query_result_matcher.rb +178 -178
- data/lib/slacker/rspec_ext.rb +57 -57
- data/lib/slacker/rspec_monkey.rb +7 -7
- data/lib/slacker/sql.rb +39 -39
- data/lib/slacker/sql_preprocessor.rb +23 -23
- data/lib/slacker/string_helper.rb +16 -16
- data/lib/slacker/version.rb +3 -3
- data/lib/slacker_new/project/data/sample_1/my_table_expected_power_results.csv +11 -11
- data/lib/slacker_new/project/data/sample_1/my_table_initial_data.csv +11 -11
- data/lib/slacker_new/project/data/sample_1/numbers_expected_output.csv +3 -3
- data/lib/slacker_new/project/database.yml +9 -9
- data/lib/slacker_new/project/lib/helpers/my_helper.rb +1 -1
- data/lib/slacker_new/project/spec/sample_1.rb +66 -66
- data/lib/slacker_new/project/sql/sample_1/my_table_on_power.sql.erb +1 -1
- data/lib/slacker_new/project/sql/sample_1/play_with_numbers.sql.erb +16 -16
- data/lib/slacker_new/project/sql/sample_1/sysobjects_with_params.sql.erb +1 -1
- data/slacker.gemspec +27 -27
- data/spec/application_spec.rb +13 -13
- data/spec/query_result_matcher_spec.rb +268 -268
- data/spec/rspec_ext_spec.rb +87 -87
- data/spec/slacker_spec.rb +59 -59
- data/spec/spec_helper.rb +19 -9
- data/spec/test_files/matcher/test_1.csv +3 -3
- data/spec/test_files/test_slacker_project/data/test_1.csv +3 -3
- data/spec/test_files/test_slacker_project/sql/nest/nested_1.sql.erb +1 -1
- data/spec/test_files/test_slacker_project/sql/no_params.sql.erb +2 -2
- data/spec/test_files/test_slacker_project/sql/params.sql.erb +1 -1
- metadata +24 -24
data/lib/slacker/rspec_ext.rb
CHANGED
@@ -1,57 +1,57 @@
|
|
1
|
-
require 'slacker'
|
2
|
-
require 'slacker/query_result_matcher'
|
3
|
-
require 'csv'
|
4
|
-
|
5
|
-
module Slacker
|
6
|
-
module RSpecExt
|
7
|
-
|
8
|
-
# Execute a SQL query or the contents of a query template query file
|
9
|
-
# In case of a query file, it passes the options to the template
|
10
|
-
def query(query_string, options = {}, log_name = nil)
|
11
|
-
log_name ||= Slacker.construct_log_name('query', query_string, options)
|
12
|
-
sql = Slacker.sql_from_query_string(query_string, options)
|
13
|
-
@results = Slacker.query_script(example, sql, log_name)
|
14
|
-
if block_given?
|
15
|
-
yield @results
|
16
|
-
end
|
17
|
-
@results
|
18
|
-
end
|
19
|
-
|
20
|
-
# Exposes a reference to the sql object, which represents the contents of the SQL folder
|
21
|
-
def sql
|
22
|
-
Slacker.sql(self)
|
23
|
-
end
|
24
|
-
|
25
|
-
# Get a matcher which will compare the query results to a golden master
|
26
|
-
def match(golden_master)
|
27
|
-
QueryResultMatcher.new(Slacker.filter_golden_master(golden_master))
|
28
|
-
end
|
29
|
-
|
30
|
-
# Loads a CSV file and returns a reference to it
|
31
|
-
# The file is relative to the data folder of the Slacker project
|
32
|
-
def csv(csv_file)
|
33
|
-
Slacker.get_csv(csv_file)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Generate CSV::Table objects with an arbitrary number of records populated with data based on a template CSV file
|
37
|
-
def touch_csv(csv_file_or_object, fields, field_generators = {})
|
38
|
-
Slacker.touch_csv(csv_file_or_object, fields, field_generators)
|
39
|
-
end
|
40
|
-
|
41
|
-
# Load a CSV file directly into a table in the target database
|
42
|
-
def load_csv(csv_file_or_object, table_name, log_name = nil)
|
43
|
-
log_name ||= "load_csv '#{csv_file_or_object.kind_of?(CSV::Table) ? 'CSV Object' : csv_file_or_object }', 'table_name'"
|
44
|
-
csv_object = case csv_file_or_object
|
45
|
-
when String then Slacker.get_csv(csv_file_or_object)
|
46
|
-
when CSV::Table then csv_file_or_object
|
47
|
-
when Array then Slacker.hash_array_to_csv(csv_file_or_object)
|
48
|
-
end
|
49
|
-
|
50
|
-
Slacker.load_csv(example, csv_object, table_name, log_name)
|
51
|
-
end
|
52
|
-
|
53
|
-
def yes?(val)
|
54
|
-
val != nil && val.downcase == 'yes'
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
1
|
+
require 'slacker'
|
2
|
+
require 'slacker/query_result_matcher'
|
3
|
+
require 'csv'
|
4
|
+
|
5
|
+
module Slacker
|
6
|
+
module RSpecExt
|
7
|
+
|
8
|
+
# Execute a SQL query or the contents of a query template query file
|
9
|
+
# In case of a query file, it passes the options to the template
|
10
|
+
def query(query_string, options = {}, log_name = nil)
|
11
|
+
log_name ||= Slacker.construct_log_name('query', query_string, options)
|
12
|
+
sql = Slacker.sql_from_query_string(query_string, options)
|
13
|
+
@results = Slacker.query_script(example, sql, log_name)
|
14
|
+
if block_given?
|
15
|
+
yield @results
|
16
|
+
end
|
17
|
+
@results
|
18
|
+
end
|
19
|
+
|
20
|
+
# Exposes a reference to the sql object, which represents the contents of the SQL folder
|
21
|
+
def sql
|
22
|
+
Slacker.sql(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Get a matcher which will compare the query results to a golden master
|
26
|
+
def match(golden_master)
|
27
|
+
QueryResultMatcher.new(Slacker.filter_golden_master(golden_master))
|
28
|
+
end
|
29
|
+
|
30
|
+
# Loads a CSV file and returns a reference to it
|
31
|
+
# The file is relative to the data folder of the Slacker project
|
32
|
+
def csv(csv_file)
|
33
|
+
Slacker.get_csv(csv_file)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Generate CSV::Table objects with an arbitrary number of records populated with data based on a template CSV file
|
37
|
+
def touch_csv(csv_file_or_object, fields, field_generators = {})
|
38
|
+
Slacker.touch_csv(csv_file_or_object, fields, field_generators)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Load a CSV file directly into a table in the target database
|
42
|
+
def load_csv(csv_file_or_object, table_name, log_name = nil)
|
43
|
+
log_name ||= "load_csv '#{csv_file_or_object.kind_of?(CSV::Table) ? 'CSV Object' : csv_file_or_object }', 'table_name'"
|
44
|
+
csv_object = case csv_file_or_object
|
45
|
+
when String then Slacker.get_csv(csv_file_or_object)
|
46
|
+
when CSV::Table then csv_file_or_object
|
47
|
+
when Array then Slacker.hash_array_to_csv(csv_file_or_object)
|
48
|
+
end
|
49
|
+
|
50
|
+
Slacker.load_csv(example, csv_object, table_name, log_name)
|
51
|
+
end
|
52
|
+
|
53
|
+
def yes?(val)
|
54
|
+
val != nil && val.downcase == 'yes'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/slacker/rspec_monkey.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
# Monkeypatch a method to reset RSpec
|
2
|
-
module RSpec
|
3
|
-
def self.slacker_reset
|
4
|
-
@world = nil
|
5
|
-
@configuration = nil
|
6
|
-
end
|
7
|
-
end
|
1
|
+
# Monkeypatch a method to reset RSpec
|
2
|
+
module RSpec
|
3
|
+
def self.slacker_reset
|
4
|
+
@world = nil
|
5
|
+
@configuration = nil
|
6
|
+
end
|
7
|
+
end
|
data/lib/slacker/sql.rb
CHANGED
@@ -1,39 +1,39 @@
|
|
1
|
-
require 'slacker'
|
2
|
-
require 'slacker/rspec_ext'
|
3
|
-
|
4
|
-
module Slacker
|
5
|
-
class Sql < BasicObject
|
6
|
-
attr_accessor :base_folder, :rspec_ext
|
7
|
-
|
8
|
-
def initialize(base_folder, rspec_ext)
|
9
|
-
@base_folder = base_folder
|
10
|
-
@rspec_ext = rspec_ext
|
11
|
-
end
|
12
|
-
|
13
|
-
def method_missing(method_name, *params, &block)
|
14
|
-
::Kernel.raise "Slacker::Sql.rspec_ext not initialized" if rspec_ext.nil?
|
15
|
-
::Kernel.raise "Missing folder #{base_folder}" if !::File.directory?(base_folder)
|
16
|
-
|
17
|
-
method_name = method_name.to_s
|
18
|
-
|
19
|
-
if ::File.directory?(::File.join(base_folder, method_name))
|
20
|
-
::Slacker::Sql.new(::File.join(base_folder, method_name), rspec_ext)
|
21
|
-
else
|
22
|
-
sql_file = ::Slacker.sql_file_from_method_name(base_folder, method_name)
|
23
|
-
case sql_file
|
24
|
-
when nil
|
25
|
-
::Kernel.raise "No SQL file found corresponding to method '#{method_name}' in folder #{base_folder}"
|
26
|
-
else
|
27
|
-
rspec_ext.query sql_file, *params, &block
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def respond_to?(method_name)
|
33
|
-
method_name = method_name.to_s
|
34
|
-
::Kernel.raise "Slacker::Sql.rspec_ext not initialized" if rspec_ext.nil?
|
35
|
-
::File.directory?(::File.join(base_folder, method_name)) ||
|
36
|
-
!(::Slacker.sql_file_from_method_name(base_folder, method_name).nil?)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
1
|
+
require 'slacker'
|
2
|
+
require 'slacker/rspec_ext'
|
3
|
+
|
4
|
+
module Slacker
|
5
|
+
class Sql < BasicObject
|
6
|
+
attr_accessor :base_folder, :rspec_ext
|
7
|
+
|
8
|
+
def initialize(base_folder, rspec_ext)
|
9
|
+
@base_folder = base_folder
|
10
|
+
@rspec_ext = rspec_ext
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(method_name, *params, &block)
|
14
|
+
::Kernel.raise "Slacker::Sql.rspec_ext not initialized" if rspec_ext.nil?
|
15
|
+
::Kernel.raise "Missing folder #{base_folder}" if !::File.directory?(base_folder)
|
16
|
+
|
17
|
+
method_name = method_name.to_s
|
18
|
+
|
19
|
+
if ::File.directory?(::File.join(base_folder, method_name))
|
20
|
+
::Slacker::Sql.new(::File.join(base_folder, method_name), rspec_ext)
|
21
|
+
else
|
22
|
+
sql_file = ::Slacker.sql_file_from_method_name(base_folder, method_name)
|
23
|
+
case sql_file
|
24
|
+
when nil
|
25
|
+
::Kernel.raise "No SQL file found corresponding to method '#{method_name}' in folder #{base_folder}"
|
26
|
+
else
|
27
|
+
rspec_ext.query sql_file, *params, &block
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def respond_to?(method_name)
|
33
|
+
method_name = method_name.to_s
|
34
|
+
::Kernel.raise "Slacker::Sql.rspec_ext not initialized" if rspec_ext.nil?
|
35
|
+
::File.directory?(::File.join(base_folder, method_name)) ||
|
36
|
+
!(::Slacker.sql_file_from_method_name(base_folder, method_name).nil?)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,24 +1,24 @@
|
|
1
|
-
module Slacker
|
2
|
-
module SqlPreprocessor
|
3
|
-
IVAR_REX = /%{\s*(.*?)\s*}/
|
4
|
-
|
5
|
-
def self.executable_sql(sql, example)
|
6
|
-
# Replace all appearances of %{} with the values of the corresponding example instance variables
|
7
|
-
sql.gsub(IVAR_REX) do
|
8
|
-
ivar = $1.to_sym
|
9
|
-
instance = example.example_group_instance
|
10
|
-
|
11
|
-
if instance.instance_variable_defined?(ivar)
|
12
|
-
instance.instance_variable_get(ivar).to_s
|
13
|
-
else
|
14
|
-
raise "Example is missing instance variable #{ivar}"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.debuggable_sql(sql)
|
20
|
-
# Replace all appearances of %{} with the names of the sql variables
|
21
|
-
sql.gsub(IVAR_REX) {$1}
|
22
|
-
end
|
23
|
-
end
|
1
|
+
module Slacker
|
2
|
+
module SqlPreprocessor
|
3
|
+
IVAR_REX = /%{\s*(.*?)\s*}/
|
4
|
+
|
5
|
+
def self.executable_sql(sql, example)
|
6
|
+
# Replace all appearances of %{} with the values of the corresponding example instance variables
|
7
|
+
sql.gsub(IVAR_REX) do
|
8
|
+
ivar = $1.to_sym
|
9
|
+
instance = example.example_group_instance
|
10
|
+
|
11
|
+
if instance.instance_variable_defined?(ivar)
|
12
|
+
instance.instance_variable_get(ivar).to_s
|
13
|
+
else
|
14
|
+
raise "Example is missing instance variable #{ivar}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.debuggable_sql(sql)
|
20
|
+
# Replace all appearances of %{} with the names of the sql variables
|
21
|
+
sql.gsub(IVAR_REX) {$1}
|
22
|
+
end
|
23
|
+
end
|
24
24
|
end
|
@@ -1,17 +1,17 @@
|
|
1
|
-
module Slacker
|
2
|
-
module StringHelper
|
3
|
-
class << self
|
4
|
-
def camelize(lower_case_and_underscored_word)
|
5
|
-
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
6
|
-
end
|
7
|
-
|
8
|
-
def constantize(camel_cased_word)
|
9
|
-
unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
|
10
|
-
raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
|
11
|
-
end
|
12
|
-
|
13
|
-
Object.module_eval("::#{$1}", __FILE__, __LINE__)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
1
|
+
module Slacker
|
2
|
+
module StringHelper
|
3
|
+
class << self
|
4
|
+
def camelize(lower_case_and_underscored_word)
|
5
|
+
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
6
|
+
end
|
7
|
+
|
8
|
+
def constantize(camel_cased_word)
|
9
|
+
unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
|
10
|
+
raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
|
11
|
+
end
|
12
|
+
|
13
|
+
Object.module_eval("::#{$1}", __FILE__, __LINE__)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
17
|
end
|
data/lib/slacker/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module Slacker
|
2
|
-
VERSION = "1.0.
|
3
|
-
end
|
1
|
+
module Slacker
|
2
|
+
VERSION = "1.0.15"
|
3
|
+
end
|
@@ -1,11 +1,11 @@
|
|
1
|
-
"x","y","power"
|
2
|
-
"2","1","2"
|
3
|
-
"3","2","9"
|
4
|
-
"4","3","64"
|
5
|
-
"5","4","625"
|
6
|
-
"4","2","16"
|
7
|
-
"3","3","27"
|
8
|
-
"2","4","16"
|
9
|
-
"1","5","1"
|
10
|
-
"-1","2","1"
|
11
|
-
"-2","5","-32"
|
1
|
+
"x","y","power"
|
2
|
+
"2","1","2"
|
3
|
+
"3","2","9"
|
4
|
+
"4","3","64"
|
5
|
+
"5","4","625"
|
6
|
+
"4","2","16"
|
7
|
+
"3","3","27"
|
8
|
+
"2","4","16"
|
9
|
+
"1","5","1"
|
10
|
+
"-1","2","1"
|
11
|
+
"-2","5","-32"
|
@@ -1,11 +1,11 @@
|
|
1
|
-
"x","y"
|
2
|
-
2,1
|
3
|
-
3,2
|
4
|
-
4,3
|
5
|
-
5,4
|
6
|
-
4,2
|
7
|
-
3,3
|
8
|
-
2,4
|
9
|
-
1,5
|
10
|
-
-1,2
|
11
|
-
-2,5
|
1
|
+
"x","y"
|
2
|
+
2,1
|
3
|
+
3,2
|
4
|
+
4,3
|
5
|
+
5,4
|
6
|
+
4,2
|
7
|
+
3,3
|
8
|
+
2,4
|
9
|
+
1,5
|
10
|
+
-1,2
|
11
|
+
-2,5
|
@@ -1,3 +1,3 @@
|
|
1
|
-
"p","s"
|
2
|
-
2,34
|
3
|
-
12,44
|
1
|
+
"p","s"
|
2
|
+
2,34
|
3
|
+
12,44
|
@@ -1,9 +1,9 @@
|
|
1
|
-
# Database connection.
|
2
|
-
# When Slacker is executed, it will attempt to connect to this database.
|
3
|
-
|
4
|
-
# Replace the following with your connection information.
|
5
|
-
# Note that at this point Slacker only works with SQL Server authentication.
|
6
|
-
server: my_server
|
7
|
-
database: my_database
|
8
|
-
user: user_name
|
9
|
-
password: password
|
1
|
+
# Database connection.
|
2
|
+
# When Slacker is executed, it will attempt to connect to this database.
|
3
|
+
|
4
|
+
# Replace the following with your connection information.
|
5
|
+
# Note that at this point Slacker only works with SQL Server authentication.
|
6
|
+
server: my_server
|
7
|
+
database: my_database
|
8
|
+
user: user_name
|
9
|
+
password: password
|
@@ -1,2 +1,2 @@
|
|
1
|
-
module MyHelper
|
1
|
+
module MyHelper
|
2
2
|
end
|
@@ -1,66 +1,66 @@
|
|
1
|
-
# Method "describe" opens up an example group.
|
2
|
-
describe 'My database' do
|
3
|
-
# Simple inline query example.
|
4
|
-
it 'contains system tables' do
|
5
|
-
# Make sure we have at least one system object in the database.
|
6
|
-
query("select * from sysobjects where xtype = 'S';").count.
|
7
|
-
end
|
8
|
-
|
9
|
-
# The same query, this time using a SQL template stored in file "sql/sample_1/sysobject.sql.erb".
|
10
|
-
it 'contains system tables (take two)' do
|
11
|
-
# Every (*.sql.erb) file in folder "sql" can be called as a method on object "sql".
|
12
|
-
# Subfolders of folder "sql" appear as children of object "sql" with their (*.sql.erb) files automatically available as methods.
|
13
|
-
sql.sample_1.sysobjects.count.
|
14
|
-
end
|
15
|
-
|
16
|
-
# This time we'll use a parameterized template.
|
17
|
-
it 'contains system tables (take three)' do
|
18
|
-
# Every template can accept parameters; see file "sql/sample_1/sysobject_with_params.sql.erb".
|
19
|
-
sql.sample_1.sysobjects_with_params(:xtype => 'S').count.
|
20
|
-
end
|
21
|
-
|
22
|
-
# SQL Templates can contain multiple statements and can return multiple resultsets.
|
23
|
-
it 'can play with numbers' do
|
24
|
-
# Note that this time we're calling the template with a block which receives the results as a block parameter.
|
25
|
-
sql.sample_1.play_with_numbers(:x => 2, :y => 12) do |results|
|
26
|
-
# The results object contains an array of all the resultsets generated by the query script.
|
27
|
-
# A resultset contains an array of records. Each record is a hash of field => value pairs.
|
28
|
-
|
29
|
-
# First resultset; First record; Column "product".
|
30
|
-
results[0][0][:product].
|
31
|
-
|
32
|
-
# A resultset can be matched directly against an array of hashes using method "match".
|
33
|
-
results[1].
|
34
|
-
|
35
|
-
# Or against a CSV file stored in project's "data" folder (see file "data/sample_1/numbers_expected_output.csv").
|
36
|
-
results[2].
|
37
|
-
|
38
|
-
# A resultset's values can be matched one-by-one.
|
39
|
-
results[2][0][:p].
|
40
|
-
results[2][0][:s].
|
41
|
-
results[2][1][:p].
|
42
|
-
results[2][1][:s].
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
# Every "it" (example) is executed in a T-SQL transaction which is rolled back once the example is complete.
|
47
|
-
# No example can ever interfere with the results of another example.
|
48
|
-
#
|
49
|
-
# CSV files can be used to load data directly into a table.
|
50
|
-
# In this example, we will create a table, populate it with data,
|
51
|
-
# calculate the exponentiation of one column based on another column
|
52
|
-
# and verify the results against an expected resultset stored in a CSV file.
|
53
|
-
it 'can play with numbers (take two)' do
|
54
|
-
# Create the table - see file "sql/sample_1/create_my_table.sql.erb".
|
55
|
-
sql.sample_1.create_my_table
|
56
|
-
# We can populate any table with data from the "data" folder by calling method "load_csv".
|
57
|
-
# See file "data/sample_1/my_table_initial_data.csv".
|
58
|
-
load_csv('sample_1/my_table_initial_data.csv', 'MyTable')
|
59
|
-
|
60
|
-
# Now let's test the system scalar function Power.
|
61
|
-
# We will use it in a query expression executed agaings MyTable and we
|
62
|
-
# will compare the results against a CSV file - we should expect them to match.
|
63
|
-
# See files "sql/sample_1/my_table_on_power.sql.erb" and "data/sample_1/my_table_expected_power_results.csv".
|
64
|
-
sql.sample_1.my_table_on_power.
|
65
|
-
end
|
66
|
-
end
|
1
|
+
# Method "describe" opens up an example group.
|
2
|
+
describe 'My database' do
|
3
|
+
# Simple inline query example.
|
4
|
+
it 'contains system tables' do
|
5
|
+
# Make sure we have at least one system object in the database.
|
6
|
+
expect(query("select * from sysobjects where xtype = 'S';").count).to be > 0
|
7
|
+
end
|
8
|
+
|
9
|
+
# The same query, this time using a SQL template stored in file "sql/sample_1/sysobject.sql.erb".
|
10
|
+
it 'contains system tables (take two)' do
|
11
|
+
# Every (*.sql.erb) file in folder "sql" can be called as a method on object "sql".
|
12
|
+
# Subfolders of folder "sql" appear as children of object "sql" with their (*.sql.erb) files automatically available as methods.
|
13
|
+
expect(sql.sample_1.sysobjects.count).to be > 0
|
14
|
+
end
|
15
|
+
|
16
|
+
# This time we'll use a parameterized template.
|
17
|
+
it 'contains system tables (take three)' do
|
18
|
+
# Every template can accept parameters; see file "sql/sample_1/sysobject_with_params.sql.erb".
|
19
|
+
expect(sql.sample_1.sysobjects_with_params(:xtype => 'S').count).to be > 0
|
20
|
+
end
|
21
|
+
|
22
|
+
# SQL Templates can contain multiple statements and can return multiple resultsets.
|
23
|
+
it 'can play with numbers' do
|
24
|
+
# Note that this time we're calling the template with a block which receives the results as a block parameter.
|
25
|
+
sql.sample_1.play_with_numbers(:x => 2, :y => 12) do |results|
|
26
|
+
# The results object contains an array of all the resultsets generated by the query script.
|
27
|
+
# A resultset contains an array of records. Each record is a hash of field => value pairs.
|
28
|
+
|
29
|
+
# First resultset; First record; Column "product".
|
30
|
+
expect(results[0][0][:product]).to be == 24
|
31
|
+
|
32
|
+
# A resultset can be matched directly against an array of hashes using method "match".
|
33
|
+
expect(results[1]).to match([{:x => 2, :y => 12, :sum => 14}])
|
34
|
+
|
35
|
+
# Or against a CSV file stored in project's "data" folder (see file "data/sample_1/numbers_expected_output.csv").
|
36
|
+
expect(results[2]).to match('sample_1/numbers_expected_output.csv')
|
37
|
+
|
38
|
+
# A resultset's values can be matched one-by-one.
|
39
|
+
expect(results[2][0][:p]).to be == 2
|
40
|
+
expect(results[2][0][:s]).to be == 34
|
41
|
+
expect(results[2][1][:p]).to be == 12
|
42
|
+
expect(results[2][1][:s]).to be == 44
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Every "it" (example) is executed in a T-SQL transaction which is rolled back once the example is complete.
|
47
|
+
# No example can ever interfere with the results of another example.
|
48
|
+
#
|
49
|
+
# CSV files can be used to load data directly into a table.
|
50
|
+
# In this example, we will create a table, populate it with data,
|
51
|
+
# calculate the exponentiation of one column based on another column
|
52
|
+
# and verify the results against an expected resultset stored in a CSV file.
|
53
|
+
it 'can play with numbers (take two)' do
|
54
|
+
# Create the table - see file "sql/sample_1/create_my_table.sql.erb".
|
55
|
+
sql.sample_1.create_my_table
|
56
|
+
# We can populate any table with data from the "data" folder by calling method "load_csv".
|
57
|
+
# See file "data/sample_1/my_table_initial_data.csv".
|
58
|
+
load_csv('sample_1/my_table_initial_data.csv', 'MyTable')
|
59
|
+
|
60
|
+
# Now let's test the system scalar function Power.
|
61
|
+
# We will use it in a query expression executed agaings MyTable and we
|
62
|
+
# will compare the results against a CSV file - we should expect them to match.
|
63
|
+
# See files "sql/sample_1/my_table_on_power.sql.erb" and "data/sample_1/my_table_expected_power_results.csv".
|
64
|
+
expect(sql.sample_1.my_table_on_power).to match('sample_1/my_table_expected_power_results.csv')
|
65
|
+
end
|
66
|
+
end
|