rom-sql 0.8.0 → 0.9.0

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +16 -12
  3. data/CHANGELOG.md +23 -0
  4. data/Gemfile +11 -3
  5. data/README.md +1 -7
  6. data/lib/rom/sql.rb +4 -7
  7. data/lib/rom/sql/association.rb +1 -1
  8. data/lib/rom/sql/association/one_to_many.rb +44 -1
  9. data/lib/rom/sql/association/one_to_one.rb +1 -38
  10. data/lib/rom/sql/commands.rb +0 -3
  11. data/lib/rom/sql/commands/error_wrapper.rb +1 -1
  12. data/lib/rom/sql/errors.rb +4 -1
  13. data/lib/rom/sql/extensions.rb +19 -0
  14. data/lib/rom/sql/{support → extensions}/active_support_notifications.rb +0 -0
  15. data/lib/rom/sql/extensions/postgres.rb +3 -0
  16. data/lib/rom/sql/{commands/postgres.rb → extensions/postgres/commands.rb} +38 -0
  17. data/lib/rom/sql/extensions/postgres/inferrer.rb +64 -0
  18. data/lib/rom/sql/extensions/postgres/types.rb +65 -0
  19. data/lib/rom/sql/{support → extensions}/rails_log_subscriber.rb +0 -0
  20. data/lib/rom/sql/gateway.rb +15 -4
  21. data/lib/rom/sql/relation.rb +6 -2
  22. data/lib/rom/sql/relation/reading.rb +18 -0
  23. data/lib/rom/sql/schema/dsl.rb +7 -4
  24. data/lib/rom/sql/schema/inferrer.rb +44 -31
  25. data/lib/rom/sql/types.rb +5 -1
  26. data/lib/rom/sql/version.rb +1 -1
  27. data/rom-sql.gemspec +14 -13
  28. data/spec/extensions/postgres/inferrer_spec.rb +40 -0
  29. data/spec/extensions/postgres/integration_spec.rb +38 -0
  30. data/spec/extensions/postgres/types_spec.rb +115 -0
  31. data/spec/integration/association/many_to_many_spec.rb +2 -1
  32. data/spec/integration/association/one_to_one_spec.rb +6 -4
  33. data/spec/integration/combine_spec.rb +1 -1
  34. data/spec/integration/commands/create_spec.rb +46 -21
  35. data/spec/integration/commands/delete_spec.rb +13 -38
  36. data/spec/integration/commands/update_spec.rb +19 -41
  37. data/spec/integration/commands/upsert_spec.rb +1 -1
  38. data/spec/integration/gateway_spec.rb +5 -9
  39. data/spec/integration/migration_spec.rb +6 -7
  40. data/spec/integration/read_spec.rb +30 -38
  41. data/spec/integration/schema_inference_spec.rb +211 -49
  42. data/spec/integration/setup_spec.rb +5 -5
  43. data/spec/integration/support/active_support_notifications_spec.rb +4 -3
  44. data/spec/integration/support/rails_log_subscriber_spec.rb +5 -4
  45. data/spec/shared/database_setup.rb +21 -6
  46. data/spec/spec_helper.rb +44 -35
  47. data/spec/unit/association/one_to_many_spec.rb +20 -0
  48. data/spec/unit/association/one_to_one_spec.rb +23 -2
  49. data/spec/unit/association_errors_spec.rb +1 -1
  50. data/spec/unit/gateway_spec.rb +9 -8
  51. data/spec/unit/logger_spec.rb +1 -1
  52. data/spec/unit/migration_tasks_spec.rb +3 -3
  53. data/spec/unit/migrator_spec.rb +3 -2
  54. data/spec/unit/plugin/assoc_macros/combined_associations_spec.rb +1 -1
  55. data/spec/unit/plugin/assoc_macros/many_to_many_spec.rb +1 -1
  56. data/spec/unit/plugin/assoc_macros/many_to_one_spec.rb +1 -1
  57. data/spec/unit/plugin/assoc_macros/one_to_many_spec.rb +1 -1
  58. data/spec/unit/relation/associations_spec.rb +27 -0
  59. data/spec/unit/relation/avg_spec.rb +11 -0
  60. data/spec/unit/relation/by_pk_spec.rb +15 -0
  61. data/spec/unit/relation/dataset_spec.rb +48 -0
  62. data/spec/unit/relation/distinct_spec.rb +14 -0
  63. data/spec/unit/relation/exclude_spec.rb +13 -0
  64. data/spec/unit/relation/fetch_spec.rb +21 -0
  65. data/spec/unit/relation/having_spec.rb +20 -0
  66. data/spec/unit/relation/inner_join_spec.rb +22 -0
  67. data/spec/unit/relation/inspect_spec.rb +11 -0
  68. data/spec/unit/relation/invert_spec.rb +12 -0
  69. data/spec/unit/relation/left_join_spec.rb +16 -0
  70. data/spec/unit/relation/map_spec.rb +16 -0
  71. data/spec/unit/relation/max_spec.rb +11 -0
  72. data/spec/unit/relation/min_spec.rb +11 -0
  73. data/spec/unit/relation/pluck_spec.rb +11 -0
  74. data/spec/unit/relation/prefix_spec.rb +27 -0
  75. data/spec/unit/relation/primary_key_spec.rb +27 -0
  76. data/spec/unit/relation/project_spec.rb +22 -0
  77. data/spec/unit/relation/qualified_columns_spec.rb +27 -0
  78. data/spec/unit/relation/rename_spec.rb +21 -0
  79. data/spec/unit/relation/sum_spec.rb +11 -0
  80. data/spec/unit/relation/union_spec.rb +19 -0
  81. data/spec/unit/relation/unique_predicate_spec.rb +18 -0
  82. data/spec/unit/schema_spec.rb +1 -1
  83. data/spec/unit/types_spec.rb +4 -21
  84. metadata +79 -11
  85. data/lib/rom/sql/commands_ext/postgres.rb +0 -45
  86. data/lib/rom/sql/types/pg.rb +0 -26
  87. data/spec/unit/relation_spec.rb +0 -272
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5da70a1471f9c0b3a27f10cacf6af54f060090be
4
- data.tar.gz: 1f391fdbd269bbf0df9d0af23a5fc112948ce1f2
3
+ metadata.gz: 4fdb75ab8064473be4552789976b049b939ed356
4
+ data.tar.gz: 3c2cc1dd4f7ee9428f6a2f45a2ecc1368c6e5882
5
5
  SHA512:
