├── .github
└── FUNDING.yml
├── .gitignore
├── .travis.yml
├── Gemfile
├── Gemfile.lock
├── MIT-LICENSE
├── README.md
├── Rakefile
├── bin
└── test
├── docs
└── sample_execute_sql.png
├── execute_sql.gemspec
├── lib
├── execute_sql.rb
├── execute_sql
│ ├── adapters
│ │ ├── base_adapter.rb
│ │ ├── mysql.rb
│ │ ├── postgres.rb
│ │ └── sqlite.rb
│ ├── blank_results.rb
│ ├── connection.rb
│ ├── database.rb
│ ├── execute_sql_error.rb
│ ├── mysql_result.rb
│ ├── railtie.rb
│ ├── result.rb
│ ├── sql_explain.rb
│ ├── sql_import.rb
│ ├── sql_query.rb
│ ├── sql_query_data.rb
│ └── version.rb
└── tasks
│ └── execute_sql_tasks.rake
└── test
├── dummy
├── .ruby-version
├── Rakefile
├── app
│ ├── assets
│ │ ├── config
│ │ │ └── manifest.js
│ │ ├── images
│ │ │ └── .keep
│ │ ├── javascripts
│ │ │ ├── application.js
│ │ │ ├── cable.js
│ │ │ ├── channels
│ │ │ │ └── .keep
│ │ │ └── home.js
│ │ └── stylesheets
│ │ │ ├── application.css
│ │ │ └── home.css
│ ├── channels
│ │ └── application_cable
│ │ │ ├── channel.rb
│ │ │ └── connection.rb
│ ├── controllers
│ │ ├── application_controller.rb
│ │ ├── concerns
│ │ │ └── .keep
│ │ └── home_controller.rb
│ ├── helpers
│ │ ├── application_helper.rb
│ │ └── home_helper.rb
│ ├── jobs
│ │ └── application_job.rb
│ ├── mailers
│ │ └── application_mailer.rb
│ ├── models
│ │ ├── application_record.rb
│ │ ├── concerns
│ │ │ └── .keep
│ │ └── user.rb
│ └── views
│ │ ├── home
│ │ └── index.html.erb
│ │ └── layouts
│ │ ├── application.html.erb
│ │ ├── mailer.html.erb
│ │ └── mailer.text.erb
├── bin
│ ├── bundle
│ ├── rails
│ ├── rake
│ ├── setup
│ ├── update
│ └── yarn
├── config.ru
├── config
│ ├── application.rb
│ ├── boot.rb
│ ├── cable.yml
│ ├── database.yml
│ ├── environment.rb
│ ├── environments
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── initializers
│ │ ├── application_controller_renderer.rb
│ │ ├── assets.rb
│ │ ├── backtrace_silencers.rb
│ │ ├── content_security_policy.rb
│ │ ├── cookies_serializer.rb
│ │ ├── filter_parameter_logging.rb
│ │ ├── inflections.rb
│ │ ├── mime_types.rb
│ │ └── wrap_parameters.rb
│ ├── locales
│ │ └── en.yml
│ ├── puma.rb
│ ├── routes.rb
│ ├── spring.rb
│ └── storage.yml
├── db
│ ├── migrate
│ │ └── 20190313194001_create_users.rb
│ └── schema.rb
├── lib
│ └── assets
│ │ └── .keep
├── log
│ └── .keep
├── package.json
└── public
│ ├── 404.html
│ ├── 422.html
│ ├── 500.html
│ ├── apple-touch-icon-precomposed.png
│ ├── apple-touch-icon.png
│ └── favicon.ico
├── execute_sql_test.rb
└── test_helper.rb
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | patreon: igorkasyanchuk
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .bundle/
2 | log/*.log
3 | pkg/
4 | test/dummy/db/*.sqlite3
5 | test/dummy/db/*.sqlite3-journal
6 | test/dummy/log/*.log
7 | test/dummy/node_modules/
8 | test/dummy/yarn-error.log
9 | test/dummy/storage/
10 | test/dummy/tmp/
11 | *.gem
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 |
3 | rvm:
4 | - "2.5"
5 | - "2.6"
6 |
7 | cache: bundler
8 |
9 | bundler_args: --without development --jobs=3 --retry=3 --path=../vendor/bundle
10 |
11 | script:
12 | - bundle exec rake test
13 |
14 | notifications:
15 | email: false
16 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3 |
4 | # Declare your gem's dependencies in execute_sql.gemspec.
5 | # Bundler will treat runtime dependencies like base dependencies, and
6 | # development dependencies will be added by default to the :development group.
7 | gemspec
8 |
9 | # Declare any dependencies that are still in development here instead of in
10 | # your gemspec. These might include edge Rails or gems from your path or
11 | # Git. Remember to move these dependencies to your gemspec before releasing
12 | # your gem to rubygems.org.
13 |
14 | # To use a debugger
15 | # gem 'byebug'
16 |
17 | #gem 'sqlite3', '~> 1.3.13', platforms: :ruby, group: [:development, :test]
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: .
3 | specs:
4 | execute_sql (0.1.1)
5 | rails
6 | terminal-table
7 |
8 | GEM
9 | remote: https://rubygems.org/
10 | specs:
11 | actioncable (6.0.1)
12 | actionpack (= 6.0.1)
13 | nio4r (~> 2.0)
14 | websocket-driver (>= 0.6.1)
15 | actionmailbox (6.0.1)
16 | actionpack (= 6.0.1)
17 | activejob (= 6.0.1)
18 | activerecord (= 6.0.1)
19 | activestorage (= 6.0.1)
20 | activesupport (= 6.0.1)
21 | mail (>= 2.7.1)
22 | actionmailer (6.0.1)
23 | actionpack (= 6.0.1)
24 | actionview (= 6.0.1)
25 | activejob (= 6.0.1)
26 | mail (~> 2.5, >= 2.5.4)
27 | rails-dom-testing (~> 2.0)
28 | actionpack (6.0.1)
29 | actionview (= 6.0.1)
30 | activesupport (= 6.0.1)
31 | rack (~> 2.0)
32 | rack-test (>= 0.6.3)
33 | rails-dom-testing (~> 2.0)
34 | rails-html-sanitizer (~> 1.0, >= 1.2.0)
35 | actiontext (6.0.1)
36 | actionpack (= 6.0.1)
37 | activerecord (= 6.0.1)
38 | activestorage (= 6.0.1)
39 | activesupport (= 6.0.1)
40 | nokogiri (>= 1.8.5)
41 | actionview (6.0.1)
42 | activesupport (= 6.0.1)
43 | builder (~> 3.1)
44 | erubi (~> 1.4)
45 | rails-dom-testing (~> 2.0)
46 | rails-html-sanitizer (~> 1.1, >= 1.2.0)
47 | activejob (6.0.1)
48 | activesupport (= 6.0.1)
49 | globalid (>= 0.3.6)
50 | activemodel (6.0.1)
51 | activesupport (= 6.0.1)
52 | activerecord (6.0.1)
53 | activemodel (= 6.0.1)
54 | activesupport (= 6.0.1)
55 | activestorage (6.0.1)
56 | actionpack (= 6.0.1)
57 | activejob (= 6.0.1)
58 | activerecord (= 6.0.1)
59 | marcel (~> 0.3.1)
60 | activesupport (6.0.1)
61 | concurrent-ruby (~> 1.0, >= 1.0.2)
62 | i18n (>= 0.7, < 2)
63 | minitest (~> 5.1)
64 | tzinfo (~> 1.1)
65 | zeitwerk (~> 2.2)
66 | builder (3.2.3)
67 | coderay (1.1.2)
68 | concurrent-ruby (1.1.5)
69 | crass (1.0.5)
70 | erubi (1.9.0)
71 | globalid (0.4.2)
72 | activesupport (>= 4.2.0)
73 | i18n (1.7.0)
74 | concurrent-ruby (~> 1.0)
75 | loofah (2.4.0)
76 | crass (~> 1.0.2)
77 | nokogiri (>= 1.5.9)
78 | mail (2.7.1)
79 | mini_mime (>= 0.1.1)
80 | marcel (0.3.3)
81 | mimemagic (~> 0.3.2)
82 | method_source (0.9.2)
83 | mimemagic (0.3.3)
84 | mini_mime (1.0.2)
85 | mini_portile2 (2.4.0)
86 | minitest (5.13.0)
87 | nio4r (2.5.2)
88 | nokogiri (1.10.7)
89 | mini_portile2 (~> 2.4.0)
90 | pry (0.12.2)
91 | coderay (~> 1.1.0)
92 | method_source (~> 0.9.0)
93 | pry-rails (0.3.9)
94 | pry (>= 0.10.4)
95 | rack (2.0.7)
96 | rack-test (1.1.0)
97 | rack (>= 1.0, < 3)
98 | rails (6.0.1)
99 | actioncable (= 6.0.1)
100 | actionmailbox (= 6.0.1)
101 | actionmailer (= 6.0.1)
102 | actionpack (= 6.0.1)
103 | actiontext (= 6.0.1)
104 | actionview (= 6.0.1)
105 | activejob (= 6.0.1)
106 | activemodel (= 6.0.1)
107 | activerecord (= 6.0.1)
108 | activestorage (= 6.0.1)
109 | activesupport (= 6.0.1)
110 | bundler (>= 1.3.0)
111 | railties (= 6.0.1)
112 | sprockets-rails (>= 2.0.0)
113 | rails-dom-testing (2.0.3)
114 | activesupport (>= 4.2.0)
115 | nokogiri (>= 1.6)
116 | rails-html-sanitizer (1.3.0)
117 | loofah (~> 2.3)
118 | railties (6.0.1)
119 | actionpack (= 6.0.1)
120 | activesupport (= 6.0.1)
121 | method_source
122 | rake (>= 0.8.7)
123 | thor (>= 0.20.3, < 2.0)
124 | rake (13.0.1)
125 | sprockets (4.0.0)
126 | concurrent-ruby (~> 1.0)
127 | rack (> 1, < 3)
128 | sprockets-rails (3.2.1)
129 | actionpack (>= 4.0)
130 | activesupport (>= 4.0)
131 | sprockets (>= 3.0.0)
132 | sqlite3 (1.4.1)
133 | terminal-table (1.8.0)
134 | unicode-display_width (~> 1.1, >= 1.1.1)
135 | thor (0.20.3)
136 | thread_safe (0.3.6)
137 | tzinfo (1.2.5)
138 | thread_safe (~> 0.1)
139 | unicode-display_width (1.6.0)
140 | websocket-driver (0.7.1)
141 | websocket-extensions (>= 0.1.0)
142 | websocket-extensions (0.1.4)
143 | zeitwerk (2.2.2)
144 |
145 | PLATFORMS
146 | ruby
147 |
148 | DEPENDENCIES
149 | execute_sql!
150 | pry-rails
151 | sqlite3 (~> 1.4)
152 |
153 | BUNDLED WITH
154 | 1.17.3
155 |
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2019 Igor Kasyanchuk
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Rails Execute SQL
2 |
3 | [](https://www.railsjazz.com)
4 | [](https://www.patreon.com/igorkasyanchuk)
5 |
6 | [](https://buymeacoffee.com/igorkasyanchuk)
7 |
8 | Execute SQL with `execute_sql` helper inside your Rails apps. Directly in `rails console`.
9 |
10 |
11 |
12 | ## Usage
13 |
14 | Simply add this gem into your Gemfile.
15 |
16 | And for example call directly in `rails console`:
17 |
18 | ```ruby
19 | execute_sql "select count(*) from users where age > 50"
20 |
21 | # see below for additional options.
22 | ```
23 |
24 | OR in your models, controllers, or other parts of app:
25 |
26 | ```ruby
27 | ExecuteSQL.run "select count(*) from users where age > 50"
28 |
29 | # or with different mode
30 | # default mode: :print
31 |
32 | # return array of HashWithIndifferentAccess objects
33 | # please remember that arrays can be manipulated with Enumerable methods, but this is *not* a chainable ARel relation
34 | ExecuteSQL.run "select * from users where age > 50", mode: :array
35 |
36 | # return array of User objects
37 | ExecuteSQL.run "select * from users where age > 50", mode: :array, klass: User
38 |
39 | # return single value
40 | ExecuteSQL.run "select count(*) from users where age > 50", mode: :single
41 |
42 | # return array of results
43 | ExecuteSQL.run "select * from users where age > 50", mode: :raw
44 |
45 | # just execute and return nil
46 | ExecuteSQL.run "truncate table users", mode: :none
47 | ```
48 |
49 | Sample in controller:
50 |
51 | ```ruby
52 | class HomeController < ApplicationController
53 | def index
54 | @users = ExecuteSql.run "select * from users", mode: :raw
55 | end
56 | end
57 | ```
58 |
59 | ## Installation
60 | Add this line to your application's Gemfile:
61 |
62 | ```ruby
63 | gem 'execute_sql'
64 | ```
65 |
66 | And then execute:
67 | ```bash
68 | $ bundle
69 | ```
70 |
71 | ## Options and modes
72 |
73 | You can call:
74 |
75 | In rails console use helper: `execute_sql "some SQL"`.
76 |
77 | Or `ExecuteSql.run "some SQL"` or `ExecuteSQL.run "some SQL"`.
78 |
79 | ## TODO
80 |
81 | - import SQL files
82 | - travis CI
83 | - verify with older rails
84 | - more specs
85 |
86 | ## Contributing
87 |
88 | You are welcome to contribute.
89 |
90 | ## License
91 |
92 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
93 |
94 | Some pieces of code I took from another my gem: https://github.com/igorkasyanchuk/rails_db.
95 |
96 | ## Contributors
97 |
98 | - @pjforde1978
99 |
100 | Big thank you.
101 |
102 | [
](https://www.railsjazz.com/?utm_source=github&utm_medium=bottom&utm_campaign=execute_sql)
104 |
105 | [](https://buymeacoffee.com/igorkasyanchuk)
106 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | begin
2 | require 'bundler/setup'
3 | rescue LoadError
4 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5 | end
6 |
7 | require 'rdoc/task'
8 |
9 | RDoc::Task.new(:rdoc) do |rdoc|
10 | rdoc.rdoc_dir = 'rdoc'
11 | rdoc.title = 'ExecuteSql'
12 | rdoc.options << '--line-numbers'
13 | rdoc.rdoc_files.include('README.md')
14 | rdoc.rdoc_files.include('lib/**/*.rb')
15 | end
16 |
17 | require 'bundler/gem_tasks'
18 |
19 | require 'rake/testtask'
20 |
21 | Rake::TestTask.new(:test) do |t|
22 | t.libs << 'test'
23 | t.pattern = 'test/**/*_test.rb'
24 | t.verbose = false
25 | end
26 |
27 | task default: :test
28 |
--------------------------------------------------------------------------------
/bin/test:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | $: << File.expand_path("../test", __dir__)
3 |
4 | require "bundler/setup"
5 | require "rails/plugin/test"
6 |
--------------------------------------------------------------------------------
/docs/sample_execute_sql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/igorkasyanchuk/execute_sql/967fc594d8c66fccf0e8197e5b40597fb6f29284/docs/sample_execute_sql.png
--------------------------------------------------------------------------------
/execute_sql.gemspec:
--------------------------------------------------------------------------------
1 | $:.push File.expand_path("lib", __dir__)
2 |
3 | # Maintain your gem's version:
4 | require "execute_sql/version"
5 |
6 | # Describe your gem and declare its dependencies:
7 | Gem::Specification.new do |spec|
8 | spec.name = "execute_sql"
9 | spec.version = ExecuteSql::VERSION
10 | spec.authors = ["Igor Kasyanchuk"]
11 | spec.email = ["igorkasyanchuk@gmail.com"]
12 | spec.homepage = "https://github.com/igorkasyanchuk/execute_sql"
13 | spec.summary = "Execute SQL directly in rails console or in the code."
14 | spec.description = "Execute SQL directly in rails console or in the code."
15 | spec.license = "MIT"
16 |
17 | spec.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"]
18 |
19 | spec.add_dependency "rails"
20 | spec.add_dependency 'terminal-table'
21 |
22 | spec.add_development_dependency "sqlite3", '~> 1.4'
23 | spec.add_development_dependency "pry-rails"
24 | end
25 |
--------------------------------------------------------------------------------
/lib/execute_sql.rb:
--------------------------------------------------------------------------------
1 | require 'terminal-table'
2 |
3 | require_relative 'execute_sql/connection'
4 | require_relative 'execute_sql/database'
5 | require_relative 'execute_sql/blank_results'
6 | require_relative 'execute_sql/mysql_result'
7 | require_relative 'execute_sql/result'
8 | require_relative 'execute_sql/execute_sql_error'
9 |
10 | require_relative 'execute_sql/sql_query_data'
11 | require_relative 'execute_sql/sql_explain'
12 | require_relative 'execute_sql/sql_import'
13 | require_relative 'execute_sql/sql_query'
14 |
15 | require_relative 'execute_sql/adapters/base_adapter'
16 | require_relative 'execute_sql/adapters/mysql'
17 | require_relative 'execute_sql/adapters/postgres'
18 | require_relative 'execute_sql/adapters/sqlite'
19 |
20 | require "execute_sql/railtie"
21 |
22 | module ExecuteSql
23 | module ConsoleMethods
24 |
25 | def execute_sql(sql, mode: :print, klass: HashWithIndifferentAccess)
26 | sql_query = ExecuteSql::SqlQuery.new("#{sql}".strip).execute
27 | rows = sql_query.data.rows
28 | cols = sql_query.data.columns
29 | case mode.to_s
30 | when 'print'
31 | puts Terminal::Table.new(rows: rows, headings: cols)
32 | when 'array'
33 | result = rows.map do |row|
34 | record = klass.new
35 | cols.each_with_index.map do |col, index|
36 | record[col] = row[index]
37 | end
38 | record
39 | end
40 | result
41 | when 'raw'
42 | rows
43 | when 'single'
44 | rows.flatten[0]
45 | when 'none'
46 | nil
47 | else
48 | []
49 | end
50 | end
51 |
52 | def run(sql, *args)
53 | execute_sql(sql, *args)
54 | end
55 | end
56 |
57 | extend ConsoleMethods
58 | end
59 |
60 | ExecuteSQL = ExecuteSql
61 |
--------------------------------------------------------------------------------
/lib/execute_sql/adapters/base_adapter.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | module Adapters
3 |
4 | class BaseAdapter
5 | extend ::ExecuteSql::Connection
6 |
7 | MULTI_STATEMENT_HELP_TEXT = "EXPERIMENTAL: You can import only file with SQL statements separated by ';'. Each new statement must start from new line."
8 |
9 | def self.execute(sql)
10 | t0 = Time.now
11 | connection.execute(sql)
12 | Time.now - t0
13 | end
14 |
15 | def self.exec_query(sql)
16 | t0 = Time.now
17 | results = connection.exec_query(sql)
18 | execution_time = Time.now - t0
19 | [results, execution_time]
20 | end
21 |
22 | def self.select(sql)
23 | BaseAdapter.exec_query(sql)
24 | end
25 |
26 | def self.explain(sql)
27 | BaseAdapter.exec_query(sql)
28 | end
29 |
30 | def self.adapter_name
31 | 'base'
32 | end
33 |
34 | def self.mime
35 | 'text/x-sql'
36 | end
37 |
38 | private
39 |
40 | def self.multiple_execute(sql, divider = ";\n")
41 | sql.split(divider).each do |statement|
42 | connection.execute(statement)
43 | end
44 | end
45 |
46 | end
47 |
48 | end
49 | end
--------------------------------------------------------------------------------
/lib/execute_sql/adapters/mysql.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | module Adapters
3 |
4 | class Mysql < BaseAdapter
5 |
6 | def self.execute(sql)
7 | t0 = Time.now
8 | multiple_execute(sql)
9 | Time.now - t0
10 | end
11 |
12 | def self.exec_query(sql, log = true)
13 | t0 = Time.now
14 | results = connection.execute(sql, 'SQL') # used from RoR mysql adapter source
15 | result = MysqlResult.new(results)
16 | execution_time = Time.now - t0
17 | [result, execution_time]
18 | end
19 |
20 | def self.adapter_name
21 | 'mysql'
22 | end
23 |
24 | def self.mime
25 | 'text/x-mysql'
26 | end
27 |
28 | end
29 |
30 | end
31 | end
--------------------------------------------------------------------------------
/lib/execute_sql/adapters/postgres.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | module Adapters
3 |
4 | class Postgres < BaseAdapter
5 |
6 | def self.adapter_name
7 | 'postgres'
8 | end
9 |
10 | def self.mime
11 | 'text/x-plsql'
12 | end
13 |
14 | end
15 |
16 | end
17 | end
--------------------------------------------------------------------------------
/lib/execute_sql/adapters/sqlite.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | module Adapters
3 |
4 | class Sqlite < BaseAdapter
5 |
6 | def self.execute(sql)
7 | t0 = Time.now
8 | multiple_execute(sql)
9 | Time.now - t0
10 | end
11 |
12 | def self.adapter_name
13 | 'sqlite'
14 | end
15 |
16 | end
17 |
18 | end
19 | end
--------------------------------------------------------------------------------
/lib/execute_sql/blank_results.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | class BlankResults
3 |
4 | def rows; [] end
5 | def columns; [] end
6 |
7 | end
8 | end
--------------------------------------------------------------------------------
/lib/execute_sql/connection.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | module Connection
3 |
4 | def connection
5 | ActiveRecord::Base.connection
6 | end
7 |
8 | def columns
9 | connection.columns(name)
10 | end
11 |
12 | def column_properties
13 | %w(name sql_type null limit precision scale type default)
14 | end
15 |
16 | def to_param
17 | name
18 | end
19 |
20 | def column_names
21 | columns.collect(&:name)
22 | end
23 |
24 | end
25 | end
--------------------------------------------------------------------------------
/lib/execute_sql/database.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | class Database
3 | extend Connection
4 |
5 | class << self
6 | delegate :execute, to: :adapter
7 | delegate :select, to: :adapter
8 | delegate :explain, to: :adapter
9 | delegate :exec_query, to: :adapter
10 | end
11 |
12 | def self.adapter
13 | case connection.class.to_s
14 | when /Mysql/
15 | ExecuteSql::Adapters::Mysql
16 | when /Postgre/
17 | ExecuteSql::Adapters::Postgres
18 | when /SQLite/
19 | ExecuteSql::Adapters::Sqlite
20 | else
21 | ExecuteSql::Adapters::BaseAdapter
22 | end
23 | end
24 |
25 | end
26 | end
--------------------------------------------------------------------------------
/lib/execute_sql/execute_sql_error.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | class ExecuteSqlError < StandardError
3 | end
4 | end
--------------------------------------------------------------------------------
/lib/execute_sql/mysql_result.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | class MysqlResult
3 |
4 | attr_reader :columns, :rows
5 |
6 | delegate :each, to: :rows
7 |
8 | def initialize(result)
9 | @columns = []
10 | @rows = []
11 | if result
12 | @columns = result.fields
13 | @rows = result.entries
14 | end
15 | end
16 |
17 | end
18 | end
--------------------------------------------------------------------------------
/lib/execute_sql/railtie.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | class Railtie < ::Rails::Railtie
3 |
4 | console do
5 | TOPLEVEL_BINDING.eval('self').extend ExecuteSql::ConsoleMethods
6 | end
7 |
8 | end
9 | end
--------------------------------------------------------------------------------
/lib/execute_sql/result.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | class Result
3 |
4 | attr_reader :error
5 |
6 | def initialize(error)
7 | @error = error
8 | end
9 |
10 | def self.ok
11 | Result.new(nil)
12 | end
13 |
14 | def ok?
15 | error.nil?
16 | end
17 |
18 | end
19 | end
--------------------------------------------------------------------------------
/lib/execute_sql/sql_explain.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | class SqlExplain < SqlQueryData
3 |
4 | def sql
5 | "EXPLAIN #{super}"
6 | end
7 |
8 | end
9 | end
--------------------------------------------------------------------------------
/lib/execute_sql/sql_import.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | class SqlImport
3 | include Connection
4 |
5 | attr_reader :time, :result
6 |
7 | def initialize(file)
8 | @file = file
9 | end
10 |
11 | def valid?
12 | if @file.nil?
13 | raise ExecuteSqlError.new('Please select valid SQL file and continue')
14 | end
15 | end
16 |
17 | def import
18 | valid?
19 | @time = Database.adapter.execute(@file.read)
20 | @result = Result.ok
21 | rescue ExecuteSqlError, ActiveRecord::StatementInvalid => e
22 | @result = Result.new(e)
23 | end
24 |
25 | end
26 | end
--------------------------------------------------------------------------------
/lib/execute_sql/sql_query.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | class SqlQuery
3 | include Connection
4 |
5 | attr_reader :query, :data, :explain, :sql_explain
6 |
7 | def initialize(query, sql_explain = false)
8 | @query = query
9 | @sql_explain = sql_explain
10 | end
11 |
12 | def valid?
13 | query.present?
14 | end
15 |
16 | def load_explain
17 | @explain ||= SqlExplain.new(self).load_data
18 | end
19 |
20 | def load_data
21 | @data ||= SqlQueryData.new(self).load_data
22 | end
23 |
24 | def execute
25 | if valid?
26 | load_data
27 | load_explain if sql_explain
28 | end
29 | self
30 | end
31 |
32 | def to_csv
33 | CSV.generate do |csv|
34 | csv << data.columns
35 | data.rows.each do |row|
36 | csv << row
37 | end
38 | end
39 | end
40 |
41 | end
42 | end
--------------------------------------------------------------------------------
/lib/execute_sql/sql_query_data.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | class SqlQueryData
3 |
4 | attr_reader :sql_query, :time, :columns, :rows, :error
5 |
6 | def initialize(sql_query)
7 | @rows = []
8 | @columns = []
9 | @sql_query = sql_query
10 | end
11 |
12 | def load_data
13 | result, @time = Database.adapter.exec_query(sql)
14 | @columns = result.columns
15 | @rows = result.rows
16 | self
17 | rescue ActiveRecord::StatementInvalid => e
18 | @columns, @rows = [], []
19 | @error = e
20 | self
21 | end
22 |
23 | def count
24 | rows.count
25 | end
26 |
27 | def is_error?
28 | error.present?
29 | end
30 |
31 | def sql
32 | sql_query.query
33 | end
34 |
35 | end
36 | end
--------------------------------------------------------------------------------
/lib/execute_sql/version.rb:
--------------------------------------------------------------------------------
1 | module ExecuteSql
2 | VERSION = '0.1.1'
3 | end
4 |
--------------------------------------------------------------------------------
/lib/tasks/execute_sql_tasks.rake:
--------------------------------------------------------------------------------
1 | # desc "Explaining what the task does"
2 | # task :execute_sql do
3 | # # Task goes here
4 | # end
5 |
--------------------------------------------------------------------------------
/test/dummy/.ruby-version:
--------------------------------------------------------------------------------
1 | ruby-2.6.1
--------------------------------------------------------------------------------
/test/dummy/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require_relative 'config/application'
5 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/config/manifest.js:
--------------------------------------------------------------------------------
1 | //= link_tree ../images
2 | //= link_directory ../javascripts .js
3 | //= link_directory ../stylesheets .css
4 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/igorkasyanchuk/execute_sql/967fc594d8c66fccf0e8197e5b40597fb6f29284/test/dummy/app/assets/images/.keep
--------------------------------------------------------------------------------
/test/dummy/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // This is a manifest file that'll be compiled into application.js, which will include all the files
2 | // listed below.
3 | //
4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6 | //
7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8 | // compiled file. JavaScript code in this file should be added after the last require_* statement.
9 | //
10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11 | // about supported directives.
12 | //
13 | //= require rails-ujs
14 | //= require activestorage
15 | //= require_tree .
16 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/javascripts/cable.js:
--------------------------------------------------------------------------------
1 | // Action Cable provides the framework to deal with WebSockets in Rails.
2 | // You can generate new channels where WebSocket features live using the `rails generate channel` command.
3 | //
4 | //= require action_cable
5 | //= require_self
6 | //= require_tree ./channels
7 |
8 | (function() {
9 | this.App || (this.App = {});
10 |
11 | App.cable = ActionCable.createConsumer();
12 |
13 | }).call(this);
14 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/javascripts/channels/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/igorkasyanchuk/execute_sql/967fc594d8c66fccf0e8197e5b40597fb6f29284/test/dummy/app/assets/javascripts/channels/.keep
--------------------------------------------------------------------------------
/test/dummy/app/assets/javascripts/home.js:
--------------------------------------------------------------------------------
1 | // Place all the behaviors and hooks related to the matching controller here.
2 | // All this logic will automatically be available in application.js.
3 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a manifest file that'll be compiled into application.css, which will include all the files
3 | * listed below.
4 | *
5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7 | *
8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10 | * files in this directory. Styles in this file should be added after the last require_* statement.
11 | * It is generally better to create a new file per style scope.
12 | *
13 | *= require_tree .
14 | *= require_self
15 | */
16 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/stylesheets/home.css:
--------------------------------------------------------------------------------
1 | /*
2 | Place all the styles related to the matching controller here.
3 | They will automatically be included in application.css.
4 | */
5 |
--------------------------------------------------------------------------------
/test/dummy/app/channels/application_cable/channel.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Channel < ActionCable::Channel::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/test/dummy/app/channels/application_cable/connection.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Connection < ActionCable::Connection::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | end
3 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/igorkasyanchuk/execute_sql/967fc594d8c66fccf0e8197e5b40597fb6f29284/test/dummy/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/test/dummy/app/controllers/home_controller.rb:
--------------------------------------------------------------------------------
1 | class HomeController < ApplicationController
2 | def index
3 | @users = ExecuteSql.run "select * from users", mode: :raw
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/test/dummy/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/test/dummy/app/helpers/home_helper.rb:
--------------------------------------------------------------------------------
1 | module HomeHelper
2 | end
3 |
--------------------------------------------------------------------------------
/test/dummy/app/jobs/application_job.rb:
--------------------------------------------------------------------------------
1 | class ApplicationJob < ActiveJob::Base
2 | end
3 |
--------------------------------------------------------------------------------
/test/dummy/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | class ApplicationMailer < ActionMailer::Base
2 | default from: 'from@example.com'
3 | layout 'mailer'
4 | end
5 |
--------------------------------------------------------------------------------
/test/dummy/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | class ApplicationRecord < ActiveRecord::Base
2 | self.abstract_class = true
3 | end
4 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/igorkasyanchuk/execute_sql/967fc594d8c66fccf0e8197e5b40597fb6f29284/test/dummy/app/models/concerns/.keep
--------------------------------------------------------------------------------
/test/dummy/app/models/user.rb:
--------------------------------------------------------------------------------
1 | class User < ApplicationRecord
2 | end
3 |
--------------------------------------------------------------------------------
/test/dummy/app/views/home/index.html.erb:
--------------------------------------------------------------------------------
1 |
Find me in app/views/home/index.html.erb
3 | 4 | <%= debug @users %> -------------------------------------------------------------------------------- /test/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |You may have mistyped the address or the page may have moved.
63 |If you are the application owner check the logs for more information.
65 |Maybe you tried to change something you didn't have access to.
63 |If you are the application owner check the logs for more information.
65 |If you are the application owner check the logs for more information.
64 |