rom-sql 3.0.0 → 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +425 -296
  3. data/LICENSE +20 -0
  4. data/README.md +14 -55
  5. data/lib/rom-sql.rb +2 -0
  6. data/lib/rom/plugins/relation/sql/auto_restrictions.rb +2 -0
  7. data/lib/rom/plugins/relation/sql/instrumentation.rb +2 -0
  8. data/lib/rom/plugins/relation/sql/postgres/explain.rb +6 -7
  9. data/lib/rom/plugins/relation/sql/postgres/full_text_search.rb +53 -0
  10. data/lib/rom/plugins/relation/sql/postgres/streaming.rb +97 -0
  11. data/lib/rom/sql.rb +2 -0
  12. data/lib/rom/sql/associations.rb +2 -0
  13. data/lib/rom/sql/associations/core.rb +10 -0
  14. data/lib/rom/sql/associations/many_to_many.rb +3 -1
  15. data/lib/rom/sql/associations/many_to_one.rb +2 -0
  16. data/lib/rom/sql/associations/one_to_many.rb +2 -0
  17. data/lib/rom/sql/associations/one_to_one.rb +2 -0
  18. data/lib/rom/sql/associations/one_to_one_through.rb +2 -0
  19. data/lib/rom/sql/associations/self_ref.rb +2 -0
  20. data/lib/rom/sql/attribute.rb +31 -22
  21. data/lib/rom/sql/attribute_aliasing.rb +88 -0
  22. data/lib/rom/sql/attribute_wrapping.rb +30 -0
  23. data/lib/rom/sql/commands.rb +2 -0
  24. data/lib/rom/sql/commands/create.rb +2 -0
  25. data/lib/rom/sql/commands/delete.rb +2 -0
  26. data/lib/rom/sql/commands/error_wrapper.rb +2 -0
  27. data/lib/rom/sql/commands/update.rb +2 -0
  28. data/lib/rom/sql/dsl.rb +11 -3
  29. data/lib/rom/sql/error.rb +2 -0
  30. data/lib/rom/sql/errors.rb +2 -0
  31. data/lib/rom/sql/extensions.rb +2 -0
  32. data/lib/rom/sql/extensions/active_support_notifications.rb +2 -0
  33. data/lib/rom/sql/extensions/mysql.rb +2 -0
  34. data/lib/rom/sql/extensions/mysql/type_builder.rb +2 -0
  35. data/lib/rom/sql/extensions/postgres.rb +3 -0
  36. data/lib/rom/sql/extensions/postgres/commands.rb +3 -1
  37. data/lib/rom/sql/extensions/postgres/type_builder.rb +6 -4
  38. data/lib/rom/sql/extensions/postgres/type_serializer.rb +2 -0
  39. data/lib/rom/sql/extensions/postgres/types.rb +2 -0
  40. data/lib/rom/sql/extensions/postgres/types/array.rb +7 -6
  41. data/lib/rom/sql/extensions/postgres/types/array_types.rb +3 -1
  42. data/lib/rom/sql/extensions/postgres/types/geometric.rb +2 -0
  43. data/lib/rom/sql/extensions/postgres/types/json.rb +76 -19
  44. data/lib/rom/sql/extensions/postgres/types/ltree.rb +25 -23
  45. data/lib/rom/sql/extensions/postgres/types/network.rb +2 -0
  46. data/lib/rom/sql/extensions/postgres/types/range.rb +2 -0
  47. data/lib/rom/sql/extensions/rails_log_subscriber.rb +2 -0
  48. data/lib/rom/sql/extensions/sqlite.rb +2 -0
  49. data/lib/rom/sql/extensions/sqlite/type_builder.rb +2 -0
  50. data/lib/rom/sql/extensions/sqlite/types.rb +2 -0
  51. data/lib/rom/sql/foreign_key.rb +3 -1
  52. data/lib/rom/sql/function.rb +30 -3
  53. data/lib/rom/sql/gateway.rb +9 -1
  54. data/lib/rom/sql/group_dsl.rb +2 -0
  55. data/lib/rom/sql/index.rb +2 -0
  56. data/lib/rom/sql/join_dsl.rb +2 -0
  57. data/lib/rom/sql/mapper_compiler.rb +12 -1
  58. data/lib/rom/sql/migration.rb +5 -3
  59. data/lib/rom/sql/migration/inline_runner.rb +2 -0
  60. data/lib/rom/sql/migration/migrator.rb +4 -2
  61. data/lib/rom/sql/migration/recorder.rb +2 -0
  62. data/lib/rom/sql/migration/runner.rb +4 -2
  63. data/lib/rom/sql/migration/schema_diff.rb +2 -0
  64. data/lib/rom/sql/migration/template.rb +2 -0
  65. data/lib/rom/sql/migration/writer.rb +12 -4
  66. data/lib/rom/sql/order_dsl.rb +2 -0
  67. data/lib/rom/sql/plugin/associates.rb +4 -2
  68. data/lib/rom/sql/plugin/nullify.rb +37 -0
  69. data/lib/rom/sql/plugin/pagination.rb +2 -0
  70. data/lib/rom/sql/plugins.rb +4 -0
  71. data/lib/rom/sql/projection_dsl.rb +3 -1
  72. data/lib/rom/sql/rake_task.rb +2 -0
  73. data/lib/rom/sql/relation.rb +3 -1
  74. data/lib/rom/sql/relation/reading.rb +35 -7
  75. data/lib/rom/sql/relation/writing.rb +2 -0
  76. data/lib/rom/sql/restriction_dsl.rb +9 -1
  77. data/lib/rom/sql/schema.rb +16 -2
  78. data/lib/rom/sql/schema/attributes_inferrer.rb +5 -3
  79. data/lib/rom/sql/schema/dsl.rb +3 -1
  80. data/lib/rom/sql/schema/index_dsl.rb +5 -2
  81. data/lib/rom/sql/schema/inferrer.rb +12 -8
  82. data/lib/rom/sql/schema/type_builder.rb +4 -2
  83. data/lib/rom/sql/spec/support.rb +5 -3
  84. data/lib/rom/sql/tasks/migration_tasks.rake +16 -11
  85. data/lib/rom/sql/transaction.rb +2 -0
  86. data/lib/rom/sql/type_dsl.rb +2 -0
  87. data/lib/rom/sql/type_extensions.rb +4 -4
  88. data/lib/rom/sql/type_serializer.rb +2 -0
  89. data/lib/rom/sql/types.rb +2 -0
  90. data/lib/rom/sql/version.rb +3 -1
  91. data/lib/rom/sql/wrap.rb +2 -0
  92. data/lib/rom/types/values.rb +2 -0
  93. metadata +34 -32
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015-2020 rom-rb team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ 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, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,69 +1,28 @@
1
1
  [gem]: https://rubygems.org/gems/rom-sql
