├── .github
└── workflows
│ └── ruby.yml
├── .gitignore
├── .hound.yml
├── .overcommit.yml
├── .reek
├── .rubocop.yml
├── Appraisals
├── Gemfile
├── MIT-LICENSE
├── README.md
├── Rakefile
├── gemfiles
├── activerecord_7_0.gemfile
├── activerecord_7_1.gemfile
├── activerecord_7_2.gemfile
├── activerecord_8_0.gemfile
├── rails_7_0.gemfile
├── rails_7_1.gemfile
├── rails_7_2.gemfile
└── rails_8_0.gemfile
├── img
├── console.png
├── jetbrains-variant-3.svg
└── log.png
├── lib
├── pp_sql.rb
└── pp_sql
│ └── version.rb
├── pp_sql.gemspec
└── test
├── pp_sql_activerecord_test.rb
├── pp_sql_rails_test.rb
├── pp_sql_test.rb
└── test_helper.rb
/.github/workflows/ruby.yml:
--------------------------------------------------------------------------------
1 | # This workflow uses actions that are not certified by GitHub.
2 | # They are provided by a third-party and are governed by
3 | # separate terms of service, privacy policy, and support
4 | # documentation.
5 | # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6 | # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7 |
8 | name: Ruby
9 |
10 | on:
11 | push:
12 | branches: [ "master" ]
13 | pull_request:
14 | branches: [ "master" ]
15 |
16 | permissions:
17 | contents: read
18 |
19 | jobs:
20 | test:
21 |
22 | runs-on: ubuntu-latest
23 | strategy:
24 | matrix:
25 | ruby-version: ['3.1', '3.2', '3.3']
26 | gemfile:
27 | - gemfiles/rails_7_0.gemfile
28 | - gemfiles/rails_7_1.gemfile
29 | - gemfiles/rails_7_2.gemfile
30 | - gemfiles/rails_8_0.gemfile
31 | - gemfiles/activerecord_7_0.gemfile
32 | - gemfiles/activerecord_7_1.gemfile
33 | - gemfiles/activerecord_7_2.gemfile
34 | - gemfiles/activerecord_8_0.gemfile
35 | exclude:
36 | - ruby-version: '3.1'
37 | gemfile: gemfiles/rails_8_0.gemfile
38 | - ruby-version: '3.1'
39 | gemfile: gemfiles/activerecord_8_0.gemfile
40 |
41 | steps:
42 | - uses: actions/checkout@v3
43 | - name: Set up Ruby
44 | # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
45 | # change this to (see https://github.com/ruby/setup-ruby#versioning):
46 | uses: ruby/setup-ruby@v1
47 | with:
48 | ruby-version: ${{ matrix.ruby-version }}
49 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically
50 | - name: Install gems
51 | env:
52 | BUNDLE_GEMFILE: ${{ matrix.gemfile }}
53 | run: bundle install
54 |
55 | - name: Run tests
56 | env:
57 | BUNDLE_GEMFILE: ${{ matrix.gemfile }}
58 | run: bundle exec rake
59 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .bundle/
2 | log/*.log
3 | Gemfile.lock
4 | *.gem
5 | gemfiles/*.gemfile.lock
6 | gemfiles/.bundle/
7 | .tool_versions
8 | .ruby-version
9 |
--------------------------------------------------------------------------------
/.hound.yml:
--------------------------------------------------------------------------------
1 | rubocop:
2 | config_file: .rubocop.yml
3 | version: 1.22.1
--------------------------------------------------------------------------------
/.overcommit.yml:
--------------------------------------------------------------------------------
1 | # Use this file to configure the Overcommit hooks you wish to use. This will
2 | # extend the default configuration defined in:
3 | # https://github.com/brigade/overcommit/blob/master/config/default.yml
4 | #
5 | # At the topmost level of this YAML file is a key representing type of hook
6 | # being run (e.g. pre-commit, commit-msg, etc.). Within each type you can
7 | # customize each hook, such as whether to only run it on certain files (via
8 | # `include`), whether to only display output if it fails (via `quiet`), etc.
9 | #
10 | # For a complete list of hooks, see:
11 | # https://github.com/brigade/overcommit/tree/master/lib/overcommit/hook
12 | #
13 | # For a complete list of options that you can use to customize hooks, see:
14 | # https://github.com/brigade/overcommit#configuration
15 | #
16 | # Uncomment the following lines to make the configuration take effect.
17 |
18 | PreCommit:
19 | RuboCop:
20 | enabled: true
21 | on_warn: fail # Treat all warnings as failures
22 | AuthorName:
23 | enabled: false
24 | description: 'Check for author name'
25 |
26 | #
27 | # TrailingWhitespace:
28 | # enabled: true
29 | # exclude:
30 | # - '**/db/structure.sql' # Ignore trailing whitespace in generated files
31 | #
32 | #PostCheckout:
33 | # ALL: # Special hook name that customizes all hooks of this type
34 | # quiet: true # Change all post-checkout hooks to only display output on failure
35 | #
36 | # IndexTags:
37 | # enabled: true # Generate a tags file with `ctags` each time HEAD changes
38 |
--------------------------------------------------------------------------------
/.reek:
--------------------------------------------------------------------------------
1 | IrresponsibleModule:
2 | enabled: false
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | Layout/LineLength:
2 | Max: 120
3 | Style/Documentation:
4 | Enabled: false
5 | Metrics/CyclomaticComplexity:
6 | Max: 10
7 | Metrics/BlockLength:
8 | Exclude:
9 | - 'test/**/*'
10 | Lint/ConstantDefinitionInBlock:
11 | Exclude:
12 | - 'test/**/*'
13 | AllCops:
14 | Exclude:
15 | - 'gemfiles/**/*'
16 | NewCops: enable
17 | SuggestExtensions: false
18 |
--------------------------------------------------------------------------------
/Appraisals:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # rubocop:disable Security/Eval
4 | skip_gems_snippet = <<~GEMS
5 | group :local_development do
6 | %w[appraisal overcommit pry reek rubocop rails sqlite3].each { |gem_name| remove_gem gem_name }
7 | end
8 | GEMS
9 |
10 | appraise 'rails-7-0' do
11 | gem 'rails', '~> 7.0.0'
12 | gem 'sqlite3', '~> 1.6'
13 | eval(skip_gems_snippet)
14 | end
15 |
16 | appraise 'rails-7-1' do
17 | gem 'rails', '~> 7.1.0'
18 | gem 'sqlite3', '~> 2.0'
19 | eval(skip_gems_snippet)
20 | end
21 |
22 | appraise 'rails-7-2' do
23 | gem 'rails', '~> 7.2.0'
24 | gem 'sqlite3', '~> 2.0'
25 | eval(skip_gems_snippet)
26 | end
27 |
28 | appraise 'rails-8-0' do
29 | gem 'rails', '~> 8.0.0'
30 | gem 'sqlite3', '~> 2.0'
31 | eval(skip_gems_snippet)
32 | end
33 |
34 | appraise 'activerecord-7-0' do
35 | gem 'activerecord', '~> 7.0.0'
36 | gem 'rake'
37 | gem 'sqlite3', '~> 1.6'
38 | eval(skip_gems_snippet)
39 | end
40 |
41 | appraise 'activerecord-7-1' do
42 | gem 'activerecord', '~> 7.1.0'
43 | gem 'rake'
44 | gem 'sqlite3', '~> 2.0'
45 | eval(skip_gems_snippet)
46 | end
47 |
48 | appraise 'activerecord-7-2' do
49 | gem 'activerecord', '~> 7.2.0'
50 | gem 'rake'
51 | gem 'sqlite3', '~> 2.0'
52 | eval(skip_gems_snippet)
53 | end
54 |
55 | appraise 'activerecord-8-0' do
56 | gem 'activerecord', '~> 8.0.0'
57 | gem 'rake'
58 | gem 'sqlite3', '~> 2.0'
59 | eval(skip_gems_snippet)
60 | end
61 | # rubocop:enable Security/Eval
62 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source 'https://rubygems.org'
4 |
5 | # Declare your gem's dependencies in pp_sql.gemspec.
6 | # Bundler will treat runtime dependencies like base dependencies, and
7 | # development dependencies will be added by default to the :development group.
8 | gemspec
9 |
10 | # Declare any dependencies that are still in development here instead of in
11 | # your gemspec. These might include edge Rails or gems from your path or
12 | # Git. Remember to move these dependencies to your gemspec before releasing
13 | # your gem to rubygems.org.
14 |
15 | # To use a debugger
16 | # gem 'byebug', group: [:development, :test]
17 | #
18 |
19 | # https://stackoverflow.com/questions/79360526/uninitialized-constant-activesupportloggerthreadsafelevellogger-nameerror
20 | gem 'concurrent-ruby', '1.3.4'
21 | gem 'minitest'
22 | gem 'minitest-focus'
23 | gem 'minitest-reporters'
24 |
25 | group :local_development do
26 | gem 'appraisal'
27 | gem 'overcommit'
28 | gem 'pry'
29 | gem 'rails', '>= 7.0'
30 | gem 'reek'
31 | gem 'rubocop', '~> 1.69.0'
32 | gem 'sqlite3', '>= 1.4'
33 | end
34 |
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2023 Kvokka
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 | # PpSql
2 |
3 | [![Version ][rubygems_badge]][rubygems]
4 | [![Codacy Badge ][codacy_badge]][codacy]
5 | [![Reviewed by Hound ][hound_badge]][hound]
6 | [
](https://api.gitsponsors.com/api/badge/link?p=J9d+7zEGJS+BQMhX3FZDy2lWmzWp75oJZulj80NsvTrAkDEWcEC5PzkwUCDB/oqWGOfl1rwmFSi7crAJTxB6ww==)
7 |
8 | Replace standard `ActiveRecord#to_sql` method with
9 | [`anbt-sql-formatter`][anbt-sql-formatter-link]
10 | gem for pretty SQL code output in console. Rails log will be formatted also.
11 | Example output:
12 |
13 | ![log][log-img]
14 |
15 | Or in console
16 |
17 | ![console][console-img]
18 |
19 | ## Require
20 |
21 | Ruby 3.1+
22 |
23 | ## Rails
24 |
25 | Rails 7.0+ (optional), will be injected automatically
26 |
27 | ## Legacy
28 |
29 | You can use version `~> 0.2` of this gem with Ruby 2.2, 2.3 and/or Rails 4.0, 4.1
30 |
31 | ## Usage
32 |
33 | ```
34 | Post.first.to_sql
35 | ```
36 |
37 | for easy and clean usage with custom string you can use:
38 |
39 | ```
40 | class MyAwesomeDecoratedString < String
41 | include PpSql::ToSqlBeautify
42 | end
43 | ```
44 |
45 | ## Installation
46 |
47 | add in Gemfile
48 |
49 | ```
50 | gem 'pp_sql', group: :development
51 | ```
52 |
53 | And then execute:
54 |
55 | ```bash
56 | bundle
57 | ```
58 |
59 | ## With other formatters
60 |
61 | If you are `pry` user, or use custom output formatter, use `puts` for output whitespaces,
62 | like `puts User.all.to_sql`, or use `User.all.pp_sql`.
63 |
64 | ## With Rails
65 |
66 | If you do not want to rewrite default `#to_sql` method you may specify
67 | `PpSql.rewrite_to_sql_method=false` in initializers.
68 |
69 | You can also disable log formatting by specifying `PpSql.add_rails_logger_formatting=false`
70 | in initializers.
71 |
72 | ### Add to Application record
73 |
74 | I found usefull this trick:
75 |
76 | ```
77 | class ApplicationRecord < ActiveRecord::Base
78 | include PpSql::ToSqlBeautify if defined?(Rails::Console)
79 |
80 | self.abstract_class = true
81 | end
82 | ```
83 |
84 | ### Supported by
85 |
86 | [![jetbrains][jetbrains-img-link]][jetbrains-link]
87 |
88 | ## Contributing
89 |
90 | Running the tests requires sqlite. To run the tests for different combinations of dependency
91 | versions, run `bundle exec appraisal install` followed by `bundle exec appraisal rake`.
92 |
93 | ## License
94 |
95 | The gem is available as open source under the terms of the
96 | [MIT License][mit-licence-link].
97 |
98 | [rubygems_badge]: http://img.shields.io/gem/v/pp_sql.svg
99 | [rubygems]: https://rubygems.org/gems/pp_sql
100 | [codacy_badge]: https://app.codacy.com/project/badge/Grade/0394889311ea49529ddea12baac9b699
101 | [codacy]: https://www.codacy.com/gh/kvokka/pp_sql/dashboard?utm_source=github.com&utm_medium=referral&utm_content=kvokka/pp_sql&utm_campaign=Badge_Grade
102 | [hound_badge]: https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg
103 | [hound]: https://houndci.com
104 |
105 | [anbt-sql-formatter-link]: https://github.com/sonota88/anbt-sql-formatter
106 | [mit-licence-link]: http://opensource.org/licenses/MIT
107 | [jetbrains-link]: https://www.jetbrains.com/?from=pp_sql
108 | [jetbrains-img-link]: https://raw.githubusercontent.com/kvokka/pp_sql/master/img/jetbrains-variant-3.svg?sanitize=true
109 |
110 | [log-img]: https://raw.githubusercontent.com/kvokka/pp_sql/master/img/log.png
111 | [console-img]: https://raw.githubusercontent.com/kvokka/pp_sql/master/img/console.png
112 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'rubygems'
4 | begin
5 | require 'bundler/setup'
6 | rescue LoadError
7 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
8 | end
9 |
10 | require 'rdoc/task'
11 |
12 | RDoc::Task.new(:rdoc) do |rdoc|
13 | rdoc.rdoc_dir = 'rdoc'
14 | rdoc.title = 'PpSql'
15 | rdoc.options << '--line-numbers'
16 | rdoc.rdoc_files.include('README.md')
17 | rdoc.rdoc_files.include('lib/**/*.rb')
18 | end
19 |
20 | require 'bundler/gem_tasks'
21 |
22 | require 'rake/testtask'
23 |
24 | Rake::TestTask.new(:test) do |t|
25 | t.libs << %w[test lib]
26 | t.pattern = 'test/**/*_test.rb'
27 | t.verbose = false
28 | end
29 |
30 | task default: :test
31 |
--------------------------------------------------------------------------------
/gemfiles/activerecord_7_0.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "concurrent-ruby", "1.3.4"
6 | gem "minitest"
7 | gem "minitest-focus"
8 | gem "minitest-reporters"
9 | gem "activerecord", "~> 7.0.0"
10 | gem "rake"
11 | gem "sqlite3", "~> 1.6"
12 |
13 | group :local_development do
14 |
15 | end
16 |
17 | gemspec path: "../"
18 |
--------------------------------------------------------------------------------
/gemfiles/activerecord_7_1.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "concurrent-ruby", "1.3.4"
6 | gem "minitest"
7 | gem "minitest-focus"
8 | gem "minitest-reporters"
9 | gem "activerecord", "~> 7.1.0"
10 | gem "rake"
11 | gem "sqlite3", "~> 2.0"
12 |
13 | group :local_development do
14 |
15 | end
16 |
17 | gemspec path: "../"
18 |
--------------------------------------------------------------------------------
/gemfiles/activerecord_7_2.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "concurrent-ruby", "1.3.4"
6 | gem "minitest"
7 | gem "minitest-focus"
8 | gem "minitest-reporters"
9 | gem "activerecord", "~> 7.2.0"
10 | gem "rake"
11 | gem "sqlite3", "~> 2.0"
12 |
13 | group :local_development do
14 |
15 | end
16 |
17 | gemspec path: "../"
18 |
--------------------------------------------------------------------------------
/gemfiles/activerecord_8_0.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "concurrent-ruby", "1.3.4"
6 | gem "minitest"
7 | gem "minitest-focus"
8 | gem "minitest-reporters"
9 | gem "activerecord", "~> 8.0.0"
10 | gem "rake"
11 | gem "sqlite3", "~> 2.0"
12 |
13 | group :local_development do
14 |
15 | end
16 |
17 | gemspec path: "../"
18 |
--------------------------------------------------------------------------------
/gemfiles/rails_7_0.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "concurrent-ruby", "1.3.4"
6 | gem "minitest"
7 | gem "minitest-focus"
8 | gem "minitest-reporters"
9 | gem "rails", "~> 7.0.0"
10 | gem "sqlite3", "~> 1.6"
11 |
12 | group :local_development do
13 |
14 | end
15 |
16 | gemspec path: "../"
17 |
--------------------------------------------------------------------------------
/gemfiles/rails_7_1.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "concurrent-ruby", "1.3.4"
6 | gem "minitest"
7 | gem "minitest-focus"
8 | gem "minitest-reporters"
9 | gem "rails", "~> 7.1.0"
10 | gem "sqlite3", "~> 2.0"
11 |
12 | group :local_development do
13 |
14 | end
15 |
16 | gemspec path: "../"
17 |
--------------------------------------------------------------------------------
/gemfiles/rails_7_2.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "concurrent-ruby", "1.3.4"
6 | gem "minitest"
7 | gem "minitest-focus"
8 | gem "minitest-reporters"
9 | gem "rails", "~> 7.2.0"
10 | gem "sqlite3", "~> 2.0"
11 |
12 | group :local_development do
13 |
14 | end
15 |
16 | gemspec path: "../"
17 |
--------------------------------------------------------------------------------
/gemfiles/rails_8_0.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "concurrent-ruby", "1.3.4"
6 | gem "minitest"
7 | gem "minitest-focus"
8 | gem "minitest-reporters"
9 | gem "rails", "~> 8.0.0"
10 | gem "sqlite3", "~> 2.0"
11 |
12 | group :local_development do
13 |
14 | end
15 |
16 | gemspec path: "../"
17 |
--------------------------------------------------------------------------------
/img/console.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kvokka/pp_sql/50b7036f2d22ac72b483f447aaea80ffd8058033/img/console.png
--------------------------------------------------------------------------------
/img/jetbrains-variant-3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
74 |
--------------------------------------------------------------------------------
/img/log.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kvokka/pp_sql/50b7036f2d22ac72b483f447aaea80ffd8058033/img/log.png
--------------------------------------------------------------------------------
/lib/pp_sql.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module PpSql
4 | WHITE_SPACE = ' '
5 |
6 | # if you do not want to rewrite AR native method #to_sql
7 | # you may switch this setting to false in initializer
8 | class << self
9 | attr_accessor :rewrite_to_sql_method, :add_rails_logger_formatting
10 | end
11 | self.rewrite_to_sql_method = true
12 | self.add_rails_logger_formatting = true
13 |
14 | module Formatter
15 | private
16 |
17 | def _sql_formatter
18 | return @_sql_formatter if defined?(@_sql_formatter) && @_sql_formatter
19 |
20 | require 'anbt-sql-formatter/formatter'
21 | rule = AnbtSql::Rule.new
22 | rule.keyword = AnbtSql::Rule::KEYWORD_UPPER_CASE
23 | %w[count sum substr date].each { |func_name| rule.function_names << func_name.upcase }
24 | rule.indent_string = WHITE_SPACE
25 | @_sql_formatter = AnbtSql::Formatter.new(rule)
26 | end
27 | end
28 |
29 | module ToSqlBeautify
30 | def to_sql
31 | if ::PpSql.rewrite_to_sql_method
32 | extend Formatter
33 | _sql_formatter.format(defined?(super) ? super.dup : dup)
34 | else
35 | defined?(super) ? super : self
36 | end
37 | end
38 |
39 | def pp_sql
40 | if ::PpSql.rewrite_to_sql_method
41 | puts to_sql
42 | else
43 | extend Formatter
44 | puts _sql_formatter.format(to_sql.dup)
45 | end
46 | end
47 | end
48 |
49 | module LogSubscriberPrettyPrint
50 | include Formatter
51 |
52 | def sql(event)
53 | return super unless ::PpSql.add_rails_logger_formatting
54 |
55 | e = event.dup
56 | e.payload[:sql] = _sql_formatter.format(e.payload[:sql].dup)
57 | super(e)
58 | end
59 | end
60 |
61 | if defined?(::Rails::Railtie)
62 | class Railtie < Rails::Railtie
63 | initializer 'pp_sql.override_to_sql' do
64 | ActiveSupport.on_load(:active_record) do
65 | ActiveRecord::Relation.prepend ToSqlBeautify
66 | ActiveRecord::LogSubscriber.prepend LogSubscriberPrettyPrint
67 | end
68 | end
69 | end
70 | end
71 | end
72 |
--------------------------------------------------------------------------------
/lib/pp_sql/version.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module PpSql
4 | VERSION = '2.1.0'
5 | end
6 |
--------------------------------------------------------------------------------
/pp_sql.gemspec:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | $LOAD_PATH.push File.expand_path('lib', __dir__)
4 |
5 | # Maintain your gem's version:
6 | require 'pp_sql/version'
7 |
8 | # Describe your gem and declare its dependencies:
9 | Gem::Specification.new do |s|
10 | s.name = 'pp_sql'
11 | s.version = PpSql::VERSION
12 | s.authors = ['Kvokka']
13 | s.email = ['kvokka@yahoo.com']
14 | s.homepage = 'https://github.com/kvokka/pp_sql'
15 | s.summary = 'Beautify SQL output of ActiveRecord#to_sql'
16 | s.description = 'Helps to save your eyes, when reading hardcore SQL requests in console'
17 | s.license = 'MIT'
18 |
19 | s.files = Dir['lib/**/*', 'MIT-LICENSE', 'Rakefile', 'README.md']
20 |
21 | s.required_ruby_version = '>= 3.1.0'
22 |
23 | s.add_dependency 'activerecord'
24 | s.add_dependency 'anbt-sql-formatter', '~> 0.1.0'
25 |
26 | s.metadata['rubygems_mfa_required'] = 'true'
27 | end
28 |
--------------------------------------------------------------------------------
/test/pp_sql_activerecord_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'test_helper'
4 | require 'sqlite3'
5 | require 'active_record'
6 |
7 | module ActiveRecord
8 | class Base
9 | establish_connection(adapter: 'sqlite3', database: ':memory:')
10 | connection.create_table(:users) { |t| t.string :name }
11 | self.logger = Logger.new(::LOGGER)
12 | end
13 |
14 | class Relation
15 | prepend PpSql::ToSqlBeautify
16 | end
17 |
18 | class LogSubscriber
19 | prepend PpSql::LogSubscriberPrettyPrint
20 | end
21 | end
22 |
23 | class User < ActiveRecord::Base; end
24 |
25 | describe PpSql do
26 | after { clear_logs! && set_default_config! }
27 |
28 | it 'ActiveRecord logs with formatted output' do
29 | User.create
30 | assert(LOGGER.string.lines.detect { |line| line =~ /INTO\n/ })
31 | clear_logs!
32 | User.first
33 | assert_equal LOGGER.string.lines.count, 6
34 | end
35 |
36 | it 'ActiveRecord logs with default output' do
37 | PpSql.add_rails_logger_formatting = false
38 | User.create
39 | clear_logs!
40 | User.first
41 | assert_equal LOGGER.string.lines.count, 1
42 | end
43 |
44 | it 'to_sql formats a relation properly' do
45 | User.create
46 | assert_equal User.all.to_sql, "SELECT\n \"users\" . *\n FROM\n \"users\""
47 | end
48 |
49 | it 'to_sql with default output' do
50 | PpSql.rewrite_to_sql_method = false
51 | User.create
52 | assert_equal User.all.to_sql.lines.count, 1
53 | end
54 |
55 | it 'to_sql with default output but formatted logs' do
56 | PpSql.rewrite_to_sql_method = false
57 | User.create
58 | assert_equal User.all.to_sql.lines.count, 1
59 | clear_logs!
60 | User.first
61 | assert_equal LOGGER.string.lines.count, 6
62 | end
63 |
64 | it 'pp_sql formats a relation properly' do
65 | User.create
66 | out, = capture_io do
67 | User.all.pp_sql
68 | end
69 | assert_equal out, "SELECT\n \"users\" . *\n FROM\n \"users\"\n"
70 | end
71 |
72 | it 'pp_sql formats frozen strings properly' do
73 | PpSql.rewrite_to_sql_method = false
74 | User.create
75 | frozen_clause = 'id > 0'
76 | out, = capture_io do
77 | User.all.where(frozen_clause).pp_sql
78 | end
79 | assert_equal out.lines.count, 8
80 | end
81 |
82 | private
83 |
84 | def clear_logs!
85 | LOGGER.string.clear
86 | end
87 |
88 | def set_default_config!
89 | PpSql.rewrite_to_sql_method = true
90 | PpSql.add_rails_logger_formatting = true
91 | end
92 | end
93 |
--------------------------------------------------------------------------------
/test/pp_sql_rails_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | return if Gem::Specification.find_all_by_name('rails').empty?
4 |
5 | require 'rails'
6 | require 'test_helper'
7 | require 'active_record'
8 | require 'sqlite3'
9 | ENV['RAILS_ENV'] = 'test'
10 |
11 | module TeatApp
12 | class Application < Rails::Application
13 | config.eager_load = false
14 | initialize!
15 | end
16 | end
17 |
18 | module ActiveRecord
19 | class Base
20 | establish_connection(adapter: 'sqlite3', database: ':memory:')
21 | connection.create_table(:users) { |t| t.string :name }
22 | self.logger = Logger.new(::LOGGER)
23 | end
24 | end
25 |
26 | class User < ActiveRecord::Base; end
27 |
28 | describe PpSql do
29 | after { clear_logs! && set_default_config! }
30 |
31 | it 'Rails & ActiveRecord with formatted output' do
32 | User.create
33 | assert(LOGGER.string.lines.detect { |line| line =~ /INTO\n/ })
34 | clear_logs!
35 | User.first
36 | assert_equal LOGGER.string.lines.count, 6
37 | end
38 |
39 | it 'Rails & ActiveRecord with default output' do
40 | PpSql.add_rails_logger_formatting = false
41 | User.create
42 | clear_logs!
43 | User.first
44 | assert_equal LOGGER.string.lines.count, 1
45 | end
46 |
47 | private
48 |
49 | def clear_logs!
50 | LOGGER.string.clear
51 | end
52 |
53 | def set_default_config!
54 | PpSql.add_rails_logger_formatting = true
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/test/pp_sql_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'test_helper'
4 |
5 | describe PpSql do
6 | class SubString < String
7 | include PpSql::ToSqlBeautify
8 | end
9 |
10 | let(:str) { SubString.new 'SELECT COUNT(*) FROM "users"' }
11 |
12 | after { PpSql.rewrite_to_sql_method = true }
13 |
14 | it 'parses provided sql' do
15 | assert_equal str.to_sql.lines.count, 4
16 | end
17 |
18 | it 'returns string as is' do
19 | PpSql.rewrite_to_sql_method = false
20 | assert_equal str.to_sql.lines.count, 1
21 | end
22 |
23 | it 'formats and prints with pp_sql' do
24 | out, = capture_io do
25 | str.pp_sql
26 | end
27 |
28 | assert_equal out, "SELECT\n COUNT( * )\n FROM\n \"users\"\n"
29 | end
30 |
31 | it 'formats and prints with pp_sql if rewrite_to_sql_method is false' do
32 | PpSql.rewrite_to_sql_method = false
33 | out, = capture_io do
34 | str.pp_sql
35 | end
36 |
37 | assert_equal out, "SELECT\n COUNT( * )\n FROM\n \"users\"\n"
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'minitest/autorun'
4 | require 'minitest/focus'
5 | require 'pp_sql'
6 |
7 | require 'minitest/reporters'
8 |
9 | LOGGER = StringIO.new
10 |
11 | Minitest::Reporters.use!
12 |
--------------------------------------------------------------------------------