rom-sql 1.0.0.beta3 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -5
  3. data/.yardopts +2 -0
  4. data/CHANGELOG.md +4 -1
  5. data/lib/rom/plugins/relation/sql/auto_combine.rb +4 -0
  6. data/lib/rom/plugins/relation/sql/auto_wrap.rb +4 -0
  7. data/lib/rom/sql/{type.rb → attribute.rb} +8 -5
  8. data/lib/rom/sql/commands/update.rb +10 -0
  9. data/lib/rom/sql/dsl.rb +1 -0
  10. data/lib/rom/sql/extensions/postgres/inferrer.rb +2 -1
  11. data/lib/rom/sql/extensions/sqlite.rb +1 -0
  12. data/lib/rom/sql/extensions/sqlite/inferrer.rb +9 -0
  13. data/lib/rom/sql/extensions/sqlite/types.rb +11 -0
  14. data/lib/rom/sql/function.rb +4 -1
  15. data/lib/rom/sql/gateway.rb +64 -28
  16. data/lib/rom/sql/migration.rb +21 -29
  17. data/lib/rom/sql/migration/migrator.rb +8 -0
  18. data/lib/rom/sql/order_dsl.rb +1 -0
  19. data/lib/rom/sql/plugin/associates.rb +21 -0
  20. data/lib/rom/sql/plugin/timestamps.rb +131 -0
  21. data/lib/rom/sql/plugins.rb +3 -0
  22. data/lib/rom/sql/projection_dsl.rb +1 -0
  23. data/lib/rom/sql/relation/reading.rb +256 -75
  24. data/lib/rom/sql/restriction_dsl.rb +1 -0
  25. data/lib/rom/sql/schema/associations_dsl.rb +119 -1
  26. data/lib/rom/sql/schema/dsl.rb +44 -2
  27. data/lib/rom/sql/version.rb +1 -1
  28. data/rom-sql.gemspec +2 -2
  29. data/spec/extensions/sqlite/types_spec.rb +11 -0
  30. data/spec/integration/plugins/associates_spec.rb +79 -0
  31. data/spec/integration/schema/inferrer/postgres_spec.rb +3 -1
  32. data/spec/integration/schema/inferrer/sqlite_spec.rb +2 -0
  33. data/spec/shared/database_setup.rb +10 -1
  34. data/spec/spec_helper.rb +1 -1
  35. data/spec/support/helpers.rb +2 -2
  36. data/spec/unit/plugin/timestamp_spec.rb +77 -0
  37. data/spec/unit/types_spec.rb +1 -1
  38. metadata +37 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3c94e3593d4f6fbe8a49111c097a6721ae9d5dfc
4
- data.tar.gz: 0b12c00984a1b6943465d608fe97e66c78beda47
3
+ metadata.gz: 7a382cb7f94949a99c91fd0a25edec94612b15da
4
+ data.tar.gz: b87bb54a9ae16bbcd2ac87bf416a80582a4df16e
5
5
  SHA512:
6
- metadata.gz: 3fc3303b1f6c7b5415d44186bc857b7f8a5add043b1b9f990f2b003003bfa8fddd87fc6feb30532759b4548919dbfbffeea2c560a42faff3225b0894933ee2c8
7
- data.tar.gz: 449816a9fe18c46ba4b65a64e0397121d57c9593a3fffd1ffdab7da04e29eb33a2a40a49cdf8c1859b3e974c68e71a6971eae3afc47a8316715c9c1d8746958d
6
+ metadata.gz: 45f97617413eac1f6c5bb3cf88cd313b74769b9c3e01f5a43939f90e0b48a2f72925b7043b74deeb7c83c9b5cdcf546aa3e347c81b970e521564c13f64c4067b
7
+ data.tar.gz: bfeab37bc67d5ed98e3bb75340ab8df8711653146d9f641d1092aef4c42433c974b32aa7af9bc8198a2df16b034523e6e50ac360df7d2890ecf7a15dbee3acd4
@@ -10,21 +10,21 @@ before_script:
10
10
  - psql -c 'create database rom_sql;' -U postgres
11
11
  - mysql -u root -e 'create database rom_sql;'
12
12
  after_success:
13
- - '[ "$TRAVIS_RUBY_VERSION" = "2.3.1" ] && [ "$TRAVIS_BRANCH" = "master" ] && bundle exec codeclimate-test-reporter'
13
+ - '[ "${TRAVIS_JOB_NUMBER#*.}" = "1" ] && [ "$TRAVIS_BRANCH" = "master" ] && bundle exec codeclimate-test-reporter'
14
14
  script: "bundle exec rake ci"
