rom-sql 2.0.0.beta2 → 2.0.0.beta3

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.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -0
  3. data/lib/rom/plugins/relation/sql/postgres/explain.rb +54 -0
  4. data/lib/rom/sql.rb +1 -1
  5. data/lib/rom/sql/attribute.rb +17 -18
  6. data/lib/rom/sql/errors.rb +3 -0
  7. data/lib/rom/sql/extensions/mysql.rb +1 -1
  8. data/lib/rom/sql/extensions/mysql/type_builder.rb +28 -0
  9. data/lib/rom/sql/extensions/postgres.rb +3 -1
  10. data/lib/rom/sql/extensions/postgres/commands.rb +30 -13
  11. data/lib/rom/sql/extensions/postgres/{attributes_inferrer.rb → type_builder.rb} +24 -28
  12. data/lib/rom/sql/extensions/postgres/type_serializer.rb +39 -0
  13. data/lib/rom/sql/extensions/postgres/types.rb +24 -477
  14. data/lib/rom/sql/extensions/postgres/types/array.rb +163 -0
  15. data/lib/rom/sql/extensions/postgres/types/geometric.rb +135 -0
  16. data/lib/rom/sql/extensions/postgres/types/json.rb +235 -0
  17. data/lib/rom/sql/extensions/postgres/types/network.rb +15 -0
  18. data/lib/rom/sql/extensions/sqlite.rb +1 -1
  19. data/lib/rom/sql/extensions/sqlite/{attributes_inferrer.rb → type_builder.rb} +5 -5
  20. data/lib/rom/sql/extensions/sqlite/types.rb +8 -3
  21. data/lib/rom/sql/foreign_key.rb +17 -0
  22. data/lib/rom/sql/function.rb +86 -8
  23. data/lib/rom/sql/gateway.rb +26 -26
  24. data/lib/rom/sql/index.rb +4 -0
  25. data/lib/rom/sql/migration.rb +3 -3
  26. data/lib/rom/sql/migration/inline_runner.rb +9 -83
  27. data/lib/rom/sql/migration/migrator.rb +35 -12
  28. data/lib/rom/sql/migration/recorder.rb +21 -0
  29. data/lib/rom/sql/migration/runner.rb +115 -0
  30. data/lib/rom/sql/migration/schema_diff.rb +108 -53
  31. data/lib/rom/sql/migration/writer.rb +61 -0
  32. data/lib/rom/sql/relation.rb +2 -1
  33. data/lib/rom/sql/relation/reading.rb +63 -3
  34. data/lib/rom/sql/relation/writing.rb +38 -0
  35. data/lib/rom/sql/schema.rb +9 -3
  36. data/lib/rom/sql/schema/attributes_inferrer.rb +3 -119
  37. data/lib/rom/sql/schema/inferrer.rb +99 -18
  38. data/lib/rom/sql/schema/type_builder.rb +94 -0
  39. data/lib/rom/sql/type_dsl.rb +30 -0
  40. data/lib/rom/sql/type_extensions.rb +11 -6
  41. data/lib/rom/sql/type_serializer.rb +46 -0
  42. data/lib/rom/sql/types.rb +12 -0
  43. data/lib/rom/sql/version.rb +1 -1
  44. metadata +26 -244
  45. data/.codeclimate.yml +0 -15
  46. data/.gitignore +0 -17
  47. data/.rspec +0 -3
  48. data/.travis.yml +0 -39
  49. data/.yardopts +0 -2
  50. data/Gemfile +0 -33
  51. data/Guardfile +0 -24
  52. data/LICENSE.txt +0 -22
  53. data/Rakefile +0 -19
  54. data/circle.yml +0 -10
  55. data/lib/rom/sql/extensions/mysql/attributes_inferrer.rb +0 -10
  56. data/lib/rom/sql/relation/sequel_api.rb +0 -133
  57. data/log/.gitkeep +0 -0
  58. data/rom-sql.gemspec +0 -29
  59. data/spec/extensions/postgres/attribute_spec.rb +0 -217
  60. data/spec/extensions/postgres/integration_spec.rb +0 -59
  61. data/spec/extensions/postgres/types_spec.rb +0 -252
  62. data/spec/extensions/sqlite/types_spec.rb +0 -11
  63. data/spec/fixtures/migrations/20150403090603_create_carrots.rb +0 -8
  64. data/spec/integration/associations/many_to_many/custom_fks_spec.rb +0 -76
  65. data/spec/integration/associations/many_to_many/from_view_spec.rb +0 -88
  66. data/spec/integration/associations/many_to_many_spec.rb +0 -162
  67. data/spec/integration/associations/many_to_one/custom_fks_spec.rb +0 -64
  68. data/spec/integration/associations/many_to_one/from_view_spec.rb +0 -84
  69. data/spec/integration/associations/many_to_one/self_ref_spec.rb +0 -53
  70. data/spec/integration/associations/many_to_one_spec.rb +0 -117
  71. data/spec/integration/associations/one_to_many/custom_fks_spec.rb +0 -54
  72. data/spec/integration/associations/one_to_many/from_view_spec.rb +0 -57
  73. data/spec/integration/associations/one_to_many/self_ref_spec.rb +0 -54
  74. data/spec/integration/associations/one_to_many_spec.rb +0 -86
  75. data/spec/integration/associations/one_to_one_spec.rb +0 -69
  76. data/spec/integration/associations/one_to_one_through_spec.rb +0 -92
  77. data/spec/integration/auto_migrations/errors_spec.rb +0 -31
  78. data/spec/integration/auto_migrations/indexes_spec.rb +0 -253
  79. data/spec/integration/auto_migrations/managing_columns_spec.rb +0 -156
  80. data/spec/integration/auto_migrations/postgres/column_types_spec.rb +0 -63
  81. data/spec/integration/combine_with_spec.rb +0 -43
  82. data/spec/integration/commands/create_spec.rb +0 -304
  83. data/spec/integration/commands/delete_spec.rb +0 -84
  84. data/spec/integration/commands/update_spec.rb +0 -90
  85. data/spec/integration/commands/upsert_spec.rb +0 -83
  86. data/spec/integration/gateway_spec.rb +0 -107
  87. data/spec/integration/migration_spec.rb +0 -55
  88. data/spec/integration/plugins/associates/many_to_many_spec.rb +0 -69
  89. data/spec/integration/plugins/associates_spec.rb +0 -250
  90. data/spec/integration/plugins/auto_restrictions_spec.rb +0 -74
  91. data/spec/integration/relation_schema_spec.rb +0 -271
  92. data/spec/integration/schema/call_spec.rb +0 -24
  93. data/spec/integration/schema/inferrer/mysql_spec.rb +0 -45
  94. data/spec/integration/schema/inferrer/postgres_spec.rb +0 -203
  95. data/spec/integration/schema/inferrer/sqlite_spec.rb +0 -37
  96. data/spec/integration/schema/inferrer_spec.rb +0 -390
  97. data/spec/integration/schema/prefix_spec.rb +0 -16
  98. data/spec/integration/schema/qualified_spec.rb +0 -16
  99. data/spec/integration/schema/rename_spec.rb +0 -21
  100. data/spec/integration/schema/view_spec.rb +0 -29
  101. data/spec/integration/sequel_api_spec.rb +0 -36
  102. data/spec/integration/setup_spec.rb +0 -26
  103. data/spec/integration/support/active_support_notifications_spec.rb +0 -24
  104. data/spec/integration/support/rails_log_subscriber_spec.rb +0 -30
  105. data/spec/integration/wrap_spec.rb +0 -91
  106. data/spec/shared/accounts.rb +0 -48
  107. data/spec/shared/database_setup.rb +0 -70
  108. data/spec/shared/notes.rb +0 -23
  109. data/spec/shared/posts.rb +0 -34
  110. data/spec/shared/puppies.rb +0 -15
  111. data/spec/shared/relations.rb +0 -8
  112. data/spec/shared/users.rb +0 -32
  113. data/spec/shared/users_and_tasks.rb +0 -50
  114. data/spec/spec_helper.rb +0 -122
  115. data/spec/support/env_helper.rb +0 -25
  116. data/spec/support/helpers.rb +0 -24
  117. data/spec/support/oracle/create_users.sql +0 -7
  118. data/spec/support/oracle/set_sys_passwords.sql +0 -2
  119. data/spec/support/test_configuration.rb +0 -16
  120. data/spec/unit/attribute_spec.rb +0 -104
  121. data/spec/unit/function_spec.rb +0 -48
  122. data/spec/unit/gateway_spec.rb +0 -70
  123. data/spec/unit/logger_spec.rb +0 -14
  124. data/spec/unit/migration_tasks_spec.rb +0 -111
  125. data/spec/unit/migrator_spec.rb +0 -25
  126. data/spec/unit/order_dsl_spec.rb +0 -43
  127. data/spec/unit/plugin/associates_spec.rb +0 -94
  128. data/spec/unit/plugin/pagination_spec.rb +0 -91
  129. data/spec/unit/plugin/timestamp_spec.rb +0 -117
  130. data/spec/unit/projection_dsl_spec.rb +0 -110
  131. data/spec/unit/relation/assoc_spec.rb +0 -87
  132. data/spec/unit/relation/associations_spec.rb +0 -27
  133. data/spec/unit/relation/avg_spec.rb +0 -11
  134. data/spec/unit/relation/by_pk_spec.rb +0 -62
  135. data/spec/unit/relation/dataset_spec.rb +0 -50
  136. data/spec/unit/relation/distinct_spec.rb +0 -15
  137. data/spec/unit/relation/exclude_spec.rb +0 -11
  138. data/spec/unit/relation/exist_predicate_spec.rb +0 -25
  139. data/spec/unit/relation/exists_spec.rb +0 -18
  140. data/spec/unit/relation/fetch_spec.rb +0 -21
  141. data/spec/unit/relation/group_spec.rb +0 -61
  142. data/spec/unit/relation/having_spec.rb +0 -22
  143. data/spec/unit/relation/inner_join_spec.rb +0 -158
  144. data/spec/unit/relation/inspect_spec.rb +0 -11
  145. data/spec/unit/relation/instrument_spec.rb +0 -45
  146. data/spec/unit/relation/invert_spec.rb +0 -11
  147. data/spec/unit/relation/left_join_spec.rb +0 -55
  148. data/spec/unit/relation/lock_spec.rb +0 -93
  149. data/spec/unit/relation/map_spec.rb +0 -16
  150. data/spec/unit/relation/max_spec.rb +0 -11
  151. data/spec/unit/relation/min_spec.rb +0 -11
  152. data/spec/unit/relation/order_spec.rb +0 -51
  153. data/spec/unit/relation/pluck_spec.rb +0 -11
  154. data/spec/unit/relation/prefix_spec.rb +0 -29
  155. data/spec/unit/relation/primary_key_spec.rb +0 -27
  156. data/spec/unit/relation/project_spec.rb +0 -24
  157. data/spec/unit/relation/qualified_columns_spec.rb +0 -30
  158. data/spec/unit/relation/qualified_spec.rb +0 -25
  159. data/spec/unit/relation/read_spec.rb +0 -25
  160. data/spec/unit/relation/rename_spec.rb +0 -23
  161. data/spec/unit/relation/right_join_spec.rb +0 -57
  162. data/spec/unit/relation/select_append_spec.rb +0 -21
  163. data/spec/unit/relation/select_spec.rb +0 -40
  164. data/spec/unit/relation/sum_spec.rb +0 -11
  165. data/spec/unit/relation/union_spec.rb +0 -19
  166. data/spec/unit/relation/unique_predicate_spec.rb +0 -18
  167. data/spec/unit/relation/where_spec.rb +0 -133
  168. data/spec/unit/restriction_dsl_spec.rb +0 -34
  169. data/spec/unit/schema_spec.rb +0 -25
  170. data/spec/unit/types_spec.rb +0 -65
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8f6a088c5111442c8a6ac85b97315143395afd3a
4
- data.tar.gz: 909c97090b071f2229b84055686ea34c0a31d9e2
3
+ metadata.gz: 3c40812f8e5e3a90dbb8a24608845b06a69f2e7c
4
+ data.tar.gz: 0675140e980842b9bfe70aae46826b7e1c4ccb4c
5
5
  SHA512:
