sqlloader 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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: []