hanami-model 1.2.0 → 1.3.3
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 +4 -4
- data/CHANGELOG.md +21 -0
- data/LICENSE.md +1 -1
- data/README.md +10 -7
- data/hanami-model.gemspec +25 -20
- data/lib/hanami-model.rb +3 -1
- data/lib/hanami/entity.rb +6 -3
- data/lib/hanami/entity/schema.rb +10 -7
- data/lib/hanami/model.rb +15 -12
- data/lib/hanami/model/association.rb +7 -7
- data/lib/hanami/model/associations/belongs_to.rb +3 -1
- data/lib/hanami/model/associations/dsl.rb +2 -2
- data/lib/hanami/model/associations/has_many.rb +10 -8
- data/lib/hanami/model/associations/has_one.rb +9 -7
- data/lib/hanami/model/associations/many_to_many.rb +9 -11
- data/lib/hanami/model/configuration.rb +29 -10
- data/lib/hanami/model/configurator.rb +5 -3
- data/lib/hanami/model/entity_name.rb +4 -2
- data/lib/hanami/model/error.rb +18 -7
- data/lib/hanami/model/mapped_relation.rb +4 -2
- data/lib/hanami/model/mapping.rb +3 -1
- data/lib/hanami/model/migration.rb +2 -0
- data/lib/hanami/model/migrator.rb +7 -5
- data/lib/hanami/model/migrator/adapter.rb +14 -12
- data/lib/hanami/model/migrator/connection.rb +16 -9
- data/lib/hanami/model/migrator/logger.rb +3 -1
- data/lib/hanami/model/migrator/mysql_adapter.rb +23 -13
- data/lib/hanami/model/migrator/postgres_adapter.rb +31 -31
- data/lib/hanami/model/migrator/sqlite_adapter.rb +7 -9
- data/lib/hanami/model/plugins.rb +5 -3
- data/lib/hanami/model/plugins/mapping.rb +2 -0
- data/lib/hanami/model/plugins/schema.rb +2 -0
- data/lib/hanami/model/plugins/timestamps.rb +3 -0
- data/lib/hanami/model/relation_name.rb +4 -2
- data/lib/hanami/model/sql.rb +9 -7
- data/lib/hanami/model/sql/console.rb +10 -8
- data/lib/hanami/model/sql/consoles/abstract.rb +3 -1
- data/lib/hanami/model/sql/consoles/mysql.rb +4 -2
- data/lib/hanami/model/sql/consoles/postgresql.rb +10 -8
- data/lib/hanami/model/sql/consoles/sqlite.rb +6 -4
- data/lib/hanami/model/sql/entity/schema.rb +6 -4
- data/lib/hanami/model/sql/types.rb +27 -27
- data/lib/hanami/model/sql/types/schema/coercions.rb +5 -4
- data/lib/hanami/model/types.rb +4 -4
- data/lib/hanami/model/version.rb +3 -1
- data/lib/hanami/repository.rb +20 -31
- metadata +64 -8
|
@@ -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 =
|
|
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 =
|
|
16
|
-
|
|
17
|
-
|
|
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 =>
|
|
24
|
-
message = if
|
|
29
|
+
rescue Sequel::DatabaseError => exception
|
|
30
|
+
message = if exception.message.match(/database exists/)
|
|
25
31
|
DB_CREATION_ERROR
|
|
26
32
|
else
|
|
27
|
-
|
|
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 =>
|
|
38
|
-
message = if
|
|
43
|
+
rescue Sequel::DatabaseError => exception
|
|
44
|
+
message = if exception.message.match(/doesn\'t exist/)
|
|
39
45
|
"Cannot find database: #{database}"
|
|
40
46
|
else
|
|
41
|
-
|
|
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: {
|
|
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: {
|
|
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: {
|
|
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 =
|
|
15
|
+
HOST = "PGHOST"
|
|
12
16
|
|
|
13
17
|
# @since 0.4.0
|
|
14
18
|
# @api private
|
|
15
|
-
PORT =
|
|
19
|
+
PORT = "PGPORT"
|
|
16
20
|
|
|
17
21
|
# @since 0.4.0
|
|
18
22
|
# @api private
|
|
19
|
-
USER =
|
|
23
|
+
USER = "PGUSER"
|
|
20
24
|
|
|
21
25
|
# @since 0.4.0
|
|
22
26
|
# @api private
|
|
23
|
-
PASSWORD =
|
|
27
|
+
PASSWORD = "PGPASSWORD"
|
|
24
28
|
|
|
25
29
|
# @since 1.0.0
|
|
26
30
|
# @api private
|
|
27
|
-
DB_CREATION_ERROR =
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
62
|
+
# @since 1.3.3
|
|
65
63
|
# @api private
|
|
66
|
-
def
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
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
|
|
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 =>
|
|
104
|
-
raise MigrationError.new(modified_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
|
-
|
|
2
|
-
|
|
3
|
-
require
|
|
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 "
|
|
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
|
data/lib/hanami/model/plugins.rb
CHANGED
|
@@ -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
|
|
21
|
-
require
|
|
22
|
-
require
|
|
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
|
data/lib/hanami/model/sql.rb
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
|
8
|
-
require
|
|
9
|
-
require
|
|
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
|
|
57
|
-
require
|
|
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
|
-
|
|
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
|
|
29
|
+
def console
|
|
28
30
|
case @uri.scheme
|
|
29
|
-
when
|
|
30
|
-
require
|
|
31
|
+
when "sqlite"
|
|
32
|
+
require "hanami/model/sql/consoles/sqlite"
|
|
31
33
|
Sql::Consoles::Sqlite.new(@uri)
|
|
32
|
-
when
|
|
33
|
-
require
|
|
34
|
+
when "postgres", "postgresql"
|
|
35
|
+
require "hanami/model/sql/consoles/postgresql"
|
|
34
36
|
Sql::Consoles::Postgresql.new(@uri)
|
|
35
|
-
when
|
|
36
|
-
require
|
|
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,4 +1,6 @@
|
|
|
1
|
-
|
|
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 =
|
|
16
|
+
COMMAND = "mysql"
|
|
15
17
|
|
|
16
18
|
# @since 0.7.0
|
|
17
19
|
# @api private
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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 =
|
|
17
|
+
COMMAND = "psql"
|
|
16
18
|
|
|
17
19
|
# @since 0.7.0
|
|
18
20
|
# @api private
|
|
19
|
-
PASSWORD =
|
|
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[
|
|
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[
|
|
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[
|
|
66
|
-
ENV[PASSWORD] = CGI.unescape(query[
|
|
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
|