6
- metadata.gz: f91c5854d45dc52b26ddb0eaca6dc465ff02db69bd145d6ce010c6eaa93571ac46842d68a6897e0b88fffb7639efe26c94435a035c0d4a0790be37defd846fa2
7
- data.tar.gz: 879cf6a660eb79ab84b1adbfb33ede96613d786356457182d81bc3f00f2a7165fbe939d25b7bd0755242710469cffae650976252c9c19eeda37067a89a0407ec
6
+ metadata.gz: a96f739270f64f4828b7d777d949b6b20bfd7161c6a19813347d1f0fdbdbe4f125c387195ab01dc184fbac06ab3faf83cfda76e608f212937336529663fd4d87
7
+ data.tar.gz: af5dbaba037a0ef816b32af01ba4b2c504eaf6310463d244b38e79304b8b4face04137857b9c12f9b30c87c73cb044e369153a0e6b8322f9d5949b0ef689cc91
data/.travis.yml CHANGED
@@ -1,5 +1,6 @@
1
1
  language: ruby
2
- sudo: false
2
+ dist: trusty
3
+ sudo: required
3
4
  cache: bundler
4
5
  services:
5
6
  - postgresql
@@ -7,27 +8,23 @@ services:
7
8
  bundler_args: --without yard guard benchmarks tools
8
9
  before_script:
9
10
  - psql -c 'create database rom_sql;' -U postgres
