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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 35cf2798d086495d8716eb22b6ce08bea72a5ab1
4
- data.tar.gz: 6e332f0a12d3442ee7a28e319cff5b8759a8affb
3
+ metadata.gz: 671eec226ce28823bcb0d2e749c3e11d7990ffca
4
+ data.tar.gz: f3447b03aa97ee19fd1e3fefd566ed24b77f2a85
5
5
  SHA512:
6
- metadata.gz: 45f2f76f763f1587b4e1d330e00f3d24e87c8f7dca32a08abc9fed7f1076f5d87d42cc1dc06eeb20a2ac2a5c92d3a8312a31642edcb80f7940bfb46cc02d5bb9
7
- data.tar.gz: d5efb732d0ebf9f8be40cf1dae1c3ba33782b4df0c92be284608fc74818b78b920177186da5fb5ef9ae6f704f11a49d2ae33cf8bd423df834b4a905bab694061
6
+ metadata.gz: 1cf66f360cb3d5cd721d6f978dcdc385e6fbfac3cf3aecd40083d8d5f9a9a1b849cf52f7884a29ece948ff4ca1164bf1ccabab97076ecbc789b6e45888bbefc4
7
+ data.tar.gz: d2dd45b2e4822fa591286030fd9bb874fd1a23fdc5ee93946c6859e64e4cf8413f4f880801baefdf86db96cf6b0a179221e1adb6b08f2f1be9d21f3afc8b6079
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- simple-sql (0.2.0)
4
+ simple-sql (0.2.1)
5
5
  pg (~> 0.20)
6
6
  pg_array_parser (~> 0)
7
7
 
@@ -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
- extend Forwardable
14
- delegate exec: :pg
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 = connection.exec_params(sql, Encoder.encode_args(args))
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 = connection.exec_params(sql, Encoder.encode_args(args))
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
- simple-sql works out of the box with ActiveRecord-based postgres connections.
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
- def connect!(url)
128
- require "pg"
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
- config = db_config_from_url(url)
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
@@ -1,5 +1,5 @@
1
1
  module Simple
2
2
  module SQL
3
- VERSION = "0.2.0"
3
+ VERSION = "0.2.1"
4
4
  end
5
5
  end
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.0
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