6
- metadata.gz: ebaf850abe38152fad88f59e91a50ecd2ea882b5e9159a252f30b32da5b383dfd8a8079095454daf7c5cffefd8e72da20f7c7c86094f50a4109b0f5fd00bbd09
7
- data.tar.gz: 36d28232439734adc2de2f440a28cc57374250efbd001bb4291939ea39c01d7e9cddf1020833bf840baf450ae2f8bee9319b0fd5a8bc93cfcb5eacfb4c26efc7
6
+ metadata.gz: 872afeaa13eb89ce9bb8606b5dc88f599d01169201464b66f746784baef1dd297fb2cfdf4f1da5f3772e54427d8a19168bd6266444b969b5cf5dbac4f781efec
7
+ data.tar.gz: b344cad962d4db308295b01c37ec7efdbcfd41d30c7aeeb51cae997188238fa73cc4273c07b12a088c283fbc25035d1afdc63b1bd7734711b70344b2cefef72c
data/CHANGELOG.md CHANGED
@@ -4,14 +4,80 @@
4
4
 
5
5
  * Support for schema plugins (flash-gordon)
6
6
  * Support for auto migrations (flash-gordon)
7
+ * Add DLS for describing table indexes (flash-gordon)
8
+
9
+ ```ruby
10
+ schema do
11
+ indexes do
12
+ index :name, name: :unique_name, unique: true
13
+ index :props, type: :gin
14
+ index :name, name: :long_names_only, predicate: 'length(name) > 10'
15
+ index :user_id, :title, name: :composite_idx
16
+ end
17
+ end
18
+ ```
19
+
20
+ * Support for composite indexes in the auto-restrictions plugin (flash-gordon)
21
+ * `SQL::Gateway#call` calls a SQL function (flash-gordon)
22
+
23
+ ```ruby
24
+ gateway.(:upper, 'foo') # => "FOO"
25
+ gateway.(:pg_advisory_xact_lock, 1234) # => nil
26
+ ```
27
+
28
+ * `SQL::Gateway#run` executes a SQL string, e.g. a DDL statement (flash-gordon)
29
+
30
+ ```ruby
31
+ gateway.run('set session IntervalStyle to default')
32
+ ```
33
+
34
+ * `SQL::Relation#exists` joins a relation with the `EXISTS` operator (flash-gordon)
35
+
36
+ ```ruby
37
+ users.exists(posts) # => users with posts
38
+ ```
39
+
40
+ * Support for processing a relation in batches (flash-gordon)
41
+
42
+ ```ruby
43
+ users.each_batch(size: 100) do |rel|
44
+ rel.
45
+ command(:update).
46
+ call(name: users[:first_name].concat(users[:last_name])
47
+ end
48
+ ```
49
+
50
+ * `SQL::Relation#import` inserts data from another relation using the `INSERT ... AS SELECT` syntax which is often far more effective than row-by-row processing and an ordinary multi-insert. Relations defined on another gateway are also supported, and in this case, the implementation falls back to the multi-insert strategy (flash-gordon)
51
+
52
+ ```ruby
53
+ users.import(authors.select { first_name.concat(last_name).as(:name) })
54
+ ```
55
+
56
+ * Support for `tinytext`, `text`, `mediumtext`, and `longtext data types in MySQL (panthomakos)
57
+ * The new `pg_explain` plugin for getting query plans on PostgreSQL (flash-gordon)
58
+
59
+ ```ruby
60
+ users.by_pk(1).explain(format: :json, analyze: true)
61
+ ```
62
+
63
+ * Support for window function calls
64
+
65
+ ```ruby
66
+ employees.select { [dep_no, salary, int::avg(salary).over(partition: dep_no, order: id).as(:avg_salary)] }
67
+ ```
68
+
7
69
 
8
70
  ### Changed
9
71
 
10
72
  * [BREAKING] based on rom 4.0 now (flash-gordon + solnic)
11
73
  * [BREAKING] `Associates` command plugin requires associations now (solnic)
12
74
  * [BREAKING] `Command#transaction` is gone in favor of `Relation#transaction` (solnic)
