simple-sql 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/simple/sql.rb +34 -32
- data/lib/simple/sql/config.rb +52 -0
- data/lib/simple/sql/logging.rb +29 -0
- data/lib/simple/sql/transactions.rb +44 -0
- data/lib/simple/sql/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 671eec226ce28823bcb0d2e749c3e11d7990ffca
|
4
|
+
data.tar.gz: f3447b03aa97ee19fd1e3fefd566ed24b77f2a85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1cf66f360cb3d5cd721d6f978dcdc385e6fbfac3cf3aecd40083d8d5f9a9a1b849cf52f7884a29ece948ff4ca1164bf1ccabab97076ecbc789b6e45888bbefc4
|
7
|
+
data.tar.gz: d2dd45b2e4822fa591286030fd9bb874fd1a23fdc5ee93946c6859e64e4cf8413f4f880801baefdf86db96cf6b0a179221e1adb6b08f2f1be9d21f3afc8b6079
|
data/Gemfile.lock
CHANGED
data/lib/simple/sql.rb
CHANGED
@@ -1,17 +1,29 @@
|
|
1
1
|
require_relative "sql/version.rb"
|
2
2
|
require_relative "sql/decoder.rb"
|
3
3
|
require_relative "sql/encoder.rb"
|
4
|
+
require_relative "sql/config.rb"
|
5
|
+
require_relative "sql/transactions.rb"
|
6
|
+
require_relative "sql/logging.rb"
|
7
|
+
|
8
|
+
require "logger"
|
4
9
|
|
5
10
|
module Simple
|
6
11
|
# The Simple::SQL module
|
7
12
|
module SQL
|
8
13
|
extend self
|
14
|
+
extend Transactions
|
15
|
+
|
16
|
+
attr_accessor :logger
|
17
|
+
self.logger = Logger.new(STDERR)
|
9
18
|
|
10
19
|
# execute one or more sql statements. This method does not allow to pass in
|
11
20
|
# arguments - since the pg client does not support this - but it allows to
|
12
21
|
# run multiple sql statements separated by ";"
|
13
|
-
|
14
|
-
|
22
|
+
def exec(sql)
|
23
|
+
Logging.yield_logged sql do
|
24
|
+
connection.exec sql
|
25
|
+
end
|
26
|
+
end
|
15
27
|
|
16
28
|
# Runs a query, with optional arguments, and returns the result. If the SQL
|
17
29
|
# query returns rows with one column, this method returns an array of these
|
@@ -28,7 +40,7 @@ module Simple
|
|
28
40
|
# end
|
29
41
|
|
30
42
|
def all(sql, *args, &block)
|
31
|
-
result =
|
43
|
+
result = exec_logged(sql, *args)
|
32
44
|
decoder = Decoder.new(result)
|
33
45
|
|
34
46
|
enumerate(result, decoder, block)
|
@@ -62,7 +74,7 @@ module Simple
|
|
62
74
|
# end
|
63
75
|
|
64
76
|
def records(sql, *args, into: Hash, &block)
|
65
|
-
result =
|
77
|
+
result = exec_logged(sql, *args)
|
66
78
|
decoder = Decoder.new(result, :record, into: into)
|
67
79
|
|
68
80
|
enumerate(result, decoder, block)
|
@@ -78,6 +90,12 @@ module Simple
|
|
78
90
|
|
79
91
|
private
|
80
92
|
|
93
|
+
def exec_logged(sql, *args)
|
94
|
+
Logging.yield_logged sql, *args do
|
95
|
+
connection.exec_params(sql, Encoder.encode_args(args))
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
81
99
|
def enumerate(result, decoder, block)
|
82
100
|
if block
|
83
101
|
result.each_row do |row|
|
@@ -112,11 +130,8 @@ module Simple
|
|
112
130
|
return ActiveRecord::Base.connection.raw_connection if defined?(ActiveRecord)
|
113
131
|
|
114
132
|
STDERR.puts <<-SQL
|
115
|
-
|
116
|
-
|
117
|
-
To use it without ActiveRecord you must connect to a database via
|
118
|
-
|
119
|
-
Simple::SQL.connect!("postgresql://username:password@dbhost:port/dbname").
|
133
|
+
Simple::SQL works out of the box with ActiveRecord-based postgres connections, reusing the current connection.
|
134
|
+
To use without ActiveRecord you must connect to a database via Simple::SQL.connect!.
|
120
135
|
SQL
|
121
136
|
|
122
137
|
raise ArgumentError, "simple-sql: missing connection"
|
@@ -124,32 +139,19 @@ SQL
|
|
124
139
|
|
125
140
|
public
|
126
141
|
|
127
|
-
|
128
|
-
|
142
|
+
# connects to the database specified via the url parameter. If called
|
143
|
+
# without argument it tries to determine a DATABASE_URL from either the
|
144
|
+
# environment setting (DATABASE_URL) or from a config/database.yml file,
|
145
|
+
# taking into account the RAILS_ENV and RACK_ENV settings.
|
146
|
+
def connect!(database_url = :auto)
|
147
|
+
database_url = Config.determine_url if database_url == :auto
|
148
|
+
|
149
|
+
logger.info "Connecting to #{database_url}"
|
150
|
+
config = Config.parse_url(database_url)
|
129
151
|
|
130
|
-
|
152
|
+
require "pg"
|
131
153
|
connection = PG::Connection.new(config)
|
132
154
|
self.connector = lambda { connection }
|
133
155
|
end
|
134
|
-
|
135
|
-
def db_config_from_url(url)
|
136
|
-
require "uri"
|
137
|
-
|
138
|
-
raise ArgumentError, "Invalid URL #{url.inspect}" unless url.is_a?(String)
|
139
|
-
raise ArgumentError, "Invalid URL #{url.inspect}" unless url =~ /^postgres(ql)?s?:\/\//
|
140
|
-
|
141
|
-
uri = URI.parse(url)
|
142
|
-
raise ArgumentError, "Invalid URL #{url}" unless uri.hostname && uri.path
|
143
|
-
|
144
|
-
config = {
|
145
|
-
dbname: uri.path.sub(%r{^/}, ""),
|
146
|
-
host: uri.hostname
|
147
|
-
}
|
148
|
-
config[:port] = uri.port if uri.port
|
149
|
-
config[:user] = uri.user if uri.user
|
150
|
-
config[:password] = uri.password if uri.password
|
151
|
-
config[:sslmode] = uri.scheme == "postgress" || uri.scheme == "postgresqls" ? "require" : "prefer"
|
152
|
-
config
|
153
|
-
end
|
154
156
|
end
|
155
157
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# private
|
2
|
+
module Simple::SQL::Config
|
3
|
+
extend self
|
4
|
+
|
5
|
+
# parse a DATABASE_URL, return PG::Connection settings.
|
6
|
+
def parse_url(url)
|
7
|
+
require "uri"
|
8
|
+
|
9
|
+
raise ArgumentError, "Invalid URL #{url.inspect}" unless url.is_a?(String)
|
10
|
+
raise ArgumentError, "Invalid URL #{url.inspect}" unless url =~ /^postgres(ql)?s?:\/\//
|
11
|
+
|
12
|
+
uri = URI.parse(url)
|
13
|
+
raise ArgumentError, "Invalid URL #{url}" unless uri.hostname && uri.path
|
14
|
+
|
15
|
+
config = {
|
16
|
+
dbname: uri.path.sub(%r{^/}, ""),
|
17
|
+
host: uri.hostname
|
18
|
+
}
|
19
|
+
config[:port] = uri.port if uri.port
|
20
|
+
config[:user] = uri.user if uri.user
|
21
|
+
config[:password] = uri.password if uri.password
|
22
|
+
config[:sslmode] = uri.scheme == "postgress" || uri.scheme == "postgresqls" ? "require" : "prefer"
|
23
|
+
config
|
24
|
+
end
|
25
|
+
|
26
|
+
# determines the database_url from either the DATABASE_URL environment setting
|
27
|
+
# or a config/database.yml file.
|
28
|
+
def determine_url
|
29
|
+
ENV["DATABASE_URL"] || database_url_from_database_yml
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def database_url_from_database_yml
|
35
|
+
abc = read_database_yml
|
36
|
+
username, password, host, port, database, password = abc.values_at "username", "password", "host", "port", "database", "password"
|
37
|
+
|
38
|
+
username_and_password = [ username, password ].compact.join(":")
|
39
|
+
host_and_port = [ host, port ].compact.join(":")
|
40
|
+
"postgres://#{username_and_password}@#{host_and_port}/#{database}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def read_database_yml
|
44
|
+
require "yaml"
|
45
|
+
database_config = YAML.load_file "config/database.yml"
|
46
|
+
env = ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
47
|
+
|
48
|
+
database_config[env] ||
|
49
|
+
database_config["defaults"] ||
|
50
|
+
raise("Invalid or missing database configuration in config/database.yml for #{env.inspect} environment")
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Simple
|
2
|
+
module SQL
|
3
|
+
module Logging
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def yield_logged(sql, *args, &block)
|
7
|
+
r0 = Time.now
|
8
|
+
rv = yield
|
9
|
+
realtime = Time.now - r0
|
10
|
+
::Simple::SQL.logger.debug "[sql] %.3f secs: %s" % [ realtime, format_query(sql, *args) ]
|
11
|
+
rv
|
12
|
+
rescue => e
|
13
|
+
realtime = Time.now - r0
|
14
|
+
::Simple::SQL.logger.warn "[sql] %.3f secs: %s:\n\tfailed with error %s" % [ realtime, format_query(sql, *args), e.message ]
|
15
|
+
raise
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def format_query(sql, *args)
|
21
|
+
sql = sql.gsub(/\s*\n\s*/, " ").gsub(/(\A\s+)|(\s+\z)/, "")
|
22
|
+
return sql if args.empty?
|
23
|
+
args = args.map(&:inspect).join(", ")
|
24
|
+
sql + " w/args: #{args}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# private
|
2
|
+
module Simple::SQL::Transactions
|
3
|
+
SELF = self
|
4
|
+
|
5
|
+
def self.nesting_level
|
6
|
+
Thread.current[:nesting_level] ||= 0
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.nesting_level=(nesting_level)
|
10
|
+
Thread.current[:nesting_level] = nesting_level
|
11
|
+
end
|
12
|
+
|
13
|
+
def transaction(&block)
|
14
|
+
# Notes: by using "ensure" (as opposed to rescue) we are rolling back
|
15
|
+
# both when an exception was raised and when a value was thrown. This
|
16
|
+
# also means we have to track whether or not to rollback. i.e. do roll
|
17
|
+
# back when we yielded to &block but not otherwise.
|
18
|
+
#
|
19
|
+
# Also the transaction support is a bit limited: you cannot rollback.
|
20
|
+
# Rolling back from inside a nested transaction would require SAVEPOINT
|
21
|
+
# support; without the code is simpler at least :)
|
22
|
+
if SELF.nesting_level == 0
|
23
|
+
transaction_started = true
|
24
|
+
ask "BEGIN"
|
25
|
+
end
|
26
|
+
|
27
|
+
SELF.nesting_level += 1
|
28
|
+
|
29
|
+
return_value = yield
|
30
|
+
|
31
|
+
# Only commit if we started a transaction here.
|
32
|
+
if transaction_started
|
33
|
+
ask "COMMIT"
|
34
|
+
transaction_committed = true
|
35
|
+
end
|
36
|
+
|
37
|
+
return_value
|
38
|
+
ensure
|
39
|
+
SELF.nesting_level -= 1
|
40
|
+
if transaction_started && !transaction_committed
|
41
|
+
ask "ROLLBACK"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/simple/sql/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple-sql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- radiospiel
|
@@ -166,8 +166,11 @@ files:
|
|
166
166
|
- bin/rake
|
167
167
|
- config/database.yml
|
168
168
|
- lib/simple/sql.rb
|
169
|
+
- lib/simple/sql/config.rb
|
169
170
|
- lib/simple/sql/decoder.rb
|
170
171
|
- lib/simple/sql/encoder.rb
|
172
|
+
- lib/simple/sql/logging.rb
|
173
|
+
- lib/simple/sql/transactions.rb
|
171
174
|
- lib/simple/sql/version.rb
|
172
175
|
- log/.gitkeep
|
173
176
|
- simple-sql.gemspec
|