15
15
  rvm:
16
- - 2.2.5
17
- - 2.3.3
18
16
  - 2.4.0
17
+ - 2.3
18
+ - 2.2
19
19
  - rbx-3
20
- - jruby
20
+ - jruby-9.1.6.0
21
21
  env:
22
22
  global:
23
23
  - CODECLIMATE_REPO_TOKEN=03d7f66589572702b12426d2bc71c4de6281a96139e33b335b894264b1f8f0b0
24
24
  - JRUBY_OPTS='--dev -J-Xmx1024M'
25
25
  matrix:
26
26
  allow_failures:
27
- - rvm: rbx
27
+ - rvm: jruby-9.1.6.0
28
28
  notifications:
29
29
  webhooks:
30
30
  urls:
@@ -0,0 +1,2 @@
1
+ --query '@api.text != "private"'
2
+ --embed-mixins
@@ -16,10 +16,13 @@ Please refer to [the upgrading guide](https://github.com/rom-rb/rom-sql/wiki/Upg
16
16
  * Schema attribute types are now SQL-specific and compatible with query DSL (ie you can pass relation attributes to `select` and they will be automatically converted to valid SQL expressions) (solnic)
17
17
  * Associations support setting custom `view` that will be used to extend association relation (solnic)
18
18
  * Associations support setting custom `foreign_key` names (solnic)
19
+ * Update commands has `:associates` plugin enabled (solnic)
19
20
  * Support for self-referencing associations (ie categories have_many child categories) (solnic)
20
21
  * Inferrers for mysql and sqlite were added (flash-gordon)
21
- * PG's auto-inferrer can handle `inet`/`cidr` data types in a two-way manner, i.e. converting them back and forth on reading and writing. Same for `point` datatype (flash-gordon)
22
+ * PG's auto-inferrer can handle `inet`/`cidr`/`point` data types in a two-way manner, i.e. converting them back and forth on reading and writing (flash-gordon)
23
+ * Support for inferring more PG types: `macaddr`, `xml` (flash-gordon)
22
24
  * `ROM::SQL::Relation::SequelAPI` extension for backward-compatible query API (this will be deprecated in 1.1.0 and removed in 2.0.0) (solnic)
25
+ * Added `Object` type for `SQLite` which is used by the inferrer for columns without a type affinity (flash-gordon)
23
26
 
24
27
  ### Changed
25
28
 
@@ -2,6 +2,7 @@ module ROM
2
2
  module Plugins
3
3
  module Relation
4
4
  module SQL
5
+ # @api private
5
6
  module AutoCombine
6
7
  # @api private
7
8
  def self.included(klass)
@@ -12,7 +13,9 @@ module ROM
12
13
  end
13
14
  end
14
15
 
16
+ # @api private
15
17
  module ClassInterface
18
+ # @api private
16
19
  def inherited(klass)
17
20
  super
18
21
  klass.auto_curry :for_combine
@@ -20,6 +23,7 @@ module ROM
20
23
  end
21
24
  end
22
25
 
26
+ # @api private
23
27
  module InstanceInterface
24
28
  # Default methods for fetching combined relation
25
29
  #
@@ -2,6 +2,7 @@ module ROM
2
2
  module Plugins
3
3
  module Relation
4
4
  module SQL
5
+ # @api private
5
6
  module AutoWrap
6
7
  # @api private
7
8
  def self.included(klass)
@@ -12,13 +13,16 @@ module ROM
12
13
  end
13
14
  end
14
15
 
16
+ # @api private
15
17
  module ClassInterface
18
+ # @api private
16
19
  def inherited(klass)
17
20
  super
18
21
  klass.auto_curry :for_wrap
19
22
  end
20
23
  end
21
24
 
25
+ # @api private
22
26
  module InstanceInterface
23
27
  # Default methods for fetching wrapped relation
24
28
  #
@@ -1,13 +1,16 @@
1
- require 'rom/schema/type'
1
+ require 'rom/schema/attribute'
2
2
 
3
3
  module ROM
4
4
  module SQL
5
- class Type < ROM::Schema::Type
5
+ # Extended schema attributes tailored for SQL databases
6
+ #
7
+ # @api public
8
+ class Attribute < ROM::Schema::Attribute
6
9
  QualifyError = Class.new(StandardError)
7
10
 
8
11
  # Return a new type marked as a FK
9
12
  #
10
- # @return [SQL::Type]
13
+ # @return [SQL::Attribute]
11
14
  #
12
15
  # @api public
13
16
  def foreign_key
@@ -22,7 +25,7 @@ module ROM
22
25
 
23
26
  # Return a new type marked as qualified
24
27
  #
25
- # @return [SQL::Type]
28
+ # @return [SQL::Attribute]
26
29
  #
27
30
  # @api public
28
31
  def qualified
@@ -39,7 +42,7 @@ module ROM
39
42
 
40
43
  # Return a new type marked as joined
41
44
  #
42
- # @return [SQL::Type]
45
+ # @return [SQL::Attribute]
43
46
  #
44
47
  # @api public
45
48
  def joined
@@ -14,6 +14,7 @@ module ROM
14
14
  include ErrorWrapper
15
15
 
16
16
  use :schema
17
+ use :associates
17
18
 
18
19
  after :finalize
19
20
 
@@ -47,6 +48,15 @@ module ROM
47
48
  def primary_key
48
49
  relation.primary_key
49
50
  end
51
+
52
+ # Yields tuples for insertion or return an enumerator
53
+ #
54
+ # @api private
55
+ def with_input_tuples(tuples)
56
+ input_tuples = Array([tuples]).flatten(1).map
57
+ return input_tuples unless block_given?
58
+ input_tuples.each { |tuple| yield(tuple) }
59
+ end
50
60
  end
51
61
  end
52
62
  end
@@ -1,5 +1,6 @@
1
1
  module ROM
2
2
  module SQL
3
+ # @api private
3
4
  class DSL < BasicObject
4
5
  # @api private
5
6
  attr_reader :schema
@@ -23,7 +23,8 @@ module ROM
23
23
  'inet' => Types::PG::IPAddress,
24
24
  'cidr' => Types::PG::IPAddress,
25
25
  'macaddr' => Types::String,
26
- 'point' => Types::PG::PointT
26
+ 'point' => Types::PG::PointT,
27
+ 'xml' => Types::String
27
28
  ).freeze