75
+ * [BREAKING] `PG::JSONArray`, `PG::JSONBArray`, `PG::JSONHash`, and `PG::JSONBHash` types were dropped, use `PG::JSON` and `PG::JSONB` instead (flash-gordon)
13
76
  * `ManyToOne` no longer uses a join (solnic)
14
77
  * `AutoCombine` and `AutoWrap` plugins were removed as this functionality is provided by core API (solnic)
78
+ * Foreign keys are indexed by default (flash-gordon)
79
+ * Schemas are qualified by default (solnic)
80
+ * `PG::JSON`, `PG::JSONB`, and `PG::Array` now all have read types so that they return plain Hash/Array values instead of Sequel's wrappers (flash-gordon)
15
81
 
16
82
  ### Fixed
17
83
 
@@ -0,0 +1,54 @@
1
+ module ROM
2
+ module Plugins
3
+ module Relation
4
+ module SQL
5
+ module Postgres
6
+ # @api public
7
+ module Explain
8
+ # Show the execution plan
9
+ # One of four different output formats are supported: plain text, XML, JSON, YAML
10
+ # JSON format will be parsed and unwrapped automatically, plan in other formats
11
+ # will be returned as a plain string.
12
+ # Other options will be transparently added to the statement.
13
+ #
14
+ # @example
15
+ # users.by_pk(1).explain(analyze: true, timing: false) # => Plan output
16
+ #
17
+ # @option :format [Symbol] Plan output format
18
+ #
19
+ # @return [Hash,String]
20
+ #
21
+ # @see https://www.postgresql.org/docs/current/static/sql-explain.html PostgreSQL docs
22
+ #
23
+ # @api public
24
+ def explain(format: :text, **options)
25
+ bool_options = options.map { |opt, value| "#{ opt.to_s.upcase } #{ !!value }" }
26
+ format_option = "FORMAT #{ format.to_s.upcase }"
27
+
28
+ query =
29
+ "EXPLAIN (" <<
30
+ [format_option, *bool_options].join(', ') <<
31
+ ") " <<
32
+ dataset.sql
33
+
34
+ rows = dataset.with_sql(query).map(:'QUERY PLAN')
35
+
36
+ case format
37
+ when :json
38
+ rows[0][0]['Plan']
39
+ else
40
+ rows.join("\n")
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ ROM.plugins do
51
+ adapter :sql do
52
+ register :pg_explain, ROM::Plugins::Relation::SQL::Postgres::Explain, type: :relation
53
+ end
54
+ end
data/lib/rom/sql.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'dry/equalizer'
2
- require 'sequel'
2
+
3
3
  require 'rom/core'
