neon_postgres 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19cb8f89bec9249fa25eb7d90c9050d8a31b10682742782b2aac1e609bd35eb4
4
- data.tar.gz: e65ea4e35f4f24ef679a3097bf587cd0975ebc64b055a6c4be69d34c7109c80b
3
+ metadata.gz: 6d2ad55de5e5434affb51e984491c49d8f55dbe05c3088589e0771e5e7ebfef9
4
+ data.tar.gz: 99390ca36ff8bb5246e4257d5c367853d8432a2da233dca90746b5b9cbf2a8ba
5
5
  SHA512:
6
- metadata.gz: 683a99ffe0a33f88e3eddc0bc3b89545d6370a3e30effb00ae114488523396356700332e01982c016f34d4d498fb05e9b0060a0c4b5e38f9e0052b00e0905e1d
7
- data.tar.gz: 904809eb087e1aee239eb4871d98f633646193b3f09c2a8db48f8704b67cc0a32397950af5f34414c63e143dc0af4e37a824294fd3d6795964a81fb376c3ea93
6
+ metadata.gz: c1a02ce11eb4834caefa3b4d98e96fddc3f0781f4f2790c178080b1e9b6d68bb00c925afbbbf5c0913dbe9231e457290f2db1b5dc59af8bfcc57552930c4e6a1
7
+ data.tar.gz: 3fab5c98423cdb3026cc7e5edc13d53d540f94d72213fad81042b4602a6431564fa022590f4eb938b41d648266a526f5be26e34157e32b889c6e1bd2409ec74b
data/Dockerfile ADDED
@@ -0,0 +1,25 @@
1
+ FROM docker.pkg.github.com/neonlaw/codebase/base:latest
2
+
3
+ ENV DATABASE_URL $DATABASE_URL
4
+ ENV FROM_DATABASE_URL $FROM_DATABASE_URL
5
+ ENV TO_DATABASE_URL $TO_DATABASE_URL
6
+
7
+ # Install dependencies from apt-get
8
+ RUN apt-get update -qqy &&\
9
+ apt-get -qqyy install ruby-full
10
+ RUN gem install bundler
11
+
12
+ ## TODO use Doppler
13
+ # RUN (curl -Ls https://cli.doppler.com/install.sh || wget -qO- https://cli.doppler.com/install.sh) | sh
14
+ # ENTRYPOINT [ "doppler", "run", "--" ]
15
+
16
+ WORKDIR /app/postgres
17
+
18
+ COPY ./postgres/Gemfile .
19
+ COPY ./postgres/Gemfile.lock .
20
+ RUN bundle install
21
+
22
+ COPY ./postgres ./
23
+
24
+ ENTRYPOINT [ "bundle", "exec" ]
25
+ CMD ["ruby", "lib/neon_postgres/inter_database_copy/copy.rb"]
data/Gemfile CHANGED
@@ -12,3 +12,5 @@ gem "fixture_dependencies", "~> 1.10"
12
12
  gem "pg", "~> 1.2"
13
13
 
14
14
  gem "pry", "~> 0.14.1"
