rom-sql 2.0.0.beta2 → 2.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
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