4
4
 
5
5
  require 'rom/sql/version'
@@ -1,7 +1,7 @@
1
1
  require 'sequel/core'
2
2
  require 'dry/core/cache'
3
3
 
4
- require 'rom/schema/attribute'
4
+ require 'rom/attribute'
5
5
 
6
6
  require 'rom/sql/type_extensions'
7
7
  require 'rom/sql/projection_dsl'
@@ -11,10 +11,10 @@ module ROM
11
11
  # Extended schema attributes tailored for SQL databases
12
12
  #
13
13
  # @api public
14
- class Attribute < ROM::Schema::Attribute
14
+ class Attribute < ROM::Attribute
15
15
  OPERATORS = %i[>= <= > <].freeze
16
16
  NONSTANDARD_EQUALITY_VALUES = [true, false, nil].freeze
17
- INDEXED = Set.new([true]).freeze
17
+ META_KEYS = %i(index foreign_key target sql_expr qualified).freeze
18
18
 
19
19
  # Error raised when an attribute cannot be qualified
20
20
  QualifyError = Class.new(StandardError)
@@ -61,10 +61,10 @@ module ROM
61
61
  #
62
62
  # @api public
63
63
  def qualified(table_alias = nil)
64
- return self if qualified?
64
+ return self if qualified? && table_alias.nil?
65
65
 