28
29
 
29
30
  db_array_type_matcher Sequel::Postgres::PGArray::EMPTY_BRACKET
@@ -1 +1,2 @@
1
+ require 'rom/sql/extensions/sqlite/types'
1
2
  require 'rom/sql/extensions/sqlite/inferrer'
@@ -4,6 +4,15 @@ module ROM
4
4
  module SQL
5
5
  class Schema
6
6
  class SqliteInferrer < Inferrer[:sqlite]
7
+ NO_TYPE = EMPTY_STRING
8
+
9
+ def map_type(_, db_type, **_kw)
10
+ if db_type.eql?(NO_TYPE)
11
+ ROM::SQL::Types::SQLite::Object
12
+ else
13
+ super
14
+ end
15
+ end
7
16
  end
8
17
  end
9
18
  end
@@ -0,0 +1,11 @@
1
+ require 'dry-types'
2
+
3
+ module ROM
4
+ module SQL
5
+ module Types
6
+ module SQLite
7
+ Object = ::ROM::SQL::Types::Object
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,6 +1,9 @@
1
+ require 'rom/schema/attribute'
2
+
1
3
  module ROM
2
4
  module SQL
3
- class Function < ROM::Schema::Type
5
+ # @api private
6
+ class Function < ROM::Schema::Attribute
4
7
  def sql_literal(ds)
5
8
  if name
6
9
  func.as(name).sql_literal(ds)
@@ -12,18 +12,14 @@ module ROM
12
12
  module SQL
13
13
  # SQL gateway
14
14
  #
15
- # @example
16
- # db = Sequel.connect(:sqlite)
17
- # gateway = ROM::SQL::Gateway.new(db)
18
- #
19
- # users = gateway.dataset(:users)
20
- #
21
15
  # @api public
22
16
  class Gateway < ROM::Gateway
23
17
  include Dry::Core::Constants
24
18
  include Migration
25
19
 
26
20
  class << self
21
+ # FIXME: get rid of this and figure out a nicer way of handling migration DSL
22
+ # we want to have global access ONLY when running migration tasks
27
23
  attr_accessor :instance
28
24
  end
29
25
 