2
- [travis]: https://travis-ci.org/rom-rb/rom-sql
3
- [codeclimate]: https://codeclimate.com/github/rom-rb/rom-sql
2
+ [actions]: https://github.com/rom-rb/rom-sql/actions
3
+ [codacy]: https://www.codacy.com/gh/rom-rb/rom-sql
4
+ [chat]: https://rom-rb.zulipchat.com
4
5
  [inchpages]: http://inch-ci.org/github/rom-rb/rom-sql
5
6
 
6
- # rom-sql
7
+ # rom-sql [![Join the chat at https://rom-rb.zulipchat.com](https://img.shields.io/badge/rom--rb-join%20chat-%23346b7a.svg)][chat]
7
8
 
8
9
  [![Gem Version](https://badge.fury.io/rb/rom-sql.svg)][gem]
9
- [![Build Status](https://travis-ci.org/rom-rb/rom-sql.svg?branch=master)][travis]
10
- [![Code Climate](https://codeclimate.com/github/rom-rb/rom-sql/badges/gpa.svg)][codeclimate]
11
- [![Test Coverage](https://codeclimate.com/github/rom-rb/rom-sql/badges/coverage.svg)][codeclimate]
10
+ [![CI Status](https://github.com/rom-rb/rom-sql/workflows/ci/badge.svg)][actions]
11
+ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/8e2cbaf78af44185876c8fa41540d7ea)][codacy]
12
+ [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/8e2cbaf78af44185876c8fa41540d7ea)][codacy]
12
13
  [![Inline docs](http://inch-ci.org/github/rom-rb/rom-sql.svg?branch=master)][inchpages]
13
14
 
14
- SQL support for [rom-rb](https://github.com/rom-rb/rom).
15
+ ## Links
15
16
 
16
- Resources:
17
+ * [User documentation](http://rom-rb.org/learn/sql)
18
+ * [API documentation](http://rubydoc.info/gems/rom-sql)
17
19
 
18
- - [User Documentation](http://rom-rb.org/learn/sql/)
19
- - [API Documentation](http://rubydoc.info/gems/rom-sql)
20
+ ## Supported Ruby versions
20
21
 
21
- ## Installation
22
+ This library officially supports the following Ruby versions:
22
23
 
23
- Add this line to your application's Gemfile:
24
-
25
- ```ruby
26
- gem 'rom-sql'
27
- ```
28
-
29
- And then execute:
30
-
31
- $ bundle
32
-
33
- Or install it yourself as:
34
-
35
- $ gem install rom-sql
36
-
37
- ## Docker
38
-
39
- ### Development
40
-
41
- In order to have reproducible environment for development, Docker can be used. Provided it's installed, in order to start developing, one can simply execute:
42
-
43
- ```bash
44
- docker-compose run --rm gem "bash"
45
- ```
46
-
47
- If this is the first time this command is executed, it will take some time to set up the dependencies and build the rom-sql container. This should happen only on first execution and in case dependency images are removed.
48
-
49
- After dependencies are set container will be started in a bash shell.
50
-
51
- ### Testing
52
-
53
- In order to test the changes, execute:
54
-
55
- ```bash
56
- docker-compose build gem
57
- docker-compose run --rm gem 'rspec'
58
- ```
59
-
60
- ### Stopping the dependencies
61
-
62
- In order to stop the dependencies, execute:
63
-
64
- ```bash
65
- docker-compose down --remove-orphans --volumes
66
- ```
24
+ * MRI >= `2.5`
25
+ * jruby >= `9.2`
67
26
 
68
27
  ## License
69
28
 
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/sql'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/support/notifications'
2
4
 
3
5
  module ROM
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ROM
2
4
  module Plugins
3
5
  module Relation
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ROM
2
4
  module Plugins
3
5
  module Relation
@@ -24,14 +26,11 @@ module ROM
24
26
  #
25
27
  # @api public
26
28
  def explain(format: :text, **options)
27
- bool_options = options.map { |opt, value| "#{ opt.to_s.upcase } #{ !!value }" }
28
- format_option = "FORMAT #{ format.to_s.upcase }"
29
+ bool_options = options.map { |opt, value| "#{opt.to_s.upcase} #{!!value}" }
30
+ format_option = "FORMAT #{format.to_s.upcase}"
31
+ explain_value = [format_option, *bool_options].join(', ')
29
32
 
30
- query =
31
- "EXPLAIN (" <<
32
- [format_option, *bool_options].join(', ') <<
33
- ") " <<
34
- dataset.sql
33
+ query = "EXPLAIN (#{explain_value}) #{dataset.sql}"
35
34
 
36
35
  rows = dataset.with_sql(query).map(:'QUERY PLAN')
37
36
 
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ROM
4
+ module Plugins
5
+ module Relation
6
+ module SQL
7
+ module Postgres
8
+ # PG-specific extensions which adds `Relation#full_text_search` method
9
+ #
10
+ # @api public
11
+ module FullTextSearch
12
+ # Run a full text search on PostgreSQL.
13
+ # By default, searching for the inclusion of any of the terms in any of the cols.
14
+ #
15
+ # @example
16
+ # posts.full_text_search([:title, :content], 'apples', language: 'english') # => Relation which match the 'apples' phrase
17
+ #
18
+ # @option :headline [String] Append a expression to the selected columns aliased to headline that contains an extract of the matched text.
19
+ #
20
+ # @option :language [String] The language to use for the search (default: 'simple')
21
+ #
22
+ # @option :plain [Boolean] Whether a plain search should be used (default: false). In this case, terms should be a single string, and it will do a search where cols contains all of the words in terms. This ignores search operators in terms.
23
+ #
24
+ # @option :phrase [Boolean] Similar to :plain, but also adding an ILIKE filter to ensure that returned rows also include the exact phrase used.
25
+ #
26
+ # @option :rank [Boolean] Set to true to order by the rank, so that closer matches are returned first.
27
+ #
28
+ # @option :to_tsquery [Symbol] Can be set to :plain or :phrase to specify the function to use to convert the terms to a ts_query.
29
+ #
30
+ # @option :tsquery [Boolean] Specifies the terms argument is already a valid SQL expression returning a tsquery, and can be used directly in the query.
31
+ #
32
+ # @option :tsvector [Boolean] Specifies the cols argument is already a valid SQL expression returning a tsvector, and can be used directly in the query.
33
+ #
34
+ # @return [Relation]
35
+ #
36
+ # @see https://www.postgresql.org/docs/current/textsearch.html PostgreSQL docs
37
+ #
38
+ # @api public
39
+ def full_text_search(*args, &block)
40
+ new dataset.__send__(__method__, *args, &block)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ ROM.plugins do
50
+ adapter :sql do
51
+ register :pg_full_text_search, ROM::Plugins::Relation::SQL::Postgres::FullTextSearch, type: :relation
52
+ end
53
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ROM
4
+ module Plugins
5
+ module Relation
6
+ module SQL
7
+ module Postgres
8
+ # PG-specific extensions which adds `Relation#stream` method
9
+ #
10
+ # @api public
11
+ module Streaming
12
+ extend Notifications::Listener
13
+
14
+ class StreamingNotSupportedError < StandardError; end
15
+
16
+ subscribe("configuration.gateway.connected") do |opts|
17
+ conn = opts[:connection]
18
+
19
+ next unless conn.database_type.to_sym == :postgres
20
+
21
+ next if defined?(JRUBY_VERSION)
22
+
23
+ begin
24
+ require "sequel_pg"
25
+ rescue LoadError
26
+ raise StreamingNotSupportedError, "add sequel_pg to Gemfile to use pg_streaming"
27
+ end
28
+
29
+ unless Sequel::Postgres.supports_streaming?
30
+ raise StreamingNotSupportedError, "postgres version does not support streaming"
31
+ end
32
+
33
+ conn.extension(:pg_streaming)
34
+ end
35
+
36
+ def self.included(klass)
37
+ super
38
+ ROM::Relation::Graph.include(Combined)
39
+ end
40
+
41
+ if defined?(JRUBY_VERSION)
42
+ # Allows you to stream returned rows one at a time, instead of
43
+ # collecting the entire result set in memory. Requires the `sequel_pg` gem
44
+ #
45
+ # @see https://github.com/jeremyevans/sequel_pg#streaming- sequel_pg docs
46
+ #
47
+ # @example
48
+ # posts.steam_each { |post| puts CSV.generate_line(post) }
49
+ #
50
+ # @return [Relation]
51
+ #
52
+ # @api publicY_VERSION
53
+ def stream_each
54
+ raise StreamingNotSupportedError, "not supported on jruby"
55
+ end
56
+ else
57
+ # Allows you to stream returned rows one at a time, instead of
58
+ # collecting the entire result set in memory. Requires the `sequel_pg` gem
59
+ #
60
+ # @see https://github.com/jeremyevans/sequel_pg#streaming- sequel_pg docs
61
+ #
62
+ # @example
63
+ # posts.steam_each { |post| puts CSV.generate_line(post) }
64
+ #
65
+ # @return [Relation]
66
+ #
67
+ # @api public
68
+ def stream_each
69
+ return to_enum unless block_given?
70
+
71
+ ds = dataset.stream
72
+
73
+ if auto_map?
74
+ ds.each { |tuple| yield(mapper.([output_schema[tuple]]).first) }
75
+ else
76
+ ds.each { |tuple| yield(output_schema[tuple]) }
77
+ end
78
+ end
79
+
80
+ module Combined
81
+ def stream_each
82
+ raise StreamingNotSupportedError, "not supported on combined relations"
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ ROM.plugins do
94
+ adapter :sql do
95
+ register :pg_streaming, ROM::Plugins::Relation::SQL::Postgres::Streaming, type: :relation
96
+ end
97
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/equalizer'
2
4
 
3
5
  require 'rom/core'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/sql/associations/many_to_many'
2
4
  require 'rom/sql/associations/many_to_one'
3
5
  require 'rom/sql/associations/one_to_many'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ROM
2
4
  module SQL
3
5
  module Associations
@@ -14,6 +16,14 @@ module ROM
14
16
 
15
17
  target.where(target_key => target_pks)
16
18
  end
19
+
20
+ # @api private
21
+ def wrapped
22
+ new_target = view ? target.send(view) : target
23
+ to_wrap = self.class.allocate
24
+ to_wrap.send(:initialize, definition, **options, target: new_target)
25
+ to_wrap.wrap
26
+ end
17
27
  end
18
28
  end
19
29
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/associations/many_to_many'
2
4
  require 'rom/sql/associations/core'
3
5
  require 'rom/sql/associations/self_ref'
@@ -18,7 +20,7 @@ module ROM
18
20
  if target != self.target
19
21
  target.schema.merge(join_schema)
20
22
  else
21
- left.schema.project(*columns)
23
+ left.schema.uniq.project(*columns)
22
24
  end
23
25
  else
24
26
  target_schema
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/associations/many_to_one'
2
4
  require 'rom/sql/associations/core'
3
5
  require 'rom/sql/associations/self_ref'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/associations/one_to_many'
2
4
  require 'rom/sql/associations/core'
3
5
  require 'rom/sql/associations/self_ref'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/sql/associations/one_to_many'
2
4
 
3
5
  module ROM
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/sql/associations/many_to_many'
2
4
 
3
5
  module ROM
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ROM
2
4
  module SQL
3
5
  module Associations
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'sequel/core'
2
4
  require 'dry/core/cache'
3
5
 
@@ -5,6 +7,8 @@ require 'rom/attribute'
5
7
 
6
8
  require 'rom/sql/type_extensions'
7
9
  require 'rom/sql/projection_dsl'
10
+ require 'rom/sql/attribute_wrapping'
11
+ require 'rom/sql/attribute_aliasing'
8
12
 
9
13
  module ROM
10
14
  module SQL
@@ -12,34 +16,24 @@ module ROM
12
16
  #
13
17
  # @api public
14
18
  class Attribute < ROM::Attribute
19
+ include AttributeWrapping
20
+ include AttributeAliasing
21
+
15
22
  OPERATORS = %i[>= <= > <].freeze
16
23
  NONSTANDARD_EQUALITY_VALUES = [true, false, nil].freeze
17
- META_KEYS = %i(index foreign_key target sql_expr qualified).freeze
24
+ META_KEYS = %i[index foreign_key target sql_expr qualified].freeze
18
25
 
19
26
  # Error raised when an attribute cannot be qualified
20
27
  QualifyError = Class.new(StandardError)
21
28
 
22
29
  extend Dry::Core::Cache
23
30
 
24
- # @api private
25
- def self.[](*args)
26
- fetch_or_store(args) { new(*args) }
27
- end
28
-
29
- # Return a new attribute with an alias
30
- #
31
- # @example
32
- # users[:id].aliased(:user_id)
33
- #
34
- # @return [SQL::Attribute]
35
- #
36
- # @api public
37
- def aliased(alias_name)
38
- super.with(name: name || alias_name).meta(
39
- sql_expr: sql_expr.as(alias_name)
40
- )
31
+ class << self
32
+ # @api private
33
+ def [](type, options = EMPTY_HASH)
34
+ fetch_or_store([type, options]) { new(type, **options) }
35
+ end
41
36
  end
42
- alias_method :as, :aliased
43
37
 
44
38
  # Return a new attribute in its canonical form
45
39
  #
@@ -73,6 +67,21 @@ module ROM
73
67
  end
74
68
  end
75
69
 
70
+ # Return a new attribute that is aliased and marked as qualified
71
+ #
72
+ # Intended to be used when passing attributes to `dataset#select`
73
+ #
74
+ # @return [SQL::Attribute]
75
+ #
76
+ # @api public
77
+ def qualified_projection(table_alias = nil)
78
+ if aliased?
79
+ qualified(table_alias).aliased(self.alias)
80
+ else
81
+ qualified(table_alias)
82
+ end
83
+ end
84
+
76
85
  # Return a new attribute marked as joined
77
86
  #
78
87
  # Whenever you join two schemas, the right schema's attribute
@@ -291,11 +300,11 @@ module ROM
291
300
  # @api private
292
301
  def to_sql_name
293
302
  @_to_sql_name ||=
294
- if qualified? && aliased?
303
+ if qualified? && aliased_projection?
295
304
  Sequel.qualify(table_name, name).as(self.alias)
296
305
  elsif qualified?
297
306
  Sequel.qualify(table_name, name)
298
- elsif aliased?
307
+ elsif aliased_projection?
299
308
  Sequel.as(name, self.alias)
300
309
  else
301
310
  Sequel[name]
@@ -328,7 +337,7 @@ module ROM
328
337
  cleaned_meta = meta.reject { |k, _| META_KEYS.include?(k) }
329
338
  type = optional? ? right : self.type
330
339
 
331
- self.class.new(type.with(meta: cleaned_meta), options)
340
+ self.class.new(type.with(meta: cleaned_meta), **options)
332
341
  end
333
342
 
334
343
  # Wrap a value with the type, it allows using attribute and type specific methods