66
66
  case sql_expr
67
- when Sequel::SQL::AliasedExpression, Sequel::SQL::Identifier
67
+ when Sequel::SQL::AliasedExpression, Sequel::SQL::Identifier, Sequel::SQL::QualifiedIdentifier
68
68
  type = meta(qualified: table_alias || true)
69
69
  type.meta(sql_expr: type.to_sql_name)
70
70
  else
@@ -287,32 +287,31 @@ module ROM
287
287
 
288
288
  # @api public
289
289
  def indexed?
290
- !indexes.empty?
290
+ meta[:index].equal?(true)
291
291
  end
292
292
 
293
+ # Returns a new attribute marked as indexed
294
+ #
293
295
  # @api public
294
- def indexes
295
- if meta[:index] == true
296
- INDEXED
297
- else
298
- meta[:index] || EMPTY_SET
299
- end
296
+ def indexed
297
+ meta(index: true)
300
298
  end
301
299
 
302
300
  # @api private
303
301
  def meta_ast
304
302
  meta = super
305
- meta[:index] = indexes if indexed?
303
+ meta[:index] = true if indexed?
306
304
  meta
307
305
  end
308
306
 
307
+ # Removes metadata from the type
308
+ #
309
309
  # @api private
310
310
  def unwrap
311
- if optional?
312
- self.class.new(right, options).meta(meta)
313
- else
314
- self
315
- end
311
+ cleaned_meta = meta.reject { |k, _| META_KEYS.include?(k) }
312
+ type = optional? ? right : self.type
313
+
314
+ self.class.new(type.with(meta: cleaned_meta), options)
316
315
  end
