simple-sql 0.2.0 → 0.2.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.
- 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
|