hanami-model 1.2.0 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +10 -7
  5. data/hanami-model.gemspec +25 -20
  6. data/lib/hanami-model.rb +3 -1
  7. data/lib/hanami/entity.rb +6 -3
  8. data/lib/hanami/entity/schema.rb +10 -7
  9. data/lib/hanami/model.rb +15 -12
  10. data/lib/hanami/model/association.rb +7 -7
  11. data/lib/hanami/model/associations/belongs_to.rb +3 -1
  12. data/lib/hanami/model/associations/dsl.rb +2 -2
  13. data/lib/hanami/model/associations/has_many.rb +10 -8
  14. data/lib/hanami/model/associations/has_one.rb +9 -7
  15. data/lib/hanami/model/associations/many_to_many.rb +9 -11
  16. data/lib/hanami/model/configuration.rb +29 -10
  17. data/lib/hanami/model/configurator.rb +5 -3
  18. data/lib/hanami/model/entity_name.rb +4 -2
  19. data/lib/hanami/model/error.rb +18 -7
  20. data/lib/hanami/model/mapped_relation.rb +4 -2
  21. data/lib/hanami/model/mapping.rb +3 -1
  22. data/lib/hanami/model/migration.rb +2 -0
  23. data/lib/hanami/model/migrator.rb +7 -5
  24. data/lib/hanami/model/migrator/adapter.rb +14 -12
  25. data/lib/hanami/model/migrator/connection.rb +16 -9
  26. data/lib/hanami/model/migrator/logger.rb +3 -1
  27. data/lib/hanami/model/migrator/mysql_adapter.rb +23 -13
  28. data/lib/hanami/model/migrator/postgres_adapter.rb +31 -31
  29. data/lib/hanami/model/migrator/sqlite_adapter.rb +7 -9
  30. data/lib/hanami/model/plugins.rb +5 -3
  31. data/lib/hanami/model/plugins/mapping.rb +2 -0
  32. data/lib/hanami/model/plugins/schema.rb +2 -0
  33. data/lib/hanami/model/plugins/timestamps.rb +3 -0
  34. data/lib/hanami/model/relation_name.rb +4 -2
  35. data/lib/hanami/model/sql.rb +9 -7
  36. data/lib/hanami/model/sql/console.rb +10 -8
  37. data/lib/hanami/model/sql/consoles/abstract.rb +3 -1
  38. data/lib/hanami/model/sql/consoles/mysql.rb +4 -2
  39. data/lib/hanami/model/sql/consoles/postgresql.rb +10 -8
  40. data/lib/hanami/model/sql/consoles/sqlite.rb +6 -4
  41. data/lib/hanami/model/sql/entity/schema.rb +6 -4
  42. data/lib/hanami/model/sql/types.rb +27 -27
  43. data/lib/hanami/model/sql/types/schema/coercions.rb +5 -4
  44. data/lib/hanami/model/types.rb +4 -4
  45. data/lib/hanami/model/version.rb +3 -1
  46. data/lib/hanami/repository.rb +20 -31
  47. metadata +64 -8
@@ -1,4 +1,6 @@
1
- require 'hanami/logger'
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/logger"
2
4
 
3
5
  module Hanami
4
6
  module Model
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hanami
2
4
  module Model
3
5
  class Migrator
@@ -8,23 +10,27 @@ module Hanami
8
10
  class MySQLAdapter < Adapter
9
11
  # @since 0.7.0
10
12
  # @api private
11
- PASSWORD = 'MYSQL_PWD'.freeze
13
+ PASSWORD = "MYSQL_PWD"
14
+
15
+ # @since 1.3.3
16
+ # @api private
17
+ DEFAULT_PORT = 3306
12
18
 
13
19
  # @since 1.0.0
14
20
  # @api private
15
- DB_CREATION_ERROR = 'Database creation failed. If the database exists, ' \
16
- 'then its console may be open. See this issue for more details: ' \
17
- 'https://github.com/hanami/model/issues/250'.freeze
21
+ DB_CREATION_ERROR = "Database creation failed. If the database exists, " \
22
+ "then its console may be open. See this issue for more details: " \
23
+ "https://github.com/hanami/model/issues/250"
18
24
 