@@ -31,35 +27,64 @@ module ROM
31
27
  postgres: %i(pg_array pg_json pg_enum)
32
28
  }.freeze
33
29
 
34
- # Return optionally configured logger
35
- #
36
- # @return [Object] logger
37
- #
38
- # @api public
30
+ # @!attribute [r] logger
31
+ # @return [Object] configured gateway logger
39
32
  attr_reader :logger
40
33
 
41
- # @api private
34
+ # @!attribute [r] options
35
+ # @return [Hash] Options used for connection
42
36
  attr_reader :options
43
37
 
44
- # SQL gateway interface
38
+ # Initialize an SQL gateway
39
+ #
40
+ # Gateways are typically initialized via ROM::Configuration object, gateway constructor
41
+ # arguments such as URI and options are passed directly to this constructor
42
+ #
43
+ # @overload initialize(uri)
44
+ # Connects to a database via URI
45
+ #
46
+ # @example
47
+ # ROM.container(:sql, 'postgres://localhost/db_name')
48
+ #
49
+ # @param [Sequel::Database] connection a connection instance
50
+ #
51
+ # @overload initialize(uri, options)
52
+ # Connects to a database via URI and options
45
53
  #
46
- # @overload connect(uri, options)
47
- # Connects to database via uri passing options
54
+ # @example
55
+ # ROM.container(:sql, 'postgres://localhost/db_name', extensions: %w[pg_enum])
48
56
  #
49
57
  # @param [String,Symbol] uri connection URI
58
+ #
50
59
  # @param [Hash] options connection options
51
60
  #
52
- # @overload connect(connection)
53
- # Re-uses connection instance
61
+ # @option options [Array<Symbol>] :inferrable_relations
62
+ # A list of dataset names that should be inferred. If
63
+ # this is set explicitly to an empty array relations
64
+ # won't be inferred at all
65
+ #
66
+ # @option options [Array<Symbol>] :not_inferrable_relations
67
+ # A list of dataset names that should NOT be inferred
68
+ #
69
+ # @option options [Array<Symbol>] :extensions
70
+ # A list of connection extensions supported by Sequel
71
+ #
72
+ # @option options [String] :user Database username
73
+ #
74
+ # @option options [String] :password Database password
75
+ #
76
+ # @overload initialize(connection)
77
+ # Creates a gateway from an existing database connection. This
78
+ # works with Sequel connections exclusively.
79
+ #
80
+ # @example
81
+ # ROM.container(:sql, Sequel.connect(:sqlite))
54
82
  #
55
83
  # @param [Sequel::Database] connection a connection instance
56
84
  #
57
- # @example
58
- # gateway = ROM::SQL::Gateway.new('postgres://localhost/rom')
85
+ # @return [SQL::Gateway]
59
86
  #
60
- # # or reuse connection
61
- # DB = Sequel.connect('postgres://localhost/rom')
62
- # gateway = ROM::SQL::Gateway.new(DB)
87
+ # @see https://github.com/jeremyevans/sequel/blob/master/doc/opening_databases.rdoc Sequel connection docs
63
88
  #
64
89
  # @api public
65
90
  def initialize(uri, options = EMPTY_HASH)
@@ -73,7 +98,7 @@ module ROM
73
98
  self.class.instance = self
74
99
  end
75
100
 
76
- # Disconnect from database
101
+ # Disconnect from the gateway's database
77
102
  #
78
103
  # @api public
79
104
  def disconnect
@@ -82,7 +107,9 @@ module ROM
82
107
 
83
108
  # Return dataset with the given name
84
109
  #
85
- # @param [String] name dataset name
110
+ # Thsi returns a raw Sequel database
111
+ #
112
+ # @param [String, Symbol] name The dataset name
86
113
  #
87
114
  # @return [Dataset]
88
115
  #
@@ -93,6 +120,15 @@ module ROM
93
120
 
94
121
  # Setup a logger
95
122
  #
123
+ # @example set a logger during configuration process
124
+ # rom = ROM.container(:sql, 'sqlite::memory') do |config|
125
+ # config.gateways[:default].use_logger(Logger.new($stdout))
126
+ # end
127
+ #
128
+ # @example set logger after gateway has been established
129
+ # rom = ROM.container(:sql, 'sqlite::memory')
130
+ # rom.gateways[:default].use_logger(Logger.new($stdout))
131
+ #
96
132
  # @param [Object] logger
97
133
  #
