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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +66 -0
- data/lib/rom/plugins/relation/sql/postgres/explain.rb +54 -0
- data/lib/rom/sql.rb +1 -1
- data/lib/rom/sql/attribute.rb +17 -18
- data/lib/rom/sql/errors.rb +3 -0
- data/lib/rom/sql/extensions/mysql.rb +1 -1
- data/lib/rom/sql/extensions/mysql/type_builder.rb +28 -0
- data/lib/rom/sql/extensions/postgres.rb +3 -1
- data/lib/rom/sql/extensions/postgres/commands.rb +30 -13
- data/lib/rom/sql/extensions/postgres/{attributes_inferrer.rb → type_builder.rb} +24 -28
- data/lib/rom/sql/extensions/postgres/type_serializer.rb +39 -0
- data/lib/rom/sql/extensions/postgres/types.rb +24 -477
- data/lib/rom/sql/extensions/postgres/types/array.rb +163 -0
- data/lib/rom/sql/extensions/postgres/types/geometric.rb +135 -0
- data/lib/rom/sql/extensions/postgres/types/json.rb +235 -0
- data/lib/rom/sql/extensions/postgres/types/network.rb +15 -0
- data/lib/rom/sql/extensions/sqlite.rb +1 -1
- data/lib/rom/sql/extensions/sqlite/{attributes_inferrer.rb → type_builder.rb} +5 -5
- data/lib/rom/sql/extensions/sqlite/types.rb +8 -3
- data/lib/rom/sql/foreign_key.rb +17 -0
- data/lib/rom/sql/function.rb +86 -8
- data/lib/rom/sql/gateway.rb +26 -26
- data/lib/rom/sql/index.rb +4 -0
- data/lib/rom/sql/migration.rb +3 -3
- data/lib/rom/sql/migration/inline_runner.rb +9 -83
- data/lib/rom/sql/migration/migrator.rb +35 -12
- data/lib/rom/sql/migration/recorder.rb +21 -0
- data/lib/rom/sql/migration/runner.rb +115 -0
- data/lib/rom/sql/migration/schema_diff.rb +108 -53
- data/lib/rom/sql/migration/writer.rb +61 -0
- data/lib/rom/sql/relation.rb +2 -1
- data/lib/rom/sql/relation/reading.rb +63 -3
- data/lib/rom/sql/relation/writing.rb +38 -0
- data/lib/rom/sql/schema.rb +9 -3
- data/lib/rom/sql/schema/attributes_inferrer.rb +3 -119
- data/lib/rom/sql/schema/inferrer.rb +99 -18
- data/lib/rom/sql/schema/type_builder.rb +94 -0
- data/lib/rom/sql/type_dsl.rb +30 -0
- data/lib/rom/sql/type_extensions.rb +11 -6
- data/lib/rom/sql/type_serializer.rb +46 -0
- data/lib/rom/sql/types.rb +12 -0
- data/lib/rom/sql/version.rb +1 -1
- metadata +26 -244
- data/.codeclimate.yml +0 -15
- data/.gitignore +0 -17
- data/.rspec +0 -3
- data/.travis.yml +0 -39
- data/.yardopts +0 -2
- data/Gemfile +0 -33
- data/Guardfile +0 -24
- data/LICENSE.txt +0 -22
- data/Rakefile +0 -19
- data/circle.yml +0 -10
- data/lib/rom/sql/extensions/mysql/attributes_inferrer.rb +0 -10
- data/lib/rom/sql/relation/sequel_api.rb +0 -133
- data/log/.gitkeep +0 -0
- data/rom-sql.gemspec +0 -29
- data/spec/extensions/postgres/attribute_spec.rb +0 -217
- data/spec/extensions/postgres/integration_spec.rb +0 -59
- data/spec/extensions/postgres/types_spec.rb +0 -252
- data/spec/extensions/sqlite/types_spec.rb +0 -11
- data/spec/fixtures/migrations/20150403090603_create_carrots.rb +0 -8
- data/spec/integration/associations/many_to_many/custom_fks_spec.rb +0 -76
- data/spec/integration/associations/many_to_many/from_view_spec.rb +0 -88
- data/spec/integration/associations/many_to_many_spec.rb +0 -162
- data/spec/integration/associations/many_to_one/custom_fks_spec.rb +0 -64
- data/spec/integration/associations/many_to_one/from_view_spec.rb +0 -84
- data/spec/integration/associations/many_to_one/self_ref_spec.rb +0 -53
- data/spec/integration/associations/many_to_one_spec.rb +0 -117
- data/spec/integration/associations/one_to_many/custom_fks_spec.rb +0 -54
- data/spec/integration/associations/one_to_many/from_view_spec.rb +0 -57
- data/spec/integration/associations/one_to_many/self_ref_spec.rb +0 -54
- data/spec/integration/associations/one_to_many_spec.rb +0 -86
- data/spec/integration/associations/one_to_one_spec.rb +0 -69
- data/spec/integration/associations/one_to_one_through_spec.rb +0 -92
- data/spec/integration/auto_migrations/errors_spec.rb +0 -31
- data/spec/integration/auto_migrations/indexes_spec.rb +0 -253
- data/spec/integration/auto_migrations/managing_columns_spec.rb +0 -156
- data/spec/integration/auto_migrations/postgres/column_types_spec.rb +0 -63
- data/spec/integration/combine_with_spec.rb +0 -43
- data/spec/integration/commands/create_spec.rb +0 -304
- data/spec/integration/commands/delete_spec.rb +0 -84
- data/spec/integration/commands/update_spec.rb +0 -90
- data/spec/integration/commands/upsert_spec.rb +0 -83
- data/spec/integration/gateway_spec.rb +0 -107
- data/spec/integration/migration_spec.rb +0 -55
- data/spec/integration/plugins/associates/many_to_many_spec.rb +0 -69
- data/spec/integration/plugins/associates_spec.rb +0 -250
- data/spec/integration/plugins/auto_restrictions_spec.rb +0 -74
- data/spec/integration/relation_schema_spec.rb +0 -271
- data/spec/integration/schema/call_spec.rb +0 -24
- data/spec/integration/schema/inferrer/mysql_spec.rb +0 -45
- data/spec/integration/schema/inferrer/postgres_spec.rb +0 -203
- data/spec/integration/schema/inferrer/sqlite_spec.rb +0 -37
- data/spec/integration/schema/inferrer_spec.rb +0 -390
- data/spec/integration/schema/prefix_spec.rb +0 -16
- data/spec/integration/schema/qualified_spec.rb +0 -16
- data/spec/integration/schema/rename_spec.rb +0 -21
- data/spec/integration/schema/view_spec.rb +0 -29
- data/spec/integration/sequel_api_spec.rb +0 -36
- data/spec/integration/setup_spec.rb +0 -26
- data/spec/integration/support/active_support_notifications_spec.rb +0 -24
- data/spec/integration/support/rails_log_subscriber_spec.rb +0 -30
- data/spec/integration/wrap_spec.rb +0 -91
- data/spec/shared/accounts.rb +0 -48
- data/spec/shared/database_setup.rb +0 -70
- data/spec/shared/notes.rb +0 -23
- data/spec/shared/posts.rb +0 -34
- data/spec/shared/puppies.rb +0 -15
- data/spec/shared/relations.rb +0 -8
- data/spec/shared/users.rb +0 -32
- data/spec/shared/users_and_tasks.rb +0 -50
- data/spec/spec_helper.rb +0 -122
- data/spec/support/env_helper.rb +0 -25
- data/spec/support/helpers.rb +0 -24
- data/spec/support/oracle/create_users.sql +0 -7
- data/spec/support/oracle/set_sys_passwords.sql +0 -2
- data/spec/support/test_configuration.rb +0 -16
- data/spec/unit/attribute_spec.rb +0 -104
- data/spec/unit/function_spec.rb +0 -48
- data/spec/unit/gateway_spec.rb +0 -70
- data/spec/unit/logger_spec.rb +0 -14
- data/spec/unit/migration_tasks_spec.rb +0 -111
- data/spec/unit/migrator_spec.rb +0 -25
- data/spec/unit/order_dsl_spec.rb +0 -43
- data/spec/unit/plugin/associates_spec.rb +0 -94
- data/spec/unit/plugin/pagination_spec.rb +0 -91
- data/spec/unit/plugin/timestamp_spec.rb +0 -117
- data/spec/unit/projection_dsl_spec.rb +0 -110
- data/spec/unit/relation/assoc_spec.rb +0 -87
- data/spec/unit/relation/associations_spec.rb +0 -27
- data/spec/unit/relation/avg_spec.rb +0 -11
- data/spec/unit/relation/by_pk_spec.rb +0 -62
- data/spec/unit/relation/dataset_spec.rb +0 -50
- data/spec/unit/relation/distinct_spec.rb +0 -15
- data/spec/unit/relation/exclude_spec.rb +0 -11
- data/spec/unit/relation/exist_predicate_spec.rb +0 -25
- data/spec/unit/relation/exists_spec.rb +0 -18
- data/spec/unit/relation/fetch_spec.rb +0 -21
- data/spec/unit/relation/group_spec.rb +0 -61
- data/spec/unit/relation/having_spec.rb +0 -22
- data/spec/unit/relation/inner_join_spec.rb +0 -158
- data/spec/unit/relation/inspect_spec.rb +0 -11
- data/spec/unit/relation/instrument_spec.rb +0 -45
- data/spec/unit/relation/invert_spec.rb +0 -11
- data/spec/unit/relation/left_join_spec.rb +0 -55
- data/spec/unit/relation/lock_spec.rb +0 -93
- data/spec/unit/relation/map_spec.rb +0 -16
- data/spec/unit/relation/max_spec.rb +0 -11
- data/spec/unit/relation/min_spec.rb +0 -11
- data/spec/unit/relation/order_spec.rb +0 -51
- data/spec/unit/relation/pluck_spec.rb +0 -11
- data/spec/unit/relation/prefix_spec.rb +0 -29
- data/spec/unit/relation/primary_key_spec.rb +0 -27
- data/spec/unit/relation/project_spec.rb +0 -24
- data/spec/unit/relation/qualified_columns_spec.rb +0 -30
- data/spec/unit/relation/qualified_spec.rb +0 -25
- data/spec/unit/relation/read_spec.rb +0 -25
- data/spec/unit/relation/rename_spec.rb +0 -23
- data/spec/unit/relation/right_join_spec.rb +0 -57
- data/spec/unit/relation/select_append_spec.rb +0 -21
- data/spec/unit/relation/select_spec.rb +0 -40
- data/spec/unit/relation/sum_spec.rb +0 -11
- data/spec/unit/relation/union_spec.rb +0 -19
- data/spec/unit/relation/unique_predicate_spec.rb +0 -18
- data/spec/unit/relation/where_spec.rb +0 -133
- data/spec/unit/restriction_dsl_spec.rb +0 -34
- data/spec/unit/schema_spec.rb +0 -25
- data/spec/unit/types_spec.rb +0 -65
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3c40812f8e5e3a90dbb8a24608845b06a69f2e7c
|
4
|
+
data.tar.gz: 0675140e980842b9bfe70aae46826b7e1c4ccb4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
data/lib/rom/sql/attribute.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'sequel/core'
|
2
2
|
require 'dry/core/cache'
|
3
3
|
|
4
|
-
require 'rom/
|
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::
|
14
|
+
class Attribute < ROM::Attribute
|
15
15
|
OPERATORS = %i[>= <= > <].freeze
|
16
16
|
NONSTANDARD_EQUALITY_VALUES = [true, false, nil].freeze
|
17
|
-
|
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
|
-
|
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
|
295
|
-
|
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] =
|
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
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
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
|
data/lib/rom/sql/errors.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require 'rom/sql/extensions/mysql/
|
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/
|
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
|
7
|
-
module
|
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
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
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
|
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
|
-
|
8
|
-
class
|
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::
|
19
|
-
'money' => Types::
|
20
|
-
'bytea' => Types::
|
21
|
-
'json' => Types::
|
22
|
-
'jsonb' => Types::
|
23
|
-
'
|
24
|
-
'
|
25
|
-
'
|
26
|
-
'
|
27
|
-
'
|
28
|
-
'hstore' => Types::
|
29
|
-
'line' => Types::
|
30
|
-
'circle' => Types::
|
31
|
-
'box' => Types::
|
32
|
-
'lseg' => Types::
|
33
|
-
'polygon' => Types::
|
34
|
-
'path' => Types::
|
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::
|
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
|