19
25
  # @since 0.4.0
20
26
  # @api private
21
27
  def create
22
28
  new_connection(global: true).run %(CREATE DATABASE `#{database}`;)
23
- rescue Sequel::DatabaseError => e
24
- message = if e.message.match(/database exists/) # rubocop:disable Performance/RedundantMatch
29
+ rescue Sequel::DatabaseError => exception
30
+ message = if exception.message.match(/database exists/)
25
31
  DB_CREATION_ERROR
26
32
  else
27
- e.message
33
+ exception.message
28
34
  end
29
35
 
30
36
  raise MigrationError.new(message)
@@ -34,11 +40,11 @@ module Hanami
34
40
  # @api private
35
41
  def drop
36
42
  new_connection(global: true).run %(DROP DATABASE `#{database}`;)
37
- rescue Sequel::DatabaseError => e
38
- message = if e.message.match(/doesn\'t exist/) # rubocop:disable Performance/RedundantMatch
43
+ rescue Sequel::DatabaseError => exception
44
+ message = if exception.message.match(/doesn\'t exist/)
39
45
  "Cannot find database: #{database}"
40
46
  else
41
- e.message
47
+ exception.message
42
48
  end
43
49
 
44
50
  raise MigrationError.new(message)
@@ -65,22 +71,26 @@ module Hanami
65
71
  connection.password
66
72
  end
67
73
 
74
+ def port
75
+ super || DEFAULT_PORT
76
+ end
77
+
68
78
  # @since 0.4.0
69
79
  # @api private
70
80
  def dump_structure
71
- execute "mysqldump --host=#{host} --port=#{port} --user=#{username} --no-data --skip-comments --ignore-table=#{database}.#{migrations_table} #{database} > #{schema}", env: { PASSWORD => password }
81
+ execute "mysqldump --host=#{host} --port=#{port} --user=#{username} --no-data --skip-comments --ignore-table=#{database}.#{migrations_table} #{database} > #{schema}", env: {PASSWORD => password}
72
82
  end
73
83
 
74
84
  # @since 0.4.0
75
85
  # @api private
76
86
  def load_structure
77
- execute("mysql --host=#{host} --port=#{port} --user=#{username} #{database} < #{escape(schema)}", env: { PASSWORD => password }) if schema.exist?
87
+ execute("mysql --host=#{host} --port=#{port} --user=#{username} #{database} < #{escape(schema)}", env: {PASSWORD => password}) if schema.exist?
78
88
  end
79
89
 
80
90
  # @since 0.4.0
81
91
  # @api private
82
92
  def dump_migrations_data
83
- execute "mysqldump --host=#{host} --port=#{port} --user=#{username} --skip-comments #{database} #{migrations_table} >> #{schema}", env: { PASSWORD => password }
93
+ execute "mysqldump --host=#{host} --port=#{port} --user=#{username} --skip-comments #{database} #{migrations_table} >> #{schema}", env: {PASSWORD => password}
84
94
  end
85
95
  end
86
96
  end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/utils/blank"
4
+
1
5
  module Hanami
2
6
  module Model
3
7
  class Migrator
@@ -8,46 +12,41 @@ module Hanami
8
12
  class PostgresAdapter < Adapter
9
13
  # @since 0.4.0
10
14
  # @api private
11
- HOST = 'PGHOST'.freeze
15
+ HOST = "PGHOST"
12
16
 
13
17
  # @since 0.4.0
14
18
  # @api private
15
- PORT = 'PGPORT'.freeze
19
+ PORT = "PGPORT"
16
20
 
17
21
  # @since 0.4.0
18
22
  # @api private
19
- USER = 'PGUSER'.freeze
23
+ USER = "PGUSER"
20
24
 
21
25
  # @since 0.4.0
22
26
  # @api private
23
- PASSWORD = 'PGPASSWORD'.freeze
27
+ PASSWORD = "PGPASSWORD"
24
28
 
25
29
  # @since 1.0.0
26
30
  # @api private
27
- DB_CREATION_ERROR = 'createdb: database creation failed. If the database exists, ' \
28
- 'then its console may be open. See this issue for more details: ' \
29
- 'https://github.com/hanami/model/issues/250'.freeze
31
+ DB_CREATION_ERROR = "createdb: database creation failed. If the database exists, " \
32
+ "then its console may be open. See this issue for more details: " \
33
+ "https://github.com/hanami/model/issues/250"
30
34
 
31
35
  # @since 0.4.0
32
36
  # @api private
33
37
  def create
34
- set_environment_variables
35
-
36
- call_db_command('createdb')
38
+ call_db_command("createdb")
37
39
  end
38
40
 
39
41
  # @since 0.4.0
40
42
  # @api private
41
43
  def drop
42
- set_environment_variables
43
-
44
- call_db_command('dropdb')
44
+ call_db_command("dropdb")
45
45
  end
46
46
 
47
47
  # @since 0.4.0
48
48
  # @api private
49
49
  def dump
50
- set_environment_variables
51
50
  dump_structure
52
51
  dump_migrations_data
53
52
  end
@@ -55,53 +54,54 @@ module Hanami
55
54
  # @since 0.4.0
56
55
  # @api private
57
56
  def load
58
- set_environment_variables
59
57
  load_structure
60
58
  end
61
59
 
62
60
  private
63
61
 
64
- # @since 0.4.0
62
+ # @since 1.3.3
65
63
  # @api private
66
- def set_environment_variables
67
- ENV[HOST] = host unless host.nil?
68
- ENV[PORT] = port.to_s unless port.nil?
69
- ENV[PASSWORD] = password unless password.nil?
70
- ENV[USER] = username unless username.nil?
64
+ def environment_variables
65
+ {}.tap do |env|
66
+ env[HOST] = host unless host.nil?
67
+ env[PORT] = port.to_s unless port.nil?
68
+ env[PASSWORD] = password unless password.nil?
69
+ env[USER] = username unless username.nil?
70
+ end
71
71
  end
72
72
 
73
73
  # @since 0.4.0
74
74
  # @api private
75
75
  def dump_structure
76
- execute "pg_dump -s -x -O -T #{migrations_table} -f #{escape(schema)} #{database}"
76
+ execute "pg_dump -s -x -O -T #{migrations_table} -f #{escape(schema)} #{database}", env: environment_variables
77
77
  end
78
78
 
79
79
  # @since 0.4.0
80
80
  # @api private
81
81
  def load_structure
82
- execute "psql -X -q -f #{escape(schema)} #{database}" if schema.exist?
82
+ return unless schema.exist?
83
+
84
+ execute "psql -X -q -f #{escape(schema)} #{database}", env: environment_variables
83
85
  end
84
86
 
85
87
  # @since 0.4.0
86
88
  # @api private
87
89
  def dump_migrations_data
88
90
  error = ->(err) { raise MigrationError.new(err) unless err =~ /no matching tables/i }
89
- execute "pg_dump -t #{migrations_table} #{database} >> #{escape(schema)}", error: error
91
+ execute "pg_dump -t #{migrations_table} #{database} >> #{escape(schema)}", error: error, env: environment_variables
90
92
  end
91
93
 
92
94
  # @since 0.5.1
93
95
  # @api private
94
96
  def call_db_command(command)
95
- require 'open3'
97
+ require "open3"
96
98
 
97
99
  begin
98
- Open3.popen3(command, database) do |_stdin, _stdout, stderr, wait_thr|
99
- unless wait_thr.value.success? # wait_thr.value is the exit status
100
- raise MigrationError.new(modified_message(stderr.read))
101
- end
100
+ Open3.popen3(environment_variables, command, database) do |_stdin, _stdout, stderr, wait_thr|
101
+ raise MigrationError.new(modified_message(stderr.read)) unless wait_thr.value.success? # wait_thr.value is the exit status
102
102
  end
103
- rescue SystemCallError => e
104
- raise MigrationError.new(modified_message(e.message))
103
+ rescue SystemCallError => exception
104
+ raise MigrationError.new(modified_message(exception.message))
105
105
  end
106
106
  end
107
107
 
@@ -1,6 +1,8 @@
1
- require 'pathname'
2
- require 'hanami/utils'
3
- require 'English'
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+ require "hanami/utils"
5
+ require "English"
4
6
 
5
7
  module Hanami
6
8
  module Model
@@ -71,7 +73,7 @@ module Hanami
71
73
  # @api private
72
74
  def path
73
75
  root.join(
74
- @connection.uri.sub(/\A(jdbc:sqlite:\/\/|sqlite:\/\/)/, '')
76
+ @connection.uri.sub(/\A(jdbc:sqlite:\/\/|sqlite:\/\/)/, "")
75
77
  )
76
78
  end
77
79
 
@@ -104,13 +106,11 @@ module Hanami
104
106
  # @since 0.4.0
105
107
  # @api private
106
108
  #
107
- # rubocop:disable Metrics/AbcSize
108
- # rubocop:disable Metrics/MethodLength
109
109
  def dump_migrations_data
110
110
  execute "sqlite3 #{escape(path)} .dump" do |stdout|
111
111
  begin
112
112
  contents = stdout.read.split($INPUT_RECORD_SEPARATOR)
113
- contents = contents.grep(/^INSERT INTO "#{migrations_table}"/)
113
+ contents = contents.grep(/^INSERT INTO "?#{migrations_table}"?/)
114
114
 
115
115
  ::File.open(schema, ::File::CREAT | ::File::BINARY | ::File::WRONLY | ::File::APPEND) do |file|
116
116
  file.write(contents.join($INPUT_RECORD_SEPARATOR))
@@ -120,8 +120,6 @@ module Hanami
120
120
  end
121
121
  end
122
122
  end
123
- # rubocop:enable Metrics/MethodLength
124
- # rubocop:enable Metrics/AbcSize
125
123
  end
126
124
  end
127
125
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hanami
2
4
  module Model
3
5
  # Plugins to extend read/write operations from/to the database
@@ -17,9 +19,9 @@ module Hanami
17
19
  end
18
20
  end
19
21
 
20
- require 'hanami/model/plugins/mapping'
21
- require 'hanami/model/plugins/schema'
22
- require 'hanami/model/plugins/timestamps'
22
+ require "hanami/model/plugins/mapping"
23
+ require "hanami/model/plugins/schema"
24
+ require "hanami/model/plugins/timestamps"
23
25
  end
24
26
  end
25
27
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hanami
2
4
  module Model
3
5
  module Plugins
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hanami
2
4
  module Model
3
5
  module Plugins
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hanami
2
4
  module Model
3
5
  module Plugins
@@ -32,6 +34,7 @@ module Hanami
32
34
  # @api private
33
35
  def [](value)
34
36
  return @input[value] unless timestamps?
37
+
35
38
  _touch(@input[value], Time.now)
36
39
  end
37
40
 
@@ -1,5 +1,7 @@
1
- require_relative 'entity_name'
2
- require 'hanami/utils/string'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "entity_name"
4
+ require "hanami/utils/string"
3
5
 
4
6
  module Hanami
5
7
  module Model
@@ -1,12 +1,14 @@
1
- require 'rom-sql'
2
- require 'hanami/utils'
1
+ # frozen_string_literal: true
2
+
3
+ require "rom-sql"
4
+ require "hanami/utils"
3
5
 
4
6
  module Hanami
5
7
  # Hanami::Model migrations
6
8
  module Model
7
- require 'hanami/model/error'
8
- require 'hanami/model/association'
9
- require 'hanami/model/migration'
9
+ require "hanami/model/error"
10
+ require "hanami/model/association"
11
+ require "hanami/model/migration"
10
12
 
11
13
  # Define a migration
12
14
  #
@@ -53,8 +55,8 @@ module Hanami
53
55
  #
54
56
  # @since 0.7.0
55
57
  module Sql
56
- require 'hanami/model/sql/types'
57
- require 'hanami/model/sql/entity/schema'
58
+ require "hanami/model/sql/types"
59
+ require "hanami/model/sql/entity/schema"
58
60
 
59
61
  # Returns a SQL fragment that references a database function by the given name
60
62
  # This is useful for database migrations
@@ -1,4 +1,6 @@
1
- require 'uri'
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
2
4
 
3
5
  module Hanami
4
6
  module Model
@@ -24,16 +26,16 @@ module Hanami
24
26
 
25
27
  # @since 0.7.0
26
28
  # @api private
27
- def console # rubocop:disable Metrics/MethodLength
29
+ def console
28
30
  case @uri.scheme
29
- when 'sqlite'
30
- require 'hanami/model/sql/consoles/sqlite'
31
+ when "sqlite"
32
+ require "hanami/model/sql/consoles/sqlite"
31
33
  Sql::Consoles::Sqlite.new(@uri)
32
- when 'postgres', 'postgresql'
33
- require 'hanami/model/sql/consoles/postgresql'
34
+ when "postgres", "postgresql"
35
+ require "hanami/model/sql/consoles/postgresql"
34
36
  Sql::Consoles::Postgresql.new(@uri)
35
- when 'mysql', 'mysql2'
36
- require 'hanami/model/sql/consoles/mysql'
37
+ when "mysql", "mysql2"
38
+ require "hanami/model/sql/consoles/mysql"
37
39
  Sql::Consoles::Mysql.new(@uri)
38
40
  end
39
41
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hanami
2
4
  module Model
3
5
  module Sql
@@ -18,7 +20,7 @@ module Hanami
18
20
  # @since 0.7.0
19
21
  # @api private
20
22
  def database_name
21
- @uri.path.sub(/^\//, '')
23
+ @uri.path.sub(/^\//, "")
22
24
  end
23
25
 
24
26
  # @since 0.7.0
@@ -1,4 +1,6 @@
1
- require_relative 'abstract'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "abstract"
2
4
 
3
5
  module Hanami
4
6
  module Model
@@ -11,7 +13,7 @@ module Hanami
11
13
  class Mysql < Abstract
12
14
  # @since 0.7.0
13
15
  # @api private
14
- COMMAND = 'mysql'.freeze
16
+ COMMAND = "mysql"
15
17
 
16
18
  # @since 0.7.0
17
19
  # @api private
@@ -1,5 +1,7 @@
1
- require_relative 'abstract'
2
- require 'cgi'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "abstract"
4
+ require "cgi"
3
5
 
4
6
  module Hanami
5
7
  module Model
@@ -12,11 +14,11 @@ module Hanami
12
14
  class Postgresql < Abstract
13
15
  # @since 0.7.0
14
16
  # @api private
15
- COMMAND = 'psql'.freeze
17
+ COMMAND = "psql"
16
18
 
17
19
  # @since 0.7.0
18
20
  # @api private
19
- PASSWORD = 'PGPASSWORD'.freeze
21
+ PASSWORD = "PGPASSWORD"
20
22
 
21
23
  # @since 0.7.0
22
24
  # @api private
@@ -48,22 +50,22 @@ module Hanami
48
50
  # @since 0.7.0
49
51
  # @api private
50
52
  def port
51
- port = query['port'] || @uri.port
53
+ port = query["port"] || @uri.port
52
54
  " -p #{port}" if port
53
55
  end
54
56
 
55
57
  # @since 0.7.0
56
58
  # @api private
57
59
  def username
58
- username = query['user'] || @uri.user
60
+ username = query["user"] || @uri.user
59
61
  " -U #{username}" if username
60
62
  end
61
63
 
62
64
  # @since 0.7.0
63
65
  # @api private
64
66
  def configure_password
65
- password = query['password'] || @uri.password
66
- ENV[PASSWORD] = CGI.unescape(query['password'] || @uri.password) if password
67
+ password = query["password"] || @uri.password
68
+ ENV[PASSWORD] = CGI.unescape(query["password"] || @uri.password) if password
67
69
  end
68
70
 
69
71
  # @since 1.1.0