postgres_utility 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 38052dc3eff9df3a9e8f7d5ef610c4f6eb42cdb818db0e38bb54d5a9d9a20f4f
4
+ data.tar.gz: 1668a26b111e84f40c71402bbb7377c59dbb6bd721a595ce4aa75a7e40767a6b
5
+ SHA512:
6
+ metadata.gz: 2563e9201f134f375c51b04f0b347fc3527457c1c91cc142fa8cbd9646de7e26d192919b5707d5265bd53e42af14697ee25d35293a9edcb31e01c601c626412b
7
+ data.tar.gz: 783974536590bbab6315b0864eb93d3819bad5caafaa46769db8057bc8480cef69d1b997af57c657f7cdb922ab97086e867955747e46ac606e9ce752cecff3df
@@ -0,0 +1,63 @@
1
+ version: 2
2
+ jobs:
3
+ build:
4
+ working_directory: ~/YourMechanic/postgres_utility
5
+ parallelism: 1
6
+ shell: /bin/bash --login
7
+
8
+ environment:
9
+ CIRCLE_ARTIFACTS: /tmp/circleci-artifacts
10
+ CIRCLE_TEST_REPORTS: /tmp/circleci-test-results
11
+ docker:
12
+ - image: circleci/ruby:2.6.2
13
+ environment:
14
+ RAILS_ENV: test
15
+ PGHOST: 127.0.0.1
16
+ PGUSER: postgres
17
+ - image: circleci/postgres:9.5.15
18
+ environment:
19
+ POSTGRES_USER: postgres
20
+ POSTGRES_DB: postgres
21
+ steps:
22
+ - checkout
23
+ - run: mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS
24
+ - restore_cache:
25
+ keys:
26
+ # This branch if available
27
+ - v2-dep-{{ .Branch }}-
28
+ # Default branch if not
29
+ - v2-dep-master-
30
+ # Any branch if there are none on the default branch - this should be unnecessary if you have your default branch configured correctly
31
+ - v2-dep-
32
+ - run:
33
+ name: Install bundler for postgres_utility
34
+ working_directory: ~/YourMechanic/postgres_utility
35
+ command: gem install bundler:2.2.11
36
+ - run:
37
+ name: Install Gems for postgres_utility
38
+ working_directory: ~/YourMechanic/postgres_utility
39
+ command: bundle install
40
+ # Save dependency cache
41
+ - save_cache:
42
+ key: v2-dep-{{ .Branch }}-{{ epoch }}
43
+ paths:
44
+ - vendor/bundle
45
+ - ~/virtualenvs
46
+ - ~/.m2
47
+ - ~/.ivy2
48
+ - ~/.bundle
49
+ - run: sudo apt-get update && sudo apt-get install postgresql 9.5 && sudo apt-get install nodejs
50
+ - run:
51
+ working_directory: ~/YourMechanic/postgres_utility
52
+ command: bundle exec rubocop
53
+ - run:
54
+ working_directory: ~/YourMechanic/postgres_utility
55
+ command: bundle exec rspec --colour --drb --profile -fd --format progress $(circleci tests glob "spec/*_spec.rb" | circleci tests split)
56
+ - store_test_results:
57
+ path: /tmp/circleci-test-results
58
+ - store_artifacts:
59
+ path: /tmp/circleci-artifacts
60
+ - store_artifacts:
61
+ path: /tmp/circleci-test-results
62
+ - store_artifacts:
63
+ path: postgres_utility/coverage
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ .byebug_history
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,24 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+
4
+ Metrics/PerceivedComplexity:
5
+ Enabled: false
6
+
7
+ Metrics/CyclomaticComplexity:
8
+ Enabled: false
9
+
10
+ Metrics/AbcSize:
11
+ Enabled: false
12
+
13
+ Gemspec/RequiredRubyVersion:
14
+ Enabled: false
15
+
16
+ Layout/LineLength:
17
+ Max: 120
18
+
19
+ Metrics/MethodLength:
20
+ Max: 25
21
+ Metrics/ClassLength:
22
+ Max: 300
23
+ Metrics/BlockLength:
24
+ Max: 50
@@ -0,0 +1,84 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
+
9
+ ## Our Standards
10
+
11
+ Examples of behavior that contributes to a positive environment for our community include:
12
+
13
+ * Demonstrating empathy and kindness toward other people
14
+ * Being respectful of differing opinions, viewpoints, and experiences
15
+ * Giving and gracefully accepting constructive feedback
16
+ * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
17
+ * Focusing on what is best not just for us as individuals, but for the overall community
18
+
19
+ Examples of unacceptable behavior include:
20
+
21
+ * The use of sexualized language or imagery, and sexual attention or
22
+ advances of any kind
23
+ * Trolling, insulting or derogatory comments, and personal or political attacks
24
+ * Public or private harassment
25
+ * Publishing others' private information, such as a physical or email
26
+ address, without their explicit permission
27
+ * Other conduct which could reasonably be considered inappropriate in a
28
+ professional setting
29
+
30
+ ## Enforcement Responsibilities
31
+
32
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
33
+
34
+ Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
35
+
36
+ ## Scope
37
+
38
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
39
+
40
+ ## Enforcement
41
+
42
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at sachinsaxena1996@gmail.com. All complaints will be reviewed and investigated promptly and fairly.
43
+
44
+ All community leaders are obligated to respect the privacy and security of the reporter of any incident.
45
+
46
+ ## Enforcement Guidelines
47
+
48
+ Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
49
+
50
+ ### 1. Correction
51
+
52
+ **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
53
+
54
+ **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
55
+
56
+ ### 2. Warning
57
+
58
+ **Community Impact**: A violation through a single incident or series of actions.
59
+
60
+ **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
61
+
62
+ ### 3. Temporary Ban
63
+
64
+ **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
65
+
66
+ **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
67
+
68
+ ### 4. Permanent Ban
69
+
70
+ **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
71
+
72
+ **Consequence**: A permanent ban from any sort of public interaction within the community.
73
+
74
+ ## Attribution
75
+
76
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,
77
+ available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
78
+
79
+ Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
80
+
81
+ [homepage]: https://www.contributor-covenant.org
82
+
83
+ For answers to common questions about this code of conduct, see the FAQ at
84
+ https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in postgres_utility.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,79 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ postgres_utility (1.0.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (5.2.6)
10
+ activesupport (= 5.2.6)
11
+ activerecord (5.2.6)
12
+ activemodel (= 5.2.6)
13
+ activesupport (= 5.2.6)
14
+ arel (>= 9.0)
15
+ activesupport (5.2.6)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 0.7, < 2)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ arel (9.0.0)
21
+ ast (2.4.2)
22
+ byebug (11.1.3)
23
+ concurrent-ruby (1.1.9)
24
+ diff-lcs (1.4.4)
25
+ i18n (1.8.10)
26
+ concurrent-ruby (~> 1.0)
27
+ minitest (5.14.4)
28
+ parallel (1.21.0)
29
+ parser (3.0.2.0)
30
+ ast (~> 2.4.1)
31
+ pg (1.2.3)
32
+ rainbow (3.0.0)
33
+ rake (13.0.6)
34
+ regexp_parser (2.1.1)
35
+ rexml (3.2.5)
36
+ rspec (3.10.0)
37
+ rspec-core (~> 3.10.0)
38
+ rspec-expectations (~> 3.10.0)
39
+ rspec-mocks (~> 3.10.0)
40
+ rspec-core (3.10.1)
41
+ rspec-support (~> 3.10.0)
42
+ rspec-expectations (3.10.1)
43
+ diff-lcs (>= 1.2.0, < 2.0)
44
+ rspec-support (~> 3.10.0)
45
+ rspec-mocks (3.10.2)
46
+ diff-lcs (>= 1.2.0, < 2.0)
47
+ rspec-support (~> 3.10.0)
48
+ rspec-support (3.10.2)
49
+ rubocop (1.21.0)
50
+ parallel (~> 1.10)
51
+ parser (>= 3.0.0.0)
52
+ rainbow (>= 2.2.2, < 4.0)
53
+ regexp_parser (>= 1.8, < 3.0)
54
+ rexml
55
+ rubocop-ast (>= 1.9.1, < 2.0)
56
+ ruby-progressbar (~> 1.7)
57
+ unicode-display_width (>= 1.4.0, < 3.0)
58
+ rubocop-ast (1.11.0)
59
+ parser (>= 3.0.1.1)
60
+ ruby-progressbar (1.11.0)
61
+ thread_safe (0.3.6)
62
+ tzinfo (1.2.9)
63
+ thread_safe (~> 0.1)
64
+ unicode-display_width (2.1.0)
65
+
66
+ PLATFORMS
67
+ x86_64-linux
68
+
69
+ DEPENDENCIES
70
+ activerecord (= 5.2.6)
71
+ byebug
72
+ pg (= 1.2.3)
73
+ postgres_utility!
74
+ rake (~> 13.0)
75
+ rspec (~> 3.0)
76
+ rubocop (~> 1.7)
77
+
78
+ BUNDLED WITH
79
+ 2.2.11
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 YourMechanic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 sachinsaxena1996
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,214 @@
1
+ # PostgresUtility
2
+
3
+ This awesome gem provides an api to execute multiple useful operations on ActiveRecord table having postgres as database.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'postgres_utility'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install postgres_utility
20
+
21
+ ## Usage
22
+
23
+ Following are use cases
24
+
25
+ ### To get the current db name
26
+ ```ruby
27
+ PostgresUtility.db_name
28
+ ```
29
+
30
+ ### To get a db connection object
31
+ ```ruby
32
+ PostgresUtility.rails_connection
33
+ ```
34
+
35
+ ### Boolean method to check if a migration is pending
36
+ ```ruby
37
+ PostgresUtility.pending_migration?
38
+ ```
39
+
40
+ ### To get the db connection config object
41
+ ```ruby
42
+ PostgresUtility.db_connection_config
43
+ ```
44
+
45
+ ### To get the db_adapter_name
46
+ ```ruby
47
+ PostgresUtility.db_adapter_name
48
+ ```
49
+
50
+ ### To find if current adapter is postgresql
51
+ ```ruby
52
+ PostgresUtility.postgresql?
53
+ ```
54
+
55
+ ### To find the current migration version
56
+ ```ruby
57
+ PostgresUtility.migration_version
58
+ ```
59
+
60
+ ### To find the current db_version
61
+ ```ruby
62
+ PostgresUtility.db_version
63
+ ```
64
+
65
+ ### To find the database size
66
+ ```ruby
67
+ PostgresUtility.db_size
68
+ ```
69
+
70
+ ### To create database
71
+ ```ruby
72
+ PostgresUtility.create_database
73
+ ```
74
+
75
+ ### To drop database
76
+ ```ruby
77
+ PostgresUtility.drop_database
78
+ ```
79
+
80
+ ### To recreate database
81
+ ```ruby
82
+ PostgresUtility.recreate_database
83
+ ```
84
+
85
+ ### To form query that copies records from source to destination table
86
+ ```ruby
87
+ PostgresUtility.copy_table_query(TestModel, DestinationTestModel)
88
+ ```
89
+
90
+ ### To perform vacuum and analyze on a table
91
+ ```ruby
92
+ PostgresUtility.vacuum_analyze(TestModel)
93
+ ```
94
+
95
+ ### To dump multiple tables to a csv
96
+ ```ruby
97
+ PostgresUtility.multi_dump_to_csv([{ tbl: TestModel, csv_path: csv_path }])
98
+ ```
99
+
100
+ ### To dump query results to a csv
101
+ ```ruby
102
+ PostgresUtility.multi_dump_query_result_to_csv("select * from test_models", csv_path)
103
+ ```
104
+
105
+ ### To fix table sequence
106
+ ```ruby
107
+ PostgresUtility.fix_sequence_value(TestModel)
108
+ ```
109
+
110
+ ### To fix table sequence with a cap value
111
+ ```ruby
112
+ PostgresUtility.fix_sequence_value_with_cap(TestModel)
113
+ ```
114
+
115
+ ### To a random record from table
116
+ ```ruby
117
+ PostgresUtility.get_random_record(TestModel)
118
+ ```
119
+
120
+ ### To execute a command with system with print
121
+ ```ruby
122
+ PostgresUtility.system_with_print("ls")
123
+ ```
124
+
125
+ ### To batch_insert of records
126
+ ```ruby
127
+ PostgresUtility.batch_insert(model: TestModel, values: [{ id: 10, data: "new_record_1" },
128
+ { id: 11, data: "new_record_2" }])
129
+ ```
130
+
131
+ ### To save data of a given table to a given file
132
+ ```ruby
133
+ PostgresUtility.pg_save_data(file_path, 'test_models')
134
+ ```
135
+
136
+ ### truncates a given table
137
+ ```ruby
138
+ PostgresUtility.truncate_table(PostgresUtility.rails_connection, "test_models")
139
+ ```
140
+
141
+ ### truncates table and populates from a csv
142
+ ```ruby
143
+ PostgresUtility.multi_truncate_reset_populate_from_csv([{ tblcls: TestModel, csv_path: csv_path }])
144
+ ```
145
+
146
+ ### To fix sequence value of a table
147
+ ```ruby
148
+ PostgresUtility.fix_sequence_value(TestModel)
149
+ ```
150
+
151
+ ### To fix sequence value of a table with cap
152
+ ```ruby
153
+ PostgresUtility.fix_sequence_value_with_cap(TestModel)
154
+ ```
155
+
156
+ ### To set up primary key of a table
157
+ ```ruby
158
+ PostgresUtility.setup_primary_key(TestModel, 'user_id')
159
+ ```
160
+
161
+ ### To delete primary key of a table
162
+ ```ruby
163
+ PostgresUtility.delete_primary_key(TestModel)
164
+ ```
165
+
166
+ ### To dump db to a file
167
+ ```ruby
168
+ PostgresUtility.pg_dump_custom('Test_Model.sql')
169
+ ```
170
+
171
+ ### To restore data and schema from a file
172
+ ```ruby
173
+ PostgresUtility.pg_restore_data_and_schema('db_Test_Model.sql')
174
+ ```
175
+
176
+ ### To load db
177
+ ```ruby
178
+ PostgresUtility.pg_load('db_Test_Model.sql')
179
+ ```
180
+
181
+ ### To truncate a table
182
+ ```ruby
183
+ PostgresUtility.truncate_table(conn, 'test_models')
184
+ ```
185
+
186
+ ### To delete records from a table
187
+ ```ruby
188
+ PostgresUtility.clear_table(conn, 'test_models')
189
+ ```
190
+
191
+ ### To truncate table and reset sequence
192
+ ```ruby
193
+ PostgresUtility.clear_table_reset_sequence(TestModel)
194
+ ```
195
+
196
+
197
+
198
+ ## Development
199
+
200
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
201
+
202
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
203
+
204
+ ## Contributing
205
+
206
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/postgres_utility. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/postgres_utility/blob/master/CODE_OF_CONDUCT.md).
207
+
208
+ ## License
209
+
210
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
211
+
212
+ ## Code of Conduct
213
+
214
+ Everyone interacting in the PostgresUtility project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/postgres_utility/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'postgres_utility'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PostgresUtility
4
+ VERSION = '1.0.0'
5
+ end
@@ -0,0 +1,502 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'postgres_utility/version'
4
+
5
+ # rubocop:disable Layout/LineLength, Metrics/ModuleLength
6
+
7
+ require 'English'
8
+ require 'active_record'
9
+
10
+ # PostgresUtility module
11
+ module PostgresUtility
12
+ extend self
13
+
14
+ DEFAULT_BATCH_SIZE = 1000
15
+
16
+ # Shorthand for rails environment based connection
17
+ def rails_connection(cls = nil)
18
+ cls ||= ActiveRecord::Base
19
+ cls.connection
20
+ end
21
+
22
+ # Copied from db:migrate:status
23
+ def pending_migration?
24
+ db_list = rails_connection
25
+ .select_values("SELECT version FROM
26
+ #{ActiveRecord::Migrator.schema_migrations_table_name}")
27
+ db_list.map! { |version| format('%.3d', version) }
28
+ ActiveRecord::Migrator.migrations_paths.each do |path|
29
+ Dir.foreach(Rails.root.join(path)) do |file|
30
+ # match "20091231235959_some_name.rb" and "001_some_name.rb" pattern
31
+ if match_data == /^(\d{3,})_(.+)\.rb$/.match(file)
32
+ is_up = db_list.delete(match_data[1])
33
+ return true unless is_up
34
+ end
35
+ end
36
+ end
37
+ false
38
+ end
39
+
40
+ def db_name
41
+ rails_connection.current_database
42
+ end
43
+
44
+ def db_connection_config
45
+ config = ActiveRecord::Base.connection_config
46
+ config = rails_connection.config if config[:adapter].match(/makara/i)
47
+ config
48
+ end
49
+
50
+ def db_adapter_name
51
+ db_connection_config[:adapter]
52
+ end
53
+
54
+ def postgresql?
55
+ !!db_adapter_name.match(/postgresql/i)
56
+ end
57
+
58
+ def migration_version
59
+ ActiveRecord::Migrator.current_version
60
+ end
61
+
62
+ def db_version
63
+ rails_connection.select_value('select version();')
64
+ end
65
+
66
+ def db_size
67
+ rails_connection.select_value("select pg_database_size('#{db_name}');").to_i
68
+ end
69
+
70
+ # Returns true if created, false if already exists, raise if failed.
71
+ def create_database
72
+ # Stolen from activerecord-3.2.3\lib\active_record\railties\databases.rake
73
+ raise 'Not implemented' unless postgresql?
74
+
75
+ begin
76
+ rails_connection.create_database(db_name)
77
+ true
78
+ rescue PG::Error, ActiveRecord::StatementInvalid => e
79
+ return false if e.to_s.include? "database \"#{db_name}\" already exists"
80
+
81
+ raise e
82
+ end
83
+ end
84
+
85
+ def drop_database
86
+ rails_connection.drop_database(db_name)
87
+ end
88
+
89
+ def recreate_database
90
+ raise unless Rails.env.development? || Rails.env.test?
91
+ return if create_database # Try create first
92
+
93
+ Rails.logger.debug("Recreate the DB:#{db_name}\n")
94
+
95
+ if postgresql?
96
+ drop_database
97
+ create_database
98
+ else # My sql
99
+ c = rails_connection
100
+ c.recreate_database(db_name)
101
+ c.execute("USE `#{db_name}`;")
102
+ end
103
+ nil # void function
104
+ end
105
+
106
+ # rubocop:disable Metrics/MethodLength
107
+
108
+ def copy_table_query(src_table_class, dest_table_class, opts = {})
109
+ unless src_table_class.respond_to?(:table_name)
110
+ raise StandardError,
111
+ "#{src_table_class} must be an ActiveRecord::Base Class"
112
+ end
113
+ unless dest_table_class.respond_to?(:table_name)
114
+ raise StandardError,
115
+ "#{dest_table_class} must be an ActiveRecord::Base Class"
116
+ end
117
+
118
+ conn = rails_connection(opts[:cls])
119
+ src_table = src_table_class.table_name
120
+ dest_table = dest_table_class.table_name
121
+ raise StandardError, "#{src_table} Table missing!" unless conn.tables.include?(src_table)
122
+ raise StandardError, "#{dest_table} Table missing!" unless conn.tables.include?(dest_table)
123
+
124
+ query = ''
125
+ # truncate dest_table and insert into dest_table from src_table,
126
+ # then vacuum dest_table
127
+ query += "TRUNCATE TABLE #{dest_table};\n"
128
+ id = dest_table_class.primary_key
129
+ schema = 'public'
130
+ schema = dest_table.split('.').first if dest_table.include?('.')
131
+ tbl_without_schema_name = dest_table.split('.').last
132
+ seq_name = "#{tbl_without_schema_name}_#{id}_seq"
133
+ # check if sequence exists
134
+ if dest_table_class.connection
135
+ .select_value("SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = '#{seq_name}' AND sequence_schema = '#{schema}'").present?
136
+ query += "ALTER SEQUENCE #{schema}.#{seq_name} RESTART;\n"
137
+ query += "UPDATE #{dest_table} SET #{id} = DEFAULT;\n"
138
+ end
139
+ query += "INSERT INTO #{dest_table} SELECT * FROM #{src_table};"
140
+
141
+ unless opts[:do_not_truncate_src]
142
+ # truncate src_table and get it primed for next time
143
+ query += "TRUNCATE TABLE #{src_table};\n"
144
+ id = src_table_class.primary_key
145
+ schema = 'public'
146
+ schema = src_table.split('.').first if src_table.include?('.')
147
+ tbl_without_schema_name = src_table.split('.').last
148
+ seq_name = "#{tbl_without_schema_name}_#{id}_seq"
149
+ # check if sequence exists
150
+ if dest_table_class.connection
151
+ .select_value("SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = '#{seq_name}' AND sequence_schema = '#{schema}'").present?
152
+ query += "ALTER SEQUENCE #{schema}.#{seq_name} RESTART;\n"
153
+ query += "UPDATE #{src_table} SET #{id} = DEFAULT;\n"
154
+ end
155
+ end
156
+ query
157
+ end
158
+
159
+ # rubocop:enable Metrics/MethodLength
160
+
161
+ def vacuum_analyze(tbl, opts = {})
162
+ query = ''
163
+ if tbl.respond_to?(:table_name)
164
+ # Take care of the case where table is an ActiveRecord::Base class
165
+ tbl = tbl.table_name
166
+ end
167
+ query += "VACUUM ANALYSE #{tbl};"
168
+ rails_connection(opts[:cls]).execute(query)
169
+ end
170
+
171
+ def multi_dump_to_csv(tables, opts = {})
172
+ conn = rails_connection(opts[:cls])
173
+ pg_conn = conn.raw_connection
174
+ tables.each do |table|
175
+ tbl = table[:tbl]
176
+ csv_path = table[:csv_path]
177
+ # Take care of the case where table is an ActiveRecord::Base class
178
+ tbl = tbl.table_name if tbl.respond_to?(:table_name)
179
+ if opts[:column_names].present? && opts[:column_names].is_a?(Array)
180
+ cols = opts[:column_names].join(',')
181
+ qcopy = "COPY #{tbl}(#{cols}) TO STDOUT WITH DELIMITER ',' CSV HEADER"
182
+ else
183
+ qcopy = "COPY #{tbl} TO STDOUT WITH DELIMITER ',' CSV HEADER"
184
+ end
185
+
186
+ csv = []
187
+ # rubocop:disable Lint/AssignmentInCondition
188
+ pg_conn.copy_data(qcopy.to_s) do
189
+ while row = pg_conn.get_copy_data
190
+ csv.push(row)
191
+ end
192
+ end
193
+ # rubocop:enable Lint/AssignmentInCondition
194
+ File.open(csv_path, 'w') do |f|
195
+ csv.each_slice(100_000).each do |chunk|
196
+ f.write(chunk.join('').force_encoding('UTF-8'))
197
+ end
198
+ end
199
+ end
200
+ end
201
+
202
+ def multi_dump_query_result_to_csv(query, csv_path, opts = {})
203
+ conn = rails_connection(opts[:cls])
204
+ pg_conn = conn.raw_connection
205
+ qcopy = "COPY (#{query}) TO STDOUT WITH DELIMITER ',' CSV HEADER"
206
+
207
+ csv = []
208
+ # rubocop:disable Lint/AssignmentInCondition
209
+ pg_conn.copy_data(qcopy.to_s) do
210
+ while row = pg_conn.get_copy_data
211
+ csv.push(row)
212
+ end
213
+ end
214
+ # rubocop:enable Lint/AssignmentInCondition
215
+
216
+ File.open(csv_path, 'w') do |f|
217
+ f.write(csv.join('').force_encoding('UTF-8'))
218
+ end
219
+ end
220
+
221
+ # rubocop:disable Metrics/MethodLength
222
+
223
+ def multi_truncate_reset_populate_from_csv(tables, opts = {})
224
+ # Cant execute PGConnection#copy_data within an
225
+ # Activerecord transaction block
226
+ # so this whole method is not in a single transaction block unfortunately
227
+
228
+ conn = rails_connection(opts[:cls])
229
+ pg_conn = conn.raw_connection
230
+
231
+ # First we loop thru all tables and create a copy of each
232
+ # Load the csv into these copy tables and these will be used
233
+ # to populate the original tables in a transaction
234
+ tables.each do |table|
235
+ tblcls = table[:tblcls]
236
+ csv_path = table[:csv_path]
237
+ # Take care of the case where table is not an ActiveRecord::Base class
238
+ raise StandardError, "#{tblcls} must be an ActiveRecord::Base Class" unless tblcls.respond_to?(:table_name)
239
+
240
+ tbl = tblcls.table_name
241
+ tbl_copy = generate_temptable_name(tbl)
242
+ # create a regular table and not temp table here
243
+ # since we dont want the table to be auto dropped at the end of this
244
+ # loop (transaction), temp tables are auto dropped at the commit of
245
+ # transaction, we will manually need to drop this table
246
+ pg_conn.exec("CREATE TABLE #{tbl_copy} (LIKE #{tbl} INCLUDING DEFAULTS)")
247
+ # pg_conn.exec("DROP TABLE IF EXISTS #{tbl_copy}")
248
+ if opts[:column_names].present? && opts[:column_names].is_a?(Array)
249
+ cols = opts[:column_names].join(',')
250
+ qcopy = "COPY #{tbl_copy}(#{cols}) FROM STDIN WITH DELIMITER ',' CSV HEADER"
251
+ else
252
+ qcopy = "COPY #{tbl_copy} FROM STDIN WITH DELIMITER ',' CSV HEADER"
253
+ end
254
+ pg_conn.copy_data(qcopy.to_s) do
255
+ File.open(csv_path, 'r').each do |line|
256
+ pg_conn.put_copy_data(line)
257
+ end
258
+ end
259
+ table[:tbl_copy] = tbl_copy
260
+ end
261
+
262
+ # transaction block to truncate table and reset sequence if needed
263
+ # Populate using the copy table just created
264
+ # drop the copy table
265
+ query = "BEGIN;\n"
266
+ tables.each do |table|
267
+ tblcls = table[:tblcls]
268
+ tbl_copy = table[:tbl_copy]
269
+ raise StandardError, "#{tbl_copy} Table missing!" unless conn.tables.include?(tbl_copy)
270
+
271
+ tbl = tblcls.table_name
272
+ unless opts[:do_not_truncate]
273
+ id = tblcls.primary_key
274
+ schema = 'public'
275
+ schema = tbl.split('.').first if tbl.include?('.')
276
+ tbl_without_schema_name = tbl.split('.').last
277
+ seq_name = "#{tbl_without_schema_name}_#{id}_seq"
278
+ query += "TRUNCATE TABLE #{tbl};\n"
279
+ # check if sequence exists
280
+ if tblcls.connection
281
+ .select_value("SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = '#{seq_name}' AND sequence_schema = '#{schema}'").present?
282
+ query += "ALTER SEQUENCE #{schema}.#{seq_name} RESTART;\n"
283
+ query += "UPDATE #{tbl} SET #{id} = DEFAULT;\n"
284
+ end
285
+ end
286
+ query += "INSERT INTO #{tbl} SELECT * FROM #{tbl_copy};"
287
+ query += "DROP TABLE #{tbl_copy};"
288
+ end
289
+ query += 'COMMIT;'
290
+ pg_conn.exec(query)
291
+
292
+ # ensuring the sequence is reset to be > max id (postgres has a bug where sequence can sometimes can become out of sync specially when doing bulk imports)
293
+ # refer to: https://stackoverflow.com/questions/11068800/rails-auto-assigning-id-that-already-exists
294
+ tables.each do |table|
295
+ tblcls = table[:tblcls]
296
+ tblcls.connection.reset_pk_sequence!(tblcls.table_name)
297
+ end
298
+
299
+ tables.each { |t| vacuum_analyze(t[:tblcls], opts) } if opts[:vacuum]
300
+ end
301
+
302
+ # rubocop:enable Metrics/MethodLength
303
+
304
+ def fix_sequence_value(table, key = nil, conn = nil)
305
+ if table.respond_to?(:table_name) # Take care of the case where table is an ActiveRecord::Base class
306
+ conn ||= table.connection
307
+ key ||= table.primary_key
308
+ table = table.table_name
309
+ else
310
+ conn ||= rails_connection
311
+ key ||= 'id'
312
+ end
313
+ seqname = "#{table}_#{key}_seq"
314
+ unless conn.select_value("SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = '#{seqname}'")
315
+ return
316
+ end
317
+
318
+ maxid = conn.select_value("SELECT MAX(#{key}) from \"#{table}\"").to_i
319
+ conn.execute("SELECT setval('#{seqname}', #{maxid});") if maxid >= 1
320
+ rescue StandardError
321
+ Rails.logger.debug("WARNING: #{$ERROR_INFO}\n")
322
+ end
323
+
324
+ def fix_sequence_value_with_cap(table, cutoff_id = nil, key = nil, conn = nil)
325
+ if table.respond_to?(:table_name) # Take care of the case where table is an ActiveRecord::Base class
326
+ conn ||= table.connection
327
+ key ||= table.primary_key
328
+ table = table.table_name
329
+ else
330
+ conn ||= rails_connection
331
+ key ||= 'id'
332
+ end
333
+ seqname = "#{table}_#{key}_seq"
334
+ unless conn.select_value("SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = '#{seqname}'")
335
+ return
336
+ end
337
+
338
+ sql = "SELECT MAX(#{key}) from \"#{table}\""
339
+ sql << " WHERE #{key} < #{cutoff_id}" if cutoff_id
340
+ maxid = conn.select_value(sql).to_i
341
+ conn.execute("SELECT setval('#{seqname}', #{maxid});") if maxid >= 1
342
+ rescue StandardError
343
+ Rails.logger.debug("WARNING: #{$ERROR_INFO}\n")
344
+ end
345
+
346
+ def setup_primary_key(table, key)
347
+ rails_connection.execute "ALTER TABLE \"#{table}\" ADD PRIMARY KEY (\"#{key}\");"
348
+ end
349
+
350
+ def delete_primary_key(table)
351
+ rails_connection.execute "ALTER TABLE \"#{table}\" DROP CONSTRAINT \"#{table}_pkey\";"
352
+ end
353
+
354
+ def pg_dump_custom(filename, dbname = nil)
355
+ dbname ||= db_name
356
+ system_with_print(
357
+ "pg_dump #{host_param} -U #{username} -w --file=#{filename} -T data_parts -T data_part_applications --format=custom #{dbname}", "Dump #{dbname} to #{filename}"
358
+ )
359
+ end
360
+
361
+ def pg_save_data(filename, table_name, dbname = nil)
362
+ dbname ||= db_name
363
+ system_with_print(
364
+ "pg_dump #{host_param} -U #{username} -w -t #{table_name} --data-only --dbname=#{dbname} -f #{filename}", "Save #{dbname} to #{filename}"
365
+ )
366
+ end
367
+
368
+ def pg_restore_data_and_schema(filename, dbname = nil)
369
+ dbname ||= db_name
370
+ system_with_print("pg_restore #{host_param} -U #{username} -w -d #{dbname} -j 4 #{filename}",
371
+ "Restore #{dbname} from #{filename}")
372
+ end
373
+
374
+ def pg_load(filename, dbname = nil)
375
+ dbname ||= db_name
376
+ bz2 = false
377
+ if filename.to_s.ends_with?('.sql.bz2')
378
+ filename = filename.to_s[0..-9]
379
+ bz2 = true
380
+ end
381
+ if bz2
382
+ system_with_print(
383
+ "bzip2 -cd #{filename}.sql.bz2 | PGPASSWORD=\'#{password}\' psql #{host_param} -q -U #{username} -w #{dbname}", "Loading #{dbname} from #{filename}"
384
+ )
385
+ else
386
+ system_with_print("PGPASSWORD=\'#{password}\' psql #{host_param} -q -U #{username} -w #{dbname} < #{filename}",
387
+ "Loading #{dbname} from #{filename}")
388
+ end
389
+ end
390
+
391
+ # Much faster when it works, but does not work for foreign key enable tables
392
+ def truncate_table(conn, tbl)
393
+ stmt = "TRUNCATE TABLE #{tbl}"
394
+ conn.execute(stmt)
395
+ end
396
+
397
+ def clear_table(conn, tbl_name, cond = nil)
398
+ stmts = if cond
399
+ ["DELETE FROM #{tbl_name} WHERE #{cond}"]
400
+ else
401
+ ["DELETE FROM #{tbl_name}"]
402
+ end
403
+ stmts.each { |stmt| conn.execute(stmt) }
404
+ end
405
+
406
+ def clear_table_reset_sequence(tblcls)
407
+ return unless tblcls.respond_to?(:table_name)
408
+
409
+ tbl = tblcls.table_name
410
+ stmts = ["TRUNCATE TABLE #{tbl}"]
411
+ id = tblcls.primary_key
412
+ schema = 'public'
413
+ schema = tbl.split('.').first if tbl.include?('.')
414
+ tbl_without_schema_name = tbl.split('.').last
415
+ seq_name = "#{tbl_without_schema_name}_#{id}_seq"
416
+ # check if sequence exists
417
+ if tblcls.connection
418
+ .select_value("SELECT sequence_name FROM information_schema.sequences
419
+ WHERE sequence_name = '#{seq_name}' AND sequence_schema = '#{schema}'").present?
420
+ stmts += [
421
+ "ALTER SEQUENCE #{schema}.#{seq_name} RESTART",
422
+ "UPDATE #{tbl} SET #{id} = DEFAULT"
423
+ ]
424
+ end
425
+ tblcls.transaction do
426
+ stmts.each { |stmt| tblcls.connection.execute(stmt) }
427
+ end
428
+ nil
429
+ end
430
+
431
+ def get_random_record(klass, opt = nil)
432
+ opt ||= {}
433
+ c = klass.connection
434
+ select_clause = opt[:dense] ? "MAX(\"#{klass.primary_key}\")" : 'COUNT(*)'
435
+ cnt = c.select_value("SELECT #{select_clause} FROM \"#{klass.table_name}\"").to_i
436
+ klass.offset(rand(cnt)).first
437
+ end
438
+
439
+ def system_with_print(cmd, toprint = nil)
440
+ toprint ||= cmd
441
+ puts "EXEC:#{toprint} ... "
442
+ start = Time.now
443
+ ret = system(cmd)
444
+ puts (ret ? 'success' : 'failed') + " (#{Time.now - start} seconds)\n"
445
+ ret
446
+ end
447
+
448
+ # Accepts an array of hashes to insert in bulk into the table
449
+ def batch_insert(model:, values:, batch_size: DEFAULT_BATCH_SIZE, include_pkey: false)
450
+ # Nothing to do if there are no values
451
+ return if values.blank?
452
+
453
+ columns = model.column_names.map(&:to_sym)
454
+ columns.delete(model.primary_key.to_sym) unless include_pkey
455
+ columns_string = columns.map(&:to_s).join(', ').to_s
456
+ table = model.table_name
457
+
458
+ value_batches = Array(values.in_groups_of(batch_size).map do |batch|
459
+ batch.compact.map { |item| "(#{columns.map { |col| process_value(item[col]) }.join(', ')})" }.join(', ')
460
+ end)
461
+
462
+ model.transaction do
463
+ value_batches.each do |vb|
464
+ rails_connection.execute("INSERT INTO #{table}(#{columns_string}) VALUES #{vb}")
465
+ end
466
+ end
467
+ end
468
+
469
+ private
470
+
471
+ def host_param
472
+ host = db_connection_config[:host]
473
+ return "-h #{host}" if host.present? && host != 'localhost' && host != '127.0.0.1'
474
+
475
+ ''
476
+ end
477
+
478
+ def username
479
+ db_connection_config[:username]
480
+ end
481
+
482
+ def password
483
+ db_connection_config[:password]
484
+ end
485
+
486
+ def generate_temptable_name(tbl_name)
487
+ raise StandardError, 'Cant create temp table for missing original table' if tbl_name.blank?
488
+
489
+ "temp_#{tbl_name.split('.').last}_#{(Time.now.to_f * 1000).round}_#{format('%03d', rand(1000))}"
490
+ end
491
+
492
+ # Convert values to database friendly format
493
+ def process_value(value)
494
+ if value.is_a?(Time)
495
+ "TIMESTAMP '#{value.strftime('%Y-%m-%d %H:%M:%S')}'"
496
+ else
497
+ ActiveRecord::Base.sanitize_sql(value)
498
+ end
499
+ end
500
+ end
501
+
502
+ # rubocop:enable Layout/LineLength, Metrics/ModuleLength
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/postgres_utility/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'postgres_utility'
7
+ spec.version = PostgresUtility::VERSION
8
+ spec.authors = ['sachinsaxena1996']
9
+ spec.email = ['dev@yourmechanic.com']
10
+
11
+ spec.summary = 'Postgres_utility gem to perform a variety of methods on Rails app having postgres db'
12
+ spec.description = 'Postgres_utility gem to perform a variety of methods on Rails app having postgres db'
13
+ spec.homepage = 'https://github.com/YourMechanic/postgres_utility'
14
+ spec.license = 'MIT'
15
+ # spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
16
+
17
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
18
+
19
+ spec.metadata['homepage_uri'] = spec.homepage
20
+ spec.metadata['source_code_uri'] = 'https://github.com/YourMechanic/postgres_utility'
21
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
27
+ end
28
+ spec.bindir = 'exe'
29
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ['lib']
31
+
32
+ # Uncomment to register a new dependency of your gem
33
+ # spec.add_dependency "example-gem", "~> 1.0"
34
+
35
+ # For more information and examples about making a new gem, checkout our
36
+ # guide at: https://bundler.io/guides/creating_gem.html
37
+
38
+ spec.add_development_dependency 'activerecord', '5.2.6'
39
+ spec.add_development_dependency 'byebug'
40
+ spec.add_development_dependency 'pg', '1.2.3'
41
+ spec.add_development_dependency 'rake', '~> 13.0'
42
+ spec.add_development_dependency 'rspec', '~> 3.0'
43
+ spec.add_development_dependency 'rubocop', '~> 1.7'
44
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: postgres_utility
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - sachinsaxena1996
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-10-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.6
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 5.2.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: byebug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pg
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.2.3
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.2.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '13.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '13.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.7'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.7'
97
+ description: Postgres_utility gem to perform a variety of methods on Rails app having
98
+ postgres db
99
+ email:
100
+ - dev@yourmechanic.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".circleci/config.yml"
106
+ - ".gitignore"
107
+ - ".rspec"
108
+ - ".rubocop.yml"
109
+ - CODE_OF_CONDUCT.md
110
+ - Gemfile
111
+ - Gemfile.lock
112
+ - LICENSE
113
+ - LICENSE.txt
114
+ - README.md
115
+ - Rakefile
116
+ - bin/console
117
+ - bin/setup
118
+ - lib/postgres_utility.rb
119
+ - lib/postgres_utility/version.rb
120
+ - postgres_utility.gemspec
121
+ homepage: https://github.com/YourMechanic/postgres_utility
122
+ licenses:
123
+ - MIT
124
+ metadata:
125
+ allowed_push_host: https://rubygems.org
126
+ homepage_uri: https://github.com/YourMechanic/postgres_utility
127
+ source_code_uri: https://github.com/YourMechanic/postgres_utility
128
+ post_install_message:
129
+ rdoc_options: []
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ requirements: []
143
+ rubygems_version: 3.0.3
144
+ signing_key:
145
+ specification_version: 4
146
+ summary: Postgres_utility gem to perform a variety of methods on Rails app having
147
+ postgres db
148
+ test_files: []