sqlloader 0.1.2

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/bin/sqlload ADDED
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright 2012 Ludovico Fischer
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ require 'sqlloader'
17
+
18
+
19
+ module Tasks
20
+ BASE_DIRECTORY = 'SQL'
21
+ def self.get_datasets()
22
+ datasets = []
23
+ Dir[File.join(BASE_DIRECTORY, '*')].each do |d|
24
+ datasets << DataSet.new(d)
25
+ end
26
+ datasets
27
+ end
28
+
29
+ def self.list_available_datasets()
30
+ self.get_datasets().each do |d|
31
+ puts File.basename(d.directory)
32
+ end
33
+ end
34
+
35
+ def self.load_dataset(dataset_name, user_options)
36
+ if dataset_name.nil? then abort 'You must specify a dataset to load' end
37
+ dataset = DataSet.new(File.join(BASE_DIRECTORY, dataset_name), user_options)
38
+ dataset.load
39
+ end
40
+
41
+ def self.reset_dataset(dataset_name, user_options)
42
+ if dataset_name.nil? then abort 'You must specify a dataset to reset' end
43
+ dataset = DataSet.new(File.join(BASE_DIRECTORY, dataset_name), user_options)
44
+ dataset.reset
45
+ end
46
+ end
47
+
48
+ module User
49
+ def self.get_commandline_options(command_string)
50
+ require 'optparse'
51
+
52
+ options = {}
53
+
54
+ optparse = OptionParser.new do |opts|
55
+ opts.banner = 'Usage: sqlload [options] list|load|reset [dataset]'
56
+
57
+ opts.on('-U', '--user USERNAME', 'Specify username') do |user|
58
+ options[:user] = user
59
+ end
60
+
61
+ opts.on('-W', '--password PASSWORD', 'Specify password') do |password|
62
+ options[:password] = password
63
+ end
64
+
65
+ opts.on('-d', '--database DBNAME', 'Specify database name') do |dbname|
66
+ options[:dbname] = dbname
67
+ end
68
+
69
+ opts.on('-p', '--port PORT', 'Specify port') do |port|
70
+ options[:port] = port
71
+ end
72
+
73
+ opts.on_tail('-h', '--help', 'Displays this message') do
74
+ puts opts
75
+ exit
76
+ end
77
+ end
78
+
79
+ optparse.parse!(command_string)
80
+ options
81
+
82
+ end
83
+ end
84
+
85
+ user_options = User.get_commandline_options(ARGV)
86
+ dataset_name = ARGV[1]
87
+
88
+ case ARGV[0]
89
+ when 'list'
90
+ Tasks.list_available_datasets
91
+ when 'load'
92
+ Tasks.load_dataset(dataset_name, user_options)
93
+ when 'reset'
94
+ Tasks.reset_dataset(dataset_name, user_options)
95
+
96
+ else abort 'You must specify one of list, load or reset.'
97
+ end
data/lib/sqlloader.rb ADDED
@@ -0,0 +1,112 @@
1
+ # Copyright 2012 Ludovico Fischer
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'sqlloader/database'
16
+
17
+ ##
18
+ # A collection of data that can be inserted together into a database
19
+ class DataSet
20
+ include DBConfig, DB
21
+ attr_accessor :ups, :downs, :config, :directory
22
+
23
+ ##
24
+ # Creates a dataset using the SQL and the configuration contained
25
+ # in directory. The supplied user configuration overrides
26
+ # the configuration contained in the directory
27
+ def initialize(directory, user_config = {})
28
+ @ups = []
29
+ @downs = []
30
+ @directory = directory
31
+ populate()
32
+ @config = load_config(directory).merge(user_config)
33
+ if insufficient(config)
34
+ raise ArgumentError, 'No database name'
35
+ end
36
+ end
37
+
38
+ ##
39
+ # If there are reset scripts available,
40
+ # executes them before executing once again the regular scripts
41
+ def reset
42
+ if @downs.empty?
43
+ raise ArgumentError, 'There are no reset scripts to run'
44
+ end
45
+ load
46
+ delete
47
+ end
48
+
49
+ ##
50
+ # Executes the SQL scripts associated with the dataset.
51
+ def load
52
+ get_db_connection(@config) do |db_connection|
53
+ @ups.each do |s|
54
+ result = db_connection.exec(s.statement)
55
+ puts "#{s.filename}: #{result.cmd_status}"
56
+ end
57
+ end
58
+ end
59
+
60
+ ##
61
+ # Executes the SQL scripts marked as reset scripts
62
+ def delete
63
+ get_db_connection(@config) do |db_connection|
64
+ @downs.each do |s|
65
+ result = db_connection.exec(s.statement)
66
+ puts "#{s.filename}: #{result.cmd_status}"
67
+ end
68
+ end
69
+ end
70
+
71
+ def to_s
72
+ File.basename(@directory)
73
+ end
74
+
75
+ private
76
+
77
+ DataPiece = Struct.new(:filename, :statement)
78
+
79
+ # Fills the list of statements to execute from the information
80
+ # found by inspecting the directory contents
81
+ def populate()
82
+ require 'find'
83
+ Find.find(@directory) do |path|
84
+ if File.file?(path) && File.extname(path) == '.sql'
85
+ data = DataPiece.new(path, File.read(path))
86
+ if is_downs path
87
+ @downs << data
88
+ elsif is_ups path
89
+ @ups << data
90
+ end
91
+ end
92
+ end
93
+
94
+ @ups.sort! do |x, y|
95
+ File.basename(x.filename) <=> File.basename(y.filename)
96
+ end
97
+ end
98
+
99
+ # Returns true if the configuration does not contain enough information
100
+ # to connect to a database
101
+ def insufficient(config)
102
+ return config[:dbname].nil?
103
+ end
104
+
105
+ def is_ups(path)
106
+ return File.extname(path) == '.sql' && File.basename(path) != 'reset.sql'
107
+ end
108
+
109
+ def is_downs(path)
110
+ return File.basename(path) == 'reset.sql'
111
+ end
112
+ end
@@ -0,0 +1,52 @@
1
+ # Copyright 2012 Ludovico Fischer
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module DB
16
+ require 'pg'
17
+ ##
18
+ # Yields a database connection configured with the supplied options.
19
+ # This method will attempt to close the connection once the block terminates.
20
+ def get_db_connection(options)
21
+ dbname = options[:dbname]
22
+ unless dbname
23
+ abort "You must specify a database name"
24
+ end
25
+ user = options.fetch(:user, dbname)
26
+ password = options[:password]
27
+ port = options.fetch(:port, 5432)
28
+ begin
29
+ db_connection = PG.connect(:host => 'localhost', :port => port, :dbname => dbname, :user => user, :password => password)
30
+ yield db_connection
31
+ ensure
32
+ db_connection.finish unless db_connection.nil?
33
+ end
34
+ end
35
+ end
36
+
37
+
38
+ module DBConfig
39
+ ##
40
+ # Generates a configuration hash from a JSON file
41
+ #
42
+ # [path] the path to the dataset to load a config for
43
+ def load_config(path)
44
+ require 'json'
45
+
46
+ config = JSON.parse(File.read(self.get_config_path(path)), :symbolize_names => true)
47
+ end
48
+
49
+ def get_config_path(dataset_path)
50
+ File.join(dataset_path, 'config.json')
51
+ end
52
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sqlloader
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ludovico Fischer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: pg
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: ! 'sqlloader inspects a directory hierarchy: for each subdirectoyr, sqlloader
31
+ offers to execute any SQL file, using the database specified in the JSON configuration.'
32
+ email: ludovico.fischer@lunatech.com
33
+ executables:
34
+ - sqlload
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - lib/sqlloader.rb
39
+ - lib/sqlloader/database.rb
40
+ - !binary |-
41
+ YmluL3NxbGxvYWQ=
42
+ homepage: https://github.com/ludovicofischer/sqlloader
43
+ licenses:
44
+ - Apache License, Version 2.0
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubyforge_project:
63
+ rubygems_version: 1.8.19
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: Load and execute SQL from a directory hierarchy. Only supports PostgreSQL
67
+ test_files: []