317
316
 
318
317
  private
@@ -1,3 +1,6 @@
1
+ require 'sequel/deprecated'
2
+ require 'sequel/exceptions'
3
+
1
4
  require 'rom/sql/error'
2
5
 
3
6
  module ROM
@@ -1 +1 @@
1
- require 'rom/sql/extensions/mysql/attributes_inferrer'
1
+ require 'rom/sql/extensions/mysql/type_builder'
@@ -0,0 +1,28 @@
1
+ require 'rom/sql/schema/attributes_inferrer'
2
+
3
+ module ROM
4
+ module SQL
5
+ module MySQL
6
+ class TypeBuilder < Schema::TypeBuilder
7
+ defines :db_type_mapping
8
+
9
+ db_type_mapping(
10
+ 'tinytext' => Types::String,
11
+ 'text' => Types::String,
12
+ 'mediumtext' => Types::String,
13
+ 'longtext' => Types::String
14
+ ).freeze
15
+
16
+ def map_type(ruby_type, db_type, **_)
17
+ map_db_type(db_type) || super
18
+ end
19
+
20
+ def map_db_type(db_type)
21
+ self.class.db_type_mapping[db_type]
22
+ end
23
+ end
24
+ end
25
+
26
+ Schema::TypeBuilder.register(:mysql, MySQL::TypeBuilder.new.freeze)
27
+ end
28
+ end
@@ -1,3 +1,5 @@
1
1
  require 'rom/sql/extensions/postgres/commands'
2
2
  require 'rom/sql/extensions/postgres/types'
3
- require 'rom/sql/extensions/postgres/attributes_inferrer'
3
+ require 'rom/sql/extensions/postgres/type_builder'
4
+ require 'rom/sql/extensions/postgres/type_serializer'
5
+ require 'rom/plugins/relation/sql/postgres/explain'
@@ -3,8 +3,8 @@ require 'rom/sql/commands/update'
3
3
 
