hanami-model 1.0.1 → 1.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 +4 -4
- data/CHANGELOG.md +7 -0
- data/hanami-model.gemspec +2 -2
- data/lib/hanami/model/migrator/adapter.rb +10 -0
- data/lib/hanami/model/migrator/mysql_adapter.rb +3 -11
- data/lib/hanami/model/migrator/postgres_adapter.rb +4 -3
- data/lib/hanami/model/migrator/sqlite_adapter.rb +20 -3
- data/lib/hanami/model/plugins/timestamps.rb +4 -5
- data/lib/hanami/model/sql/consoles/postgresql.rb +2 -1
- data/lib/hanami/model/sql/types.rb +13 -2
- data/lib/hanami/model/sql/types/schema/coercions.rb +23 -0
- data/lib/hanami/model/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b42e3225f01dfdc11db772e01e9380930378b34b
|
4
|
+
data.tar.gz: 61c681f2b8dacd1867ac9b929e84f2fc2d9da120
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7c31f943c0af575a6b1197c87d2ce0bcf1b1ccf3e42dab6869c85580e79f5f316c62d7c52093a8b96b4fb5ace02e237723fd3fa115398247e68c409871cb592
|
7
|
+
data.tar.gz: f6b396a6f8e57b35d9a213f9d49c45610a3dc3825fc8233e83721af811bdf411b270e6d1ce8420d745d91d725ba3ca826ffa1b6dca02e4976c44de79dc74a6e8
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
# Hanami::Model
|
2
2
|
A persistence layer for Hanami
|
3
3
|
|
4
|
+
## v1.0.2 - 2017-08-04
|
5
|
+
### Fixed
|
6
|
+
- [Maurizio De Magnis] URI escape for Postgres password
|
7
|
+
- [Marion Duprey] Ensure repository to generate timestamps values even when only one between `created_at` and `updated_at` is present
|
8
|
+
- [Paweł Świątkowski] Make Postgres JSON(B) to work with Ruby arrays
|
9
|
+
- [Luca Guidi] Don't remove migrations when running `Hanami::Model::Migrator#apply` fails to dump the database
|
10
|
+
|
4
11
|
## v1.0.1 - 2017-06-23
|
5
12
|
### Fixed
|
6
13
|
- [Kai Kuchenbecker & Marcello Rocha & Luca Guidi] Ensure `Hanami::Entity#initialize` to not serialize (into `Hash`) other entities passed as an argument
|
data/hanami-model.gemspec
CHANGED
@@ -22,8 +22,8 @@ Gem::Specification.new do |spec|
|
|
22
22
|
|
23
23
|
spec.add_runtime_dependency 'hanami-utils', '~> 1.0'
|
24
24
|
spec.add_runtime_dependency 'rom-sql', '~> 1.3'
|
25
|
-
spec.add_runtime_dependency 'rom-repository', '~> 1.
|
26
|
-
spec.add_runtime_dependency 'dry-types', '~> 0.
|
25
|
+
spec.add_runtime_dependency 'rom-repository', '~> 1.4'
|
26
|
+
spec.add_runtime_dependency 'dry-types', '~> 0.11'
|
27
27
|
spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
|
28
28
|
|
29
29
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'shellwords'
|
3
|
+
require 'open3'
|
3
4
|
|
4
5
|
module Hanami
|
5
6
|
module Model
|
@@ -176,6 +177,15 @@ module Hanami
|
|
176
177
|
def escape(string)
|
177
178
|
Shellwords.escape(string) unless string.nil?
|
178
179
|
end
|
180
|
+
|
181
|
+
# @since 1.0.2
|
182
|
+
# @api private
|
183
|
+
def execute(command, env: {}, error: ->(err) { raise MigrationError.new(err) })
|
184
|
+
Open3.popen3(env, command) do |_, stdout, stderr, wait_thr|
|
185
|
+
error.call(stderr.read) unless wait_thr.value.success?
|
186
|
+
yield stdout if block_given?
|
187
|
+
end
|
188
|
+
end
|
179
189
|
end
|
180
190
|
end
|
181
191
|
end
|
@@ -47,7 +47,6 @@ module Hanami
|
|
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,18 +54,11 @@ 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.7.0
|
65
|
-
# @api private
|
66
|
-
def set_environment_variables
|
67
|
-
ENV[PASSWORD] = password unless password.nil?
|
68
|
-
end
|
69
|
-
|
70
62
|
# @since 0.7.0
|
71
63
|
# @api private
|
72
64
|
def password
|
@@ -76,19 +68,19 @@ module Hanami
|
|
76
68
|
# @since 0.4.0
|
77
69
|
# @api private
|
78
70
|
def dump_structure
|
79
|
-
|
71
|
+
execute "mysqldump --host=#{host} --port=#{port} --user=#{username} --no-data --skip-comments --ignore-table=#{database}.#{migrations_table} #{database} > #{schema}", env: { PASSWORD => password }
|
80
72
|
end
|
81
73
|
|
82
74
|
# @since 0.4.0
|
83
75
|
# @api private
|
84
76
|
def load_structure
|
85
|
-
|
77
|
+
execute("mysql --host=#{host} --port=#{port} --user=#{username} #{database} < #{escape(schema)}", env: { PASSWORD => password }) if schema.exist?
|
86
78
|
end
|
87
79
|
|
88
80
|
# @since 0.4.0
|
89
81
|
# @api private
|
90
82
|
def dump_migrations_data
|
91
|
-
|
83
|
+
execute "mysqldump --host=#{host} --port=#{port} --user=#{username} --skip-comments #{database} #{migrations_table} >> #{schema}", env: { PASSWORD => password }
|
92
84
|
end
|
93
85
|
end
|
94
86
|
end
|
@@ -89,19 +89,20 @@ module Hanami
|
|
89
89
|
# @since 0.4.0
|
90
90
|
# @api private
|
91
91
|
def dump_structure
|
92
|
-
|
92
|
+
execute "pg_dump -s -x -O -T #{migrations_table} -f #{escape(schema)} #{database}"
|
93
93
|
end
|
94
94
|
|
95
95
|
# @since 0.4.0
|
96
96
|
# @api private
|
97
97
|
def load_structure
|
98
|
-
|
98
|
+
execute "psql -X -q -f #{escape(schema)} #{database}" if schema.exist?
|
99
99
|
end
|
100
100
|
|
101
101
|
# @since 0.4.0
|
102
102
|
# @api private
|
103
103
|
def dump_migrations_data
|
104
|
-
|
104
|
+
error = ->(err) { raise MigrationError.new(err) unless err =~ /no matching tables/i }
|
105
|
+
execute "pg_dump -t #{migrations_table} #{database} >> #{escape(schema)}", error: error
|
105
106
|
end
|
106
107
|
|
107
108
|
# @since 0.5.1
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'pathname'
|
2
2
|
require 'hanami/utils'
|
3
|
+
require 'English'
|
3
4
|
|
4
5
|
module Hanami
|
5
6
|
module Model
|
@@ -91,20 +92,36 @@ module Hanami
|
|
91
92
|
# @since 0.4.0
|
92
93
|
# @api private
|
93
94
|
def dump_structure
|
94
|
-
|
95
|
+
execute "sqlite3 #{escape(path)} .schema > #{escape(schema)}"
|
95
96
|
end
|
96
97
|
|
97
98
|
# @since 0.4.0
|
98
99
|
# @api private
|
99
100
|
def load_structure
|
100
|
-
|
101
|
+
execute "sqlite3 #{escape(path)} < #{escape(schema)}" if schema.exist?
|
101
102
|
end
|
102
103
|
|
103
104
|
# @since 0.4.0
|
104
105
|
# @api private
|
106
|
+
#
|
107
|
+
# rubocop:disable Metrics/AbcSize
|
108
|
+
# rubocop:disable Metrics/MethodLength
|
105
109
|
def dump_migrations_data
|
106
|
-
|
110
|
+
execute "sqlite3 #{escape(path)} .dump" do |stdout|
|
111
|
+
begin
|
112
|
+
contents = stdout.read.split($INPUT_RECORD_SEPARATOR)
|
113
|
+
contents = contents.grep(/^INSERT INTO "#{migrations_table}"/)
|
114
|
+
|
115
|
+
::File.open(schema, ::File::CREAT | ::File::BINARY | ::File::WRONLY | ::File::APPEND) do |file|
|
116
|
+
file.write(contents.join($INPUT_RECORD_SEPARATOR))
|
117
|
+
end
|
118
|
+
rescue => exception
|
119
|
+
raise MigrationError.new(exception.message)
|
120
|
+
end
|
121
|
+
end
|
107
122
|
end
|
123
|
+
# rubocop:enable Metrics/MethodLength
|
124
|
+
# rubocop:enable Metrics/AbcSize
|
108
125
|
end
|
109
126
|
end
|
110
127
|
end
|
@@ -23,8 +23,7 @@ module Hanami
|
|
23
23
|
# @api private
|
24
24
|
def initialize(relation, input)
|
25
25
|
super
|
26
|
-
|
27
|
-
@timestamps = (columns & TIMESTAMPS) == TIMESTAMPS
|
26
|
+
@timestamps = relation.columns & TIMESTAMPS
|
28
27
|
end
|
29
28
|
|
30
29
|
# Processes the input
|
@@ -49,7 +48,7 @@ module Hanami
|
|
49
48
|
# @since 0.7.0
|
50
49
|
# @api private
|
51
50
|
def timestamps?
|
52
|
-
|
51
|
+
!@timestamps.empty?
|
53
52
|
end
|
54
53
|
end
|
55
54
|
|
@@ -63,7 +62,7 @@ module Hanami
|
|
63
62
|
# @since 0.7.0
|
64
63
|
# @api private
|
65
64
|
def _touch(value, now)
|
66
|
-
value[:updated_at] ||= now
|
65
|
+
value[:updated_at] ||= now if @timestamps.include?(:updated_at)
|
67
66
|
value
|
68
67
|
end
|
69
68
|
end
|
@@ -79,7 +78,7 @@ module Hanami
|
|
79
78
|
# @api private
|
80
79
|
def _touch(value, now)
|
81
80
|
super
|
82
|
-
value[:created_at] ||= now
|
81
|
+
value[:created_at] ||= now if @timestamps.include?(:created_at)
|
83
82
|
value
|
84
83
|
end
|
85
84
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative 'abstract'
|
2
|
+
require 'cgi'
|
2
3
|
|
3
4
|
module Hanami
|
4
5
|
module Model
|
@@ -59,7 +60,7 @@ module Hanami
|
|
59
60
|
# @since 0.7.0
|
60
61
|
# @api private
|
61
62
|
def configure_password
|
62
|
-
ENV[PASSWORD] = @uri.password unless @uri.password.nil?
|
63
|
+
ENV[PASSWORD] = CGI.unescape(@uri.password) unless @uri.password.nil?
|
63
64
|
end
|
64
65
|
end
|
65
66
|
end
|
@@ -31,6 +31,8 @@ module Hanami
|
|
31
31
|
Array = Types::Strict::Nil | Types::Array.constructor(Coercions.method(:array))
|
32
32
|
Hash = Types::Strict::Nil | Types::Hash.constructor(Coercions.method(:hash))
|
33
33
|
|
34
|
+
PG_JSON = Types::Strict::Nil | Types::Any.constructor(Coercions.method(:pg_json))
|
35
|
+
|
34
36
|
# @since 0.7.0
|
35
37
|
# @api private
|
36
38
|
MAPPING = {
|
@@ -72,14 +74,23 @@ module Hanami
|
|
72
74
|
#
|
73
75
|
# MAPPING.fetch(unwrapped.pristine, attribute)
|
74
76
|
MAPPING.fetch(unwrapped.pristine) do
|
75
|
-
if
|
76
|
-
Schema::
|
77
|
+
if pg_json?(unwrapped.pristine)
|
78
|
+
Schema::PG_JSON
|
77
79
|
else
|
78
80
|
attribute
|
79
81
|
end
|
80
82
|
end
|
81
83
|
end
|
82
84
|
|
85
|
+
# @since 1.0.2
|
86
|
+
# @api private
|
87
|
+
def self.pg_json?(pristine)
|
88
|
+
(defined?(ROM::SQL::Types::PG::JSONB) && pristine == ROM::SQL::Types::PG::JSONB) ||
|
89
|
+
(defined?(ROM::SQL::Types::PG::JSON) && pristine == ROM::SQL::Types::PG::JSON)
|
90
|
+
end
|
91
|
+
|
92
|
+
private_class_method :pg_json?
|
93
|
+
|
83
94
|
# Coercer for SQL associations target
|
84
95
|
#
|
85
96
|
# @since 0.7.0
|
@@ -11,6 +11,7 @@ module Hanami
|
|
11
11
|
# @since 0.7.0
|
12
12
|
# @api private
|
13
13
|
#
|
14
|
+
# rubocop:disable Metrics/ModuleLength
|
14
15
|
# rubocop:disable Metrics/MethodLength
|
15
16
|
module Coercions
|
16
17
|
# Coerces given argument into Integer
|
@@ -192,8 +193,30 @@ module Hanami
|
|
192
193
|
raise ArgumentError.new("invalid value for Hash(): #{arg.inspect}")
|
193
194
|
end
|
194
195
|
end
|
196
|
+
|
197
|
+
# Coerces given argument to appropriate Postgres JSON(B) type, i.e. Hash or Array
|
198
|
+
#
|
199
|
+
# @param arg [Object] the object to coerce
|
200
|
+
#
|
201
|
+
# @return [Hash, Array] the result of the coercion
|
202
|
+
#
|
203
|
+
# @raise [ArgumentError] if the coercion fails
|
204
|
+
#
|
205
|
+
# @since 1.0.2
|
206
|
+
# @api private
|
207
|
+
def self.pg_json(arg)
|
208
|
+
case arg
|
209
|
+
when ->(a) { a.respond_to?(:to_hash) }
|
210
|
+
hash(arg)
|
211
|
+
when ->(a) { a.respond_to?(:to_a) }
|
212
|
+
array(arg)
|
213
|
+
else
|
214
|
+
raise ArgumentError.new("invalid value for PG_JSON(): #{arg.inspect}")
|
215
|
+
end
|
216
|
+
end
|
195
217
|
end
|
196
218
|
# rubocop:enable Metrics/MethodLength
|
219
|
+
# rubocop:enable Metrics/ModuleLength
|
197
220
|
end
|
198
221
|
end
|
199
222
|
end
|
data/lib/hanami/model/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hanami-model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-08-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hanami-utils
|
@@ -44,28 +44,28 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '1.
|
47
|
+
version: '1.4'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '1.
|
54
|
+
version: '1.4'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: dry-types
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0.
|
61
|
+
version: '0.11'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0.
|
68
|
+
version: '0.11'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: concurrent-ruby
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
192
192
|
version: '0'
|
193
193
|
requirements: []
|
194
194
|
rubyforge_project:
|
195
|
-
rubygems_version: 2.6.
|
195
|
+
rubygems_version: 2.6.11
|
196
196
|
signing_key:
|
197
197
|
specification_version: 4
|
198
198
|
summary: A persistence layer for Hanami
|