15
+
16
+ gem "faker", "~> 2.17"
data/Gemfile.lock CHANGED
@@ -1,15 +1,20 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- neon_postgres (0.1.0)
4
+ neon_postgres (0.0.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  ast (2.4.2)
10
10
  coderay (1.1.3)
11
+ concurrent-ruby (1.1.8)
11
12
  diff-lcs (1.4.4)
13
+ faker (2.17.0)
14
+ i18n (>= 1.6, < 2)
12
15
  fixture_dependencies (1.10.0)
16
+ i18n (1.8.10)
17
+ concurrent-ruby (~> 1.0)
13
18
  method_source (1.0.0)
14
19
  parallel (1.20.1)
15
20
  parser (3.0.1.0)
@@ -60,6 +65,7 @@ PLATFORMS
60
65
  ruby
61
66
 
62
67
  DEPENDENCIES
68
+ faker (~> 2.17)
63
69
  fixture_dependencies (~> 1.10)
64
70
  neon_postgres!
65
71
  pg (~> 1.2)
data/README.md CHANGED
@@ -4,6 +4,29 @@ This gem is mainly used to test the Neon Law database which is created and
4
4
  maintained by Graphile. It is also consumed by other background-job ruby gems
5
5
  that handle non-web-request related processing.
6
6
 
7
+ ## Inter Database Copy
8
+
9
+ To copy data between two databases run the following script from the root of
10
+ this codebase (`../`) from this directory.
11
+
12
+ ```bash
13
+ doppler setup # project inter_db_copy, environment production
14
+
15
+ # Copy the GCP credentials to your machine from the above directory
16
+ yarn copy-gcp-credentials
17
+
18
+ # These following commands start db processes so you may need to run them in
19
+ # separate shells.
20
+ yarn sql-proxy-production
21
+ yarn sql-proxy-staging
22
+
23
+ # Then in this directory run
24
+ doppler run -- bundle exec ruby lib/neon_postgres/inter_database_copy/copy.rb
25
+ ```
26
+
27
+ We use this ruby script to copy data from `production` to `staging` so we can
28
+ freely showcase our software without fear of disclosing client interests.
29
+
7
30
  ## Contributing
8
31
 
9
32
  Bug reports and pull requests are welcome on GitHub at
data/lib/neon_postgres.rb CHANGED
@@ -1,27 +1,14 @@
1
- require "neon_postgres/version"
2
1
  require "sequel"
3
2
 
3
+ require "neon_postgres/version"
4
+ require "neon_postgres/database"
5
+ require "neon_postgres/document_sanitizer"
6
+ require "neon_postgres/sequel_models"
7
+ Dir["#{__dir__}/neon_postgres/inter_database_copy/*"].sort.each { |file|
8
+ next if /copy.rb$/.match?(file)
9
+ require file
10
+ }
11
+
4
12
  module NeonPostgres
5
13
  class Error < StandardError; end
6
-
7
- class Database
8
- def self.connection
9
- @_connection ||= Sequel.connect(
10
- ENV.fetch("DATABASE_URL") {
11
- "postgres://postgres:password@localhost:5432/neon_law"
12
- }
13
- )
14
- end
15
-
16
- def self.anonymous_connection
17
- @_anonymous_connection ||= Sequel.connect(
18
- ENV.fetch("DATABASE_URL") {
19
- "postgres://postgres:password@localhost:5432/neon_law"
20
- },
21
- connect_sqls: [
22
- "SET role = 'anonymous';"
23
- ]
24
- )
25
- end
26
- end
27
14
  end
@@ -0,0 +1,76 @@
1
+ require "sequel"
2
+
3
+ module NeonPostgres
4
+ class Database
5
+ def self.connection
6
+ @_connection ||= Sequel.connect(
7
+ ENV.fetch("DATABASE_URL") {
8
+ "postgres://postgres:password@localhost:5432/neon_law"
9
+ }
10
+ )
11
+ end
12
+
13
+ def self.anonymous_connection
14
+ @_anonymous_connection ||= Sequel.connect(
15
+ ENV.fetch("DATABASE_URL") {
16
+ "postgres://postgres:password@localhost:5432/neon_law"
17
+ },
18
+ connect_sqls: [
19
+ "SET role = 'anonymous';"
20
+ ]
21
+ )
22
+ end
23
+
24
+ def self.portal_connection(user_id:)
25
+ @_portal_connection ||= Sequel.connect(
26
+ ENV.fetch("DATABASE_URL") {
27
+ "postgres://postgres:password@localhost:5432/neon_law"
28
+ },
29
+ connect_sqls: [
30
+ "SET role = 'portal';",
31
+ "SET \"person.id\" = '#{user_id}';"
32
+ ]
33
+ )
34
+ end
35
+
36
+ def self.lawyer_connection(user_id:)
37
+ @_lawyer_connection ||= Sequel.connect(
38
+ ENV.fetch("DATABASE_URL") {
39
+ "postgres://postgres:password@localhost:5432/neon_law"
40
+ },
41
+ connect_sqls: [
42
+ "SET role = 'lawyer';",
43
+ "SET \"person.id\" = '#{user_id}';"
44
+ ]
45
+ )
46
+ end
47
+
48
+ def self.admin_connection(user_id:)
49
+ @_admin_connection ||= Sequel.connect(
50
+ ENV.fetch("DATABASE_URL") {
51
+ "postgres://postgres:password@localhost:5432/neon_law"
52
+ },
53
+ connect_sqls: [
54
+ "SET role = 'admin';",
55
+ "SET \"person.id\" = '#{user_id}';"
56
+ ]
57
+ )
58
+ end
59
+
60
+ def self.from_connection
61
+ @_from_connection ||= Sequel.connect(
62
+ ENV.fetch("FROM_DATABASE_URL") {
63
+ "postgres://postgres:password@localhost:5432/production"
64
+ }
65
+ )
66
+ end
67
+
68
+ def self.to_connection
69
+ @_to_connection ||= Sequel.connect(
70
+ ENV.fetch("TO_DATABASE_URL") {
71
+ "postgres://postgres:password@localhost:5432/staging"
72
+ }
73
+ )
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,46 @@
1
+ require_relative "./database"
2
+ require "faker"
3
+
4
+ module NeonPostgres
5
+ class DocumentSanitizer
6
+ def self.sanitize(
7
+ document:, database_connection: NeonPostgres::Database.connection
8
+ )
9
+ new(
10
+ database_connection: database_connection,
11
+ document: document
12
+ ).sanitize
13
+ end
14
+
15
+ def initialize(database_connection:, document:)
16
+ @database_connection = database_connection
17
+ @document = document
18
+ end
19
+
20
+ def sanitize
21
+ values = documents_connection.find(id: document.fetch(:id)).first
22
+
23
+ filename = "#{Faker::Internet.uuid}.pdf"
24
+
25
+ values[:filename] = filename
26
+ values[:gcp_url] = "https://neon-law-staging-private-assets.storage."\
27
+ "googleapis.com/matters/#{Faker::Internet.uuid}/#{filename}"
28
+
29
+ documents_connection.insert_conflict(
30
+ target: :id,
31
+ update: {
32
+ filename: Sequel[:excluded][:filename],
33
+ gcp_url: Sequel[:excluded][:gcp_url]
34
+ }
35
+ ).insert(values)
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :database_connection, :document
41
+
42
+ def documents_connection
43
+ @_documents_connection ||= database_connection[:documents]
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,34 @@
1
+ require_relative "../document_sanitizer"
2
+ require_relative "./document_template_copier"
3
+ require_relative "./matter_copier"
4
+ require_relative "./matter_template_copier"
5
+ require_relative "./matter_documents_copier"
6
+
7
+ NeonPostgres::InterDatabaseCopy::DocumentTemplateCopier.copy
8
+ NeonPostgres::InterDatabaseCopy::MatterTemplateCopier.copy
9
+ NeonPostgres::InterDatabaseCopy::MatterCopier.copy
10
+ NeonPostgres::InterDatabaseCopy::MatterDocumentsCopier.copy
11
+
12
+ # Add the admin test user as a lawyer matter contact to all matters
13
+ admin_id = NeonPostgres::Database.to_connection[:people]
14
+ .where(email: "admin@sink.sendgrid.com").first.fetch(:id)
15
+
16
+ NeonPostgres::Database.to_connection[:matters].all.each do |matter|
17
+ puts "Copying matter #{matter.fetch(:id)}"
18
+
19
+ NeonPostgres::Database.to_connection[:matter_contacts].insert_conflict.insert(
20
+ matter_id: matter.fetch(:id),
21
+ contact_id: admin_id,
22
+ role: "lawyer"
23
+ )
24
+ end
25
+
26
+ # Sanitize the documents in the to connection
27
+ NeonPostgres::Database.to_connection[:documents].all.each do |document|
28
+ puts "sanitizing #{document.fetch(:id)}"
29
+
30
+ NeonPostgres::DocumentSanitizer.sanitize(
31
+ document: document,
32
+ database_connection: NeonPostgres::Database.to_connection
33
+ )
34
+ end
@@ -0,0 +1,49 @@
1
+ require_relative "../database"
2
+
3
+ module NeonPostgres
4
+ module InterDatabaseCopy
5
+ class DocumentTemplateCopier
6
+ def self.copy(
7
+ from_connection: NeonPostgres::Database.from_connection,
8
+ to_connection: NeonPostgres::Database.to_connection
9
+ )
10
+ new(
11
+ from_connection: from_connection,
12
+ to_connection: to_connection
13
+ ).copy
14
+ end
15
+
16
+ def initialize(from_connection:, to_connection:)
17
+ @from_connection = from_connection
18
+ @to_connection = to_connection
19
+ end
20
+
21
+ def copy
22
+ from_dataset.each do |row|
23
+ to_dataset
24
+ .insert_conflict(
25
+ target: :id,
26
+ update: {
27
+ name: Sequel[:excluded][:name],
28
+ description: Sequel[:excluded][:description],
29
+ abbreviation: Sequel[:excluded][:abbreviation],
30
+ jurisdiction: Sequel[:excluded][:jurisdiction]
31
+ }
32
+ ).insert(row)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :from_connection, :to_connection
39
+
40
+ def from_dataset
41
+ @_from_dataset ||= from_connection[:document_templates]
42
+ end
43
+
44
+ def to_dataset
45
+ @_to_dataset ||= to_connection[:document_templates]
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,85 @@
1
+ require_relative "../database"
2
+ require "faker"
3
+
4
+ module NeonPostgres
5
+ module InterDatabaseCopy
6
+ class MatterCopier
7
+ def self.copy(
8
+ from_connection: NeonPostgres::Database.from_connection,
9
+ to_connection: NeonPostgres::Database.to_connection
10
+ )
11
+ new(
12
+ from_connection: from_connection,
13
+ to_connection: to_connection
14
+ ).copy
15
+ end
16
+
17
+ def initialize(from_connection:, to_connection:)
18
+ @from_connection = from_connection
19
+ @to_connection = to_connection
20
+ end
21
+
22
+ def copy
23
+ from_dataset.each do |row|
24
+ to_connection[:matter_templates].insert_conflict(
25
+ target: :id,
26
+ update: {
27
+ category: Sequel[:excluded][:category],
28
+ name: Sequel[:excluded][:name],
29
+ description: Sequel[:excluded][:description]
30
+ }
31
+ ).insert({
32
+ id: row.fetch(:matter_template_id),
33
+ name: row.fetch(:matter_templates_name),
34
+ category: row.fetch(:category),
35
+ description: row.fetch(:matter_templates_description)
36
+ })
37
+
38
+ to_connection[:people].insert_conflict(
39
+ target: :id,
40
+ update: {
41
+ name: Sequel[:excluded][:name],
42
+ email: Sequel[:excluded][:email],
43
+ sub: Sequel[:excluded][:sub]
44
+ }
45
+ ).insert({
46
+ id: row.fetch(:people_id),
47
+ name: Faker::Name.name,
48
+ email: Faker::Internet.email,
49
+ sub: Faker::Internet.uuid
50
+ })
51
+
52
+ to_connection[:matters].insert_conflict(
53
+ target: :name,
54
+ update: {
55
+ matter_template_id: Sequel[:excluded][:matter_template_id],
56
+ primary_contact_id: Sequel[:excluded][:primary_contact_id],
57
+ description: Sequel[:excluded][:description]
58
+ }
59
+ ).insert({
60
+ name: "#{row.fetch(:matter_templates_name)} Matter",
61
+ matter_template_id: row.fetch(:matter_template_id),
62
+ description: JSON.generate({
63
+ body: Faker::Lorem.paragraphs(number: 3)
64
+ }),
65
+ primary_contact_id: row.fetch(:primary_contact_id)
66
+ })
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ attr_reader :from_connection, :to_connection
73
+
74
+ def from_dataset
75
+ @_from_dataset ||= from_connection[:matters].graph(
76
+ :people,
77
+ id: :primary_contact_id
78
+ ).graph(
79
+ :matter_templates,
80
+ id: Sequel[:matters][:matter_template_id]
81
+ )
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,82 @@
1
+ require_relative "../database"
2
+ require "faker"
3
+
4
+ module NeonPostgres
5
+ module InterDatabaseCopy
6
+ class MatterDocumentsCopier
7
+ def self.copy(
8
+ from_connection: NeonPostgres::Database.from_connection,
9
+ to_connection: NeonPostgres::Database.to_connection
10
+ )
11
+ new(
12
+ from_connection: from_connection,
13
+ to_connection: to_connection
14
+ ).copy
15
+ end
16
+
17
+ def initialize(from_connection:, to_connection:)
18
+ @from_connection = from_connection
19
+ @to_connection = to_connection
20
+ end
21
+
22
+ def copy
23
+ from_dataset.each do |row|
24
+ to_connection[:documents].insert_conflict(
25
+ target: :id,
26
+ update: {
27
+ filename: Sequel[:excluded][:filename],
28
+ gcp_url: Sequel[:excluded][:gcp_url],
29
+ document_template_id: Sequel[:excluded][:document_template_id],
30
+ documentable_table_name: Sequel[:excluded][
31
+ :documentable_table_name
32
+ ],
33
+ created_at: Sequel[:excluded][:created_at]
34
+ }
35
+ ).insert({
36
+ id: row.fetch(:document_id),
37
+ filename: row.fetch(:filename),
38
+ gcp_url: row.fetch(:gcp_url),
39
+ documentable_table_name: row.fetch(:documentable_table_name),
40
+ document_template_id: row.fetch(:document_template_id),
41
+ created_at: row.fetch(:created_at)
42
+ })
43
+
44
+ matter_id = to_connection[:matters].select(:id).all.sample.fetch(:id)
45
+ author_id = to_connection[:people].select(:id).all.sample.fetch(:id)
46
+
47
+ to_connection[:matter_documents].insert_conflict({
48
+ target: :document_id,
49
+ update: {
50
+ matter_id: Sequel[:excluded][:matter_id],
51
+ author_id: Sequel[:excluded][:author_id]
52
+ }
53
+ }).insert({
54
+ document_id: row.fetch(:document_id),
55
+ matter_id: matter_id,
56
+ author_id: author_id
57
+ })
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ attr_reader :from_connection, :to_connection
64
+
65
+ def from_dataset
66
+ @_from_dataset ||= from_connection[:matter_documents].graph(
67
+ :documents,
68
+ id: Sequel[:matter_documents][:document_id]
69
+ ).graph(
70
+ :matters,
71
+ id: Sequel[:matter_documents][:matter_id]
72
+ ).graph(
73
+ :people,
74
+ id: Sequel[:matter_documents][:author_id]
75
+ ).graph(
76
+ :document_templates,
77
+ id: Sequel[:documents][:document_template_id]
78
+ )
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,47 @@
1
+ require_relative "../database"
2
+
3
+ module NeonPostgres
4
+ module InterDatabaseCopy
5
+ class MatterTemplateCopier
6
+ def self.copy(
7
+ from_connection: NeonPostgres::Database.from_connection,
8
+ to_connection: NeonPostgres::Database.to_connection
9
+ )
10
+ new(
11
+ from_connection: from_connection,
12
+ to_connection: to_connection
13
+ ).copy
14
+ end
15
+
16
+ def initialize(from_connection:, to_connection:)
17
+ @from_connection = from_connection
18
+ @to_connection = to_connection
19
+ end
20
+
21
+ def copy
22
+ from_dataset.each do |row|
23
+ to_dataset
24
+ .insert_conflict(
25
+ target: :name,
26
+ update: {
27
+ category: Sequel[:excluded][:category],
28
+ description: Sequel[:excluded][:description]
29
+ }
30
+ ).insert(row)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :from_connection, :to_connection
37
+
38
+ def from_dataset
39
+ @_from_dataset ||= from_connection[:matter_templates]
40
+ end
41
+
42
+ def to_dataset
43
+ @_to_dataset ||= to_connection[:matter_templates]
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,36 @@
1
+ require_relative "./database"
2
+ Sequel::Model.db = NeonPostgres::Database.connection
3
+
4
+ module NeonPostgres
5
+ module Models
6
+ class Person < Sequel::Model
7
+ one_to_many :matters, key: :primary_contact_id
8
+ one_to_many :matter_documents, key: :author_id
9
+ end
10
+
11
+ class DocumentTemplate < Sequel::Model
12
+ one_to_many :documents
13
+ end
14
+
15
+ class MatterTemplate < Sequel::Model
16
+ one_to_many :matters
17
+ end
18
+
19
+ class Matter < Sequel::Model
20
+ many_to_one :matter_template
21
+ many_to_one :matter_documents
22
+ many_to_one :primary_contact, class: :person, key: :primary_contact_id
23
+ end
24
+
25
+ class Document < Sequel::Model
26
+ many_to_one :document_template
27
+ one_to_many :matter_document
28
+ end
29
+
30
+ class MatterDocument < Sequel::Model
31
+ many_to_one :document
32
+ many_to_one :matter
33
+ many_to_one :author, class: :person, key: :author_id
34
+ end
35
+ end
36
+ end
@@ -1,3 +1,3 @@
1
1
  module NeonPostgres
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neon_postgres
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Neon Law
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-27 00:00:00.000000000 Z
11
+ date: 2021-05-25 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |-
14
14
  This gem contains tests and sequel setup to speak to
@@ -21,11 +21,20 @@ extra_rdoc_files: []
21
21
  files:
22
22
  - ".gitignore"
23
23
  - ".rspec"
24
+ - Dockerfile
24
25
  - Gemfile
25
26
  - Gemfile.lock
26
27
  - README.md
27
28
  - Rakefile
28
29
  - lib/neon_postgres.rb
30
+ - lib/neon_postgres/database.rb
31
+ - lib/neon_postgres/document_sanitizer.rb
32
+ - lib/neon_postgres/inter_database_copy/copy.rb
33
+ - lib/neon_postgres/inter_database_copy/document_template_copier.rb
34
+ - lib/neon_postgres/inter_database_copy/matter_copier.rb
35
+ - lib/neon_postgres/inter_database_copy/matter_documents_copier.rb
36
+ - lib/neon_postgres/inter_database_copy/matter_template_copier.rb
37
+ - lib/neon_postgres/sequel_models.rb
29
38
  - lib/neon_postgres/version.rb
30
39
  - neon_postgres.gemspec
31
40
  homepage: https://github.com/neonlaw/codebase