10
- - mysql -e 'create database rom_sql;'
11
+ - mysql -u root -e 'create database rom_sql;'
12
+ after_success:
13
+ - '[ "$TRAVIS_RUBY_VERSION" = "2.3.1" ] && [ "$TRAVIS_BRANCH" = "master" ] && bundle exec codeclimate-test-reporter'
11
14
  script: "bundle exec rake ci"
12
15
  rvm:
13
- - 2.1.9
16
+ - 2.1.10
14
17
  - 2.2.5
15
18
  - 2.3.1
16
- - rbx-2
17
- - jruby-9.0.5.0
18
- - ruby-head
19
+ - rbx-3
20
+ - jruby
19
21
  env:
20
22
  global:
21
23
  - CODECLIMATE_REPO_TOKEN=03d7f66589572702b12426d2bc71c4de6281a96139e33b335b894264b1f8f0b0
22
24
  - JRUBY_OPTS='--dev -J-Xmx1024M'
23
- - PG_LTE_95='false'
24
25
  matrix:
25
26
  allow_failures:
26
- - rvm: ruby-head
27
- - rvm: jruby-head
28
- include:
29
- - rvm: jruby-head
30
- before_install: gem install bundler --no-ri --no-rdoc
27
+ - rvm: rbx
31
28
  notifications:
32
29
  webhooks:
33
30
  urls:
@@ -35,3 +32,10 @@ notifications:
35
32
  on_success: change
36
33
  on_failure: always
37
34
  on_start: false