4
4
  module ROM
5
5
  module SQL
6
- module Commands
7
- module Postgres
6
+ module Postgres
7
+ module Commands
8
8
  module Create
9
9
  # Executes insert statement and returns inserted tuples
10
10
  #
@@ -45,21 +45,19 @@ module ROM
45
45
 
46
46
  # Upsert command
47
47
  #
48
- # Uses a feature of PostgreSQL 9.5 commonly called an "upsert".
49
- # The command been called attempts to perform an insert and
50
- # can make an update (or silently do nothing) in case of
51
- # the insertion was unsuccessful due to a violation of a unique
52
- # constraint.
53
- # Very important implementation detail is that the whole operation
54
- # is atomic, i.e. aware of concurrent transactions, and doesn't raise
55
- # exceptions if used properly.
48
+ # The command beign called attempts to insert a record and
49
+ # if the inserted row would violate a unique constraint
50
+ # updates the conflicting row (or silently does nothing).
51
+ # A very important implementation detail is that the whole operation
52
+ # is serializable, i.e. aware of concurrent transactions, and doesn't raise
53
+ # exceptions and doesn't issue missing updates once used properly.
56
54
  #
57
55
  # See PG's docs in INSERT statement for details
58
56
  # https://www.postgresql.org/docs/current/static/sql-insert.html
59
57
  #
60
- # Normally, the command should configured via class level settings.
61
- # By default, that is without any settings provided, the command
62
- # uses ON CONFLICT DO NOTHING clause.
58
+ # Normally, the command should be configured via class level settings.
59
+ # By default, that is without any setting provided, the command
60
+ # uses the ON CONFLICT DO NOTHING clause.
63
61
  #
64
62
  # This implementation uses Sequel's API underneath, the docs are available at
65
63
  # http://sequel.jeremyevans.net/rdoc-adapters/classes/Sequel/Postgres/DatasetMethods.html#method-i-insert_conflict
@@ -113,5 +111,24 @@ module ROM
113
111
  end
114
112
  end
115
113
  end
114
+
115
+ Commands::Postgres = Postgres::Commands
116
+
117
+ Gateway.subscribe('configuration.commands.class.before_build') do |event|
118
+ klass = event[:command]
119
+ dataset = event[:dataset]
120
+ type = dataset.db.database_type
121
+
122
+ if type == :postgres
123
+ ext =
124
+ if klass < Commands::Create
125
+ Postgres::Commands::Create
126
+ elsif klass < Commands::Update
127
+ Postgres::Commands::Update
128
+ end
129
+
130
+ klass.include(ext) if ext
131
+ end
132
+ end
116
133
  end
117
134
  end
@@ -1,11 +1,7 @@
1
- require 'set'
2
- require 'rom/sql/schema/attributes_inferrer'
3
- require 'rom/sql/extensions/postgres/types'
4
-
5
1
  module ROM
6
2
  module SQL
7
- class Schema
8
- class PostgresInferrer < AttributesInferrer[:postgres]
3
+ module Postgres
4
+ class TypeBuilder < Schema::TypeBuilder
9
5
  defines :db_numeric_types, :db_type_mapping, :db_array_type_matcher
10
6
 
11
7
  db_numeric_types %w(
@@ -15,29 +11,27 @@ module ROM
15
11
  ).to_set.freeze
16
12
 