98
134
  # @see Sequel::Database#loggers
@@ -114,7 +150,7 @@ module ROM
114
150
  connection[name]
115
151
  end
116
152
 
117
- # Check if dataset exists
153
+ # Check if a dataset exists
118
154
  #
119
155
  # @param [String] name dataset name
120
156
  #
@@ -123,10 +159,10 @@ module ROM
123
159
  schema.include?(name)
124
160
  end
125
161
 
126
- # Extend database-specific behavior
162
+ # Extend the command class with database-specific behavior
127
163
  #
128
- # @param [Class] klass command class
129
- # @param [Object] dataset a dataset that will be used
164
+ # @param [Class] klass Command class
165
+ # @param [Sequel::Dataset] dataset A dataset that will be used
130
166
  #
131
167
  # Note: Currently, only postgres is supported.
132
168
  #
@@ -6,13 +6,12 @@ module ROM
6
6
  # on a specific gateway, use ROM::SQL::Gateway#migration
7
7
  #
8
8
  # @example
9
- # ROM.setup(
9
+ # rom = ROM.container(
10
10
  # default: [:sql, 'sqlite::memory'],
11
11
  # other: [:sql, 'postgres://localhost/test']
12
12
  # )
13
13
  #
14
- # ROM.finalize
15
- #
14
+ # # default gateway migrations
16
15
  # ROM::SQL.migration do
17
16
  # change do
18
17
  # create_table(:users) do
@@ -22,6 +21,16 @@ module ROM
22
21
  # end
23
22
  # end
24
23
  #
24
+ # # other gateway migrations
25
+ # rom.gateways[:other].migration do
26
+ # change do
27
+ # create_table(:users) do
28
+ # primary_key :id
29
+ # String :name
30
+ # end
31
+ # end
32
+ # end
33
+ #
25
34
  # @api public
26
35
  def self.migration(&block)
27
36
  ROM::SQL::Gateway.instance.migration(&block)
@@ -30,7 +39,8 @@ module ROM
30
39
  module Migration
31
40
  Sequel.extension :migration
32
41
 
33
- # @api public
42
+ # @!attribute [r] migrator
43
+ # @return [Migrator] Migrator instance
34
44
  attr_reader :migrator
35
45
 
36
46
  # @api private
@@ -38,6 +48,8 @@ module ROM
38
48
  @migrator = options.fetch(:migrator) { Migrator.new(connection) }
39
49
  end
40
50
 
51
+ # Check if there are any pending migrations
52
+ #
41
53
  # @see ROM::SQL::Migration.pending?
42
54
  #
43
55
  # @api public
@@ -45,6 +57,8 @@ module ROM
45
57
  migrator.pending?
46
58
  end
47
59
 
60
+ # Migration DSL
61
+ #
48
62
  # @see ROM::SQL.migration
49
63
  #
50
64
  # @api public
@@ -52,13 +66,11 @@ module ROM
52
66
  migrator.migration(&block)
53
67
  end
54
68
 
55
- # Run migrations for a given gateway
69
+ # Run migrations
56
70
  #
57
71
  # @example
58
- # ROM.setup(:sql, ['sqlite::memory'])
59
- # ROM.finalize
60
- # ROM.env.gateways[:default].run_migrations
61
- #
72
+ # rom = ROM.container(:sql, ['sqlite::memory'])
73
+ # rom.gateways[:default].run_migrations
62
74
  #
63
75
  # @param [Hash] options The options used by Sequel migrator
64
76
  #
@@ -66,26 +78,6 @@ module ROM
66
78
  def run_migrations(options = {})
67
79
  migrator.run(options)
68
80
  end
69
-
70
- # TODO: this should be removed in favor of migration API in Gateway
71
- class << self
72
- attr_writer :path
73
- attr_accessor :connection
74
-
75
- def path
76
- @path || Migrator::DEFAULT_PATH
77
- end
78
-
79
- def run(options = {})
80
- warn "ROM::SQL::Migration.run is deprecated please ROM::SQL::Gateway#run_migrations (#{caller[0]})"
81
- ::Sequel::Migrator.run(connection, path, options)
82
- end
83
-
84
- def create(&block)
85
- warn "ROM::SQL::Migration.create is deprecated please use ROM::SQL.migration (#{caller[0]})"
86
- ::Sequel.migration(&block)
87
- end
88
- end
89
81
  end
90
82
  end
91
83
  end