35
+ addons:
36
+ postgresql: 9.5
37
+ apt:
38
+ packages:
39
+ - mysql-server-5.6
40
+ - mysql-client-core-5.6
41
+ - mysql-client-5.6
data/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ ## v0.9.0 2016-11-08
2
+
3
+ ### Added
4
+
5
+ * `Associations::{OneToMany,OneToOne}#associate` for merging FKs into child tuple (jodosha)
6
+ * Added support for PostgreSQL types: UUID, Array, JSONB and Money (jodosha)
7
+ * Support for DB specific schema inferrers (flash-gordon)
8
+ * Automatically infer PG arrays and JSON(B) types (jodosha + flash-gordon)
9
+ * Support for `Relation#having` (cflipse)
10
+
11
+ ### Changed
12
+
13
+ * Inferred types in schemas **are no longer strict** (flash-gordon)
14
+ * PG-specific types are handled by `:postgres` extension and it loads connection extensions automatically (flash-gordon)
15
+ * Make `OneToOne` inherit from `OneToMany` (beauby)
16
+ * Default dataset will use column names from schema if it's available (solnic)
17
+
18
+ ### Fixed
19
+
20
+ * Floats are inferred by schemas (cflipse)
21
+
22
+ [Compare v0.8.0...v0.9.0](https://github.com/rom-rb/rom-sql/compare/v0.8.0...v0.9.0)
23
+
1
24
  ## v0.8.0 2016-07-27
2
25
 
3
26
  ### Added
data/Gemfile CHANGED
@@ -2,14 +2,22 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
+ gem 'rom', github: 'rom-rb/rom', branch: 'master'
6
+
5
7
  group :test do
6
8
  gem 'byebug', platforms: :mri
7
- gem 'anima', '~> 0.2.0'
8
- gem 'virtus'
9
+ gem 'dry-struct'
9
10
  gem 'activesupport', '~> 4.2'
10
11
  gem 'rspec', '~> 3.1'
11
12
  gem 'codeclimate-test-reporter', require: false
12
- gem 'pg', platforms: [:mri, :rbx]
13
+ gem 'simplecov', require: false
14
+
15
+ if RUBY_ENGINE == 'rbx'
16
+ gem 'pg', '~> 0.18.0', platforms: :rbx
17
+ else
18
+ gem 'pg', '~> 0.19', platforms: :mri
19
+ end
20
+
13
21
  gem 'mysql2', platforms: [:mri, :rbx]
14
22
  gem 'jdbc-postgres', platforms: :jruby
15
23
  gem 'jdbc-mysql', platforms: :jruby
data/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  [![Test Coverage](https://codeclimate.com/github/rom-rb/rom-sql/badges/coverage.svg)][codeclimate]
14
14
  [![Inline docs](http://inch-ci.org/github/rom-rb/rom-sql.svg?branch=master)][inchpages]
15
15
 
16
- RDBMS support for [Ruby Object Mapper](https://github.com/rom-rb/rom).
16
+ SQL support for [rom-rb](https://github.com/rom-rb/rom).
17
17
 
18
18
  Resources:
19
19
 
@@ -36,12 +36,6 @@ Or install it yourself as:
36
36
 
37
37
  $ gem install rom-sql
38
38
 
39
- Check out [SQL guide](http://rom-rb.org/learn/adapters/sql/) for usage examples.
40
-
41
- ## ROADMAP
42
-
43
- For details please refer to [issues](https://github.com/rom-rb/rom-sql/issues).
44
-
45
39
  ## License
46
40
 
47
41
  See `LICENSE` file.
data/lib/rom/sql.rb CHANGED
@@ -2,22 +2,19 @@ require 'dry-equalizer'
2
2
  require 'sequel'
3
3
  require 'rom'
4
4
 
5
- module ROM
6
- MissingConfigurationError = Class.new(StandardError)
7
- end
5
+ require 'rom/sql/version'
6
+ require 'rom/sql/errors'
8
7
 
9
8
  require 'rom/configuration_dsl'
10
9
 
11
- require 'rom/sql/version'
12
- require 'rom/sql/errors'
13
10
  require 'rom/sql/plugins'
14
11
  require 'rom/sql/relation'
15
12
  require 'rom/sql/gateway'
16
13
  require 'rom/sql/migration'
14
+ require 'rom/sql/extensions'
17
15
 
18
16
  if defined?(Rails)
19
- require 'rom/sql/support/active_support_notifications'
20
- require 'rom/sql/support/rails_log_subscriber'
17
+ ROM::SQL.load_extensions(:active_support_notifications, :rails_log_subscriber)
21
18
  end
22
19
 
23
20
  ROM.register_adapter(:sql, ROM::SQL)
@@ -68,8 +68,8 @@ module ROM
68
68
  end
69
69
  end
70
70
 
71
- require 'rom/sql/association/one_to_one'
72
71
  require 'rom/sql/association/one_to_many'
72
+ require 'rom/sql/association/one_to_one'
73
73
  require 'rom/sql/association/many_to_many'
74
74
  require 'rom/sql/association/many_to_one'
75
75
  require 'rom/sql/association/one_to_one_through'
@@ -1,8 +1,51 @@
1
1
  module ROM
2
2
  module SQL
3
3
  class Association
4
- class OneToMany < OneToOne
4
+ class OneToMany < Association
5
5
  result :many
6
+
7
+ # @api public
8
+ def call(relations)
9
+ with_keys(relations) do |left_pk, right_fk|
10
+ right = relations[target.relation]
11
+ columns = right.header.qualified.to_a
12
+
13
+ relation = right
14
+ .inner_join(source, left_pk => right_fk)
15
+ .select(*columns)
16
+ .order(*right.header.project(*right.primary_key).qualified)
17
+
18
+ relation.with(attributes: relation.header.names)
19
+ end
20
+ end
21
+
22
+ # @api public
23
+ def combine_keys(relations)
24
+ Hash[*with_keys(relations)]
25
+ end
26
+
27
+ # @api public
28
+ def join_keys(relations)
29
+ with_keys(relations) { |source_key, target_key|
30
+ { qualify(source, source_key) => qualify(target, target_key) }
31
+ }
32
+ end
33
+
34
+ # @api private
35
+ def associate(relations, child, parent)
36
+ pk, fk = join_key_map(relations)
37
+ child.merge(fk => parent.fetch(pk))
38
+ end
39
+
40
+ protected
41
+
42
+ # @api private
43
+ def with_keys(relations, &block)
44
+ source_key = relations[source.relation].primary_key
45
+ target_key = relations[target.relation].foreign_key(source.relation)
46
+ return [source_key, target_key] unless block
47
+ yield(source_key, target_key)
48
+ end
6
49
  end
7
50
  end
8
51
  end
@@ -1,45 +1,8 @@
1
1
  module ROM
2
2
  module SQL
3
3
  class Association
4
- class OneToOne < Association
4
+ class OneToOne < OneToMany
5
5
  result :one
6
-
7
- # @api public
8
- def call(relations)
9
- with_keys(relations) do |left_pk, right_fk|
10
- right = relations[target.relation]
11
- columns = right.header.qualified.to_a
12
-
13
- relation = right
14
- .inner_join(source, left_pk => right_fk)
15
- .select(*columns)
16
- .order(*right.header.project(*right.primary_key).qualified)
17
-
18
- relation.with(attributes: relation.header.names)
19
- end
20
- end
21
-
22
- # @api public
23
- def combine_keys(relations)
24
- Hash[*with_keys(relations)]
25
- end
26
-
27
- # @api public
28
- def join_keys(relations)
29
- with_keys(relations) { |source_key, target_key|
30
- { qualify(source, source_key) => qualify(target, target_key) }
31
- }
32
- end
33
-
34
- protected
35
-
36
- # @api private
37
- def with_keys(relations, &block)
38
- source_key = relations[source.relation].primary_key
39
- target_key = relations[target.relation].foreign_key(source.relation)
40
- return [source_key, target_key] unless block
41
- yield(source_key, target_key)
42
- end
43
6
  end
44
7
  end
45
8
  end
@@ -3,6 +3,3 @@ require 'rom/commands'
3
3
  require 'rom/sql/commands/create'
4
4
  require 'rom/sql/commands/update'
5
5
  require 'rom/sql/commands/delete'
6
-
7
- require 'rom/sql/commands/postgres'
8
- require 'rom/sql/commands_ext/postgres'
@@ -11,7 +11,7 @@ module ROM
11
11
  def call(*args)
12
12
  super
13
13
  rescue *ERROR_MAP.keys => e
14
- raise ERROR_MAP[e.class], e
14
+ raise ERROR_MAP.fetch(e.class, Error), e
15
15
  end
16
16
 
17
17
  alias_method :[], :call
@@ -1,7 +1,8 @@
1
- require "rom/sql/error"
1
+ require 'rom/sql/error'
2
2
 
3
3
  module ROM
4
4
  module SQL
5
+ MissingConfigurationError = Class.new(StandardError)
5
6
  NoAssociationError = Class.new(StandardError)
6
7
  DatabaseError = Class.new(Error)
7
8
  ConstraintError = Class.new(Error)
@@ -9,9 +10,11 @@ module ROM
9
10
  UniqueConstraintError = Class.new(ConstraintError)
10
11
  ForeignKeyConstraintError = Class.new(ConstraintError)
11
12
  CheckConstraintError = Class.new(ConstraintError)
13
+ UnknownDBTypeError = Class.new(StandardError)
12
14
 
13
15
  ERROR_MAP = {
14
16
  Sequel::DatabaseError => DatabaseError,
17
+ Sequel::ConstraintViolation => ConstraintError,
15
18
  Sequel::NotNullConstraintViolation => NotNullConstraintError,
16
19
  Sequel::UniqueConstraintViolation => UniqueConstraintError,
17
20
  Sequel::ForeignKeyConstraintViolation => ForeignKeyConstraintError,
@@ -0,0 +1,19 @@
1
+ require 'dry/core/extensions'
2
+
3
+ module ROM
4
+ module SQL
5
+ extend Dry::Core::Extensions
6
+
7
+ register_extension(:postgres) do
8
+ require 'rom/sql/extensions/postgres'
9
+ end
10
+
11
+ register_extension(:active_support_notifications) do
12
+ require 'rom/sql/extensions/active_support_notifications'
13
+ end
14
+
15
+ register_extension(:rails_log_subscriber) do
16
+ require 'rom/sql/extensions/rails_log_subscriber'
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ require 'rom/sql/extensions/postgres/commands'
2
+ require 'rom/sql/extensions/postgres/types'
3
+ require 'rom/sql/extensions/postgres/inferrer'
@@ -1,7 +1,45 @@
1
+ require 'rom/sql/commands/create'
2
+ require 'rom/sql/commands/update'
3
+
1
4
  module ROM
2
5
  module SQL
3
6
  module Commands
4
7
  module Postgres
8
+ module Create
9
+ # Executes insert statement and returns inserted tuples
10
+ #
11
+ # @api private
12
+ def insert(tuples)
13
+ tuples.map do |tuple|
14
+ relation.dataset.returning(*relation.columns).insert(tuple)
15
+ end.flatten
16
+ end
17
+
18
+ # Executes multi_insert statement and returns inserted tuples
19
+ #
20
+ # @api private
21
+ def multi_insert(tuples)
22
+ relation.dataset.returning(*relation.columns).multi_insert(tuples)
23
+ end
24
+
25
+ # Executes upsert statement (INSERT with ON CONFLICT clause)
26
+ # and returns inserted/updated tuples
27
+ #
28
+ # @api private
29
+ def upsert(tuple, opts = EMPTY_HASH)
30
+ relation.dataset.returning(*relation.columns).insert_conflict(opts).insert(tuple)
31
+ end
32
+ end
33
+
34
+ module Update
35
+ # Executes update statement and returns updated tuples
36
+ #
37
+ # @api private
38
+ def update(tuple)
39
+ relation.dataset.returning(*relation.columns).update(tuple)
40
+ end
41
+ end
42
+
5
43
  # Upsert command
6
44
  #
7
45
  # Uses a feature of PostgreSQL 9.5 commonly called an "upsert".
@@ -0,0 +1,64 @@
1
+ require 'rom/sql/schema/inferrer'
2
+ require 'rom/sql/extensions/postgres/types'
3
+
4
+ module ROM
5
+ module SQL
6
+ class Schema
7
+ class PostgresInferrer < Inferrer[:postgres]
8
+ defines :db_numeric_types, :db_type_mapping, :db_array_type_matcher
9
+
10
+ db_numeric_types(
11
+ 'smallint' => true,
12
+ 'integer' => true,
13
+ 'bigint' => true,
14
+ 'decimal' => true,
15
+ 'numeric' => true,
16
+ 'real' => true,
17
+ 'double precision' => true,
18
+ 'serial' => true,
19
+ 'bigserial' => true,
20
+ ).freeze
21
+
22
+ db_type_mapping(
23
+ 'uuid' => Types::PG::UUID,
24
+ 'money' => Types::PG::Money,
25
+ 'bytea' => Types::Blob,
26
+ 'json' => Types::PG::JSON,
27
+ 'jsonb' => Types::PG::JSONB,
28
+ ).freeze
29
+
30
+ db_array_type_matcher Sequel::Postgres::PGArray::EMPTY_BRACKET
31
+
32
+ private
33
+
34
+ def map_pk_type(type, db_type)
35
+ if numeric?(type, db_type)
36
+ type = self.class.numeric_pk_type
37
+ else
38
+ type = map_type(type, db_type)
39
+ end
40
+
41
+ type.meta(primary_key: true)
42
+ end
43
+
44
+ def map_type(ruby_type, db_type)
45
+ if db_type.end_with?(self.class.db_array_type_matcher)
46
+ Types::PG::Array(db_type)
47
+ else
48
+ map_db_type(db_type) || super
49
+ end
50
+ end
51
+
52
+ def map_db_type(db_type)
53
+ self.class.db_type_mapping[db_type]
54
+ end
55
+
56
+ def numeric?(ruby_type, db_type)
57
+ self.class.db_numeric_types.fetch(db_type) do
58
+ ruby_type == :integer
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end