17
13
  db_type_mapping(
18
- 'uuid' => Types::PG::UUID,
19
- 'money' => Types::PG::Money,
20
- 'bytea' => Types::Blob,
21
- 'json' => Types::PG::JSON,
22
- 'jsonb' => Types::PG::JSONB,
23
- 'inet' => Types::PG::IPAddress,
24
- 'cidr' => Types::PG::IPAddress,
25
- 'macaddr' => Types::String,
26
- 'point' => Types::PG::PointT,
27
- 'xml' => Types::String,
28
- 'hstore' => Types::PG::HStore,
29
- 'line' => Types::PG::LineT,
30
- 'circle' => Types::PG::CircleT,
31
- 'box' => Types::PG::BoxT,
32
- 'lseg' => Types::PG::LineSegmentT,
33
- 'polygon' => Types::PG::PolygonT,
34
- 'path' => Types::PG::PathT
14
+ 'uuid' => Types::UUID,
15
+ 'money' => Types::Money,
16
+ 'bytea' => Types::Bytea,
17
+ 'json' => Types::JSON,
18
+ 'jsonb' => Types::JSONB,
19
+ 'xml' => Types::XML,
20
+ 'inet' => Types::IPAddress,
21
+ 'cidr' => Types::IPAddress,
22
+ 'macaddr' => SQL::Types::String,
23
+ 'point' => Types::Point,
24
+ 'hstore' => Types::HStore,
25
+ 'line' => Types::Line,
26
+ 'circle' => Types::Circle,
27
+ 'box' => Types::Box,
28
+ 'lseg' => Types::LineSegment,
29
+ 'polygon' => Types::Polygon,
30
+ 'path' => Types::Path
35
31
  ).freeze
36
32
 
37
33
  db_array_type_matcher '[]'.freeze
38
34
 
39
- private
40
-
41
35
  def map_pk_type(type, db_type)
42
36
  if numeric?(type, db_type)
43
37
  type = self.class.numeric_pk_type
@@ -50,9 +44,9 @@ module ROM
50
44
 
51
45
  def map_type(ruby_type, db_type, enum_values: nil, **_)
52
46
  if db_type.end_with?(self.class.db_array_type_matcher)
53
- Types::PG::Array(db_type)
47
+ Types::Array(db_type[0...-2])
54
48
  elsif enum_values
55
- Types::String.enum(*enum_values)
49
+ SQL::Types::String.enum(*enum_values)
56
50
  else
57
51
  map_db_type(db_type) || super
58
52
  end
@@ -60,7 +54,7 @@ module ROM
60
54
 
61
55
  def map_db_type(db_type)
62
56
  self.class.db_type_mapping[db_type] ||
63
- (db_type.start_with?('timestamp') ? Types::Time : nil)
57
+ (db_type.start_with?('timestamp') ? SQL::Types::Time : nil)
64
58
  end
65
59
 
66
60
  def numeric?(ruby_type, db_type)
@@ -68,5 +62,7 @@ module ROM
68
62
  end
69
63
  end
70
64
  end
65
+
66
+ Schema::TypeBuilder.register(:postgres, Postgres::TypeBuilder.new.freeze)
71
67
  end
72
68
  end
@@ -0,0 +1,39 @@
1
+ module ROM
2
+ module SQL
3
+ module Postgres
4
+ # @api private
5
+ class TypeSerializer < ROM::SQL::TypeSerializer
6
+ mapping(
7
+ mapping.merge(
8
+ SQL::Types::String => 'text',
9
+ Types::UUID => 'uuid',
10
+ Types::XML => 'xml',
11
+ Types::Money => 'money',
12
+ Types::Bytea => 'bytea',
13
+ Types::JSON => 'json',
14
+ Types::JSONB => 'jsonb',
15
+ Types::HStore => 'hstore',
16
+ Types::IPAddress => 'inet',
17
+ Types::Point => 'point',
18
+ Types::Line => 'line',
19
+ Types::Circle => 'circle',
20
+ Types::Box => 'box',
21
+ Types::LineSegment => 'lseg',
22
+ Types::Polygon => 'polygon',
23
+ Types::Path => 'path'
24
+ )
25
+ )
26
+
27
+ def call(type)
28
+ super do
29
+ if type.respond_to?(:primitive) && type.primitive.equal?(Array)
30
+ "#{ type.meta[:type] }[]"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ TypeSerializer.register(:postgres, Postgres::TypeSerializer.new.freeze)
38
+ end
39
+ end