rom-sql 1.3.5 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -7
  3. data/Gemfile +7 -5
  4. data/lib/rom/plugins/relation/sql/auto_restrictions.rb +11 -17
  5. data/lib/rom/sql.rb +3 -2
  6. data/lib/rom/sql/associations.rb +5 -0
  7. data/lib/rom/sql/associations/core.rb +20 -0
  8. data/lib/rom/sql/associations/many_to_many.rb +83 -0
  9. data/lib/rom/sql/associations/many_to_one.rb +55 -0
  10. data/lib/rom/sql/associations/one_to_many.rb +31 -0
  11. data/lib/rom/sql/{association → associations}/one_to_one.rb +3 -2
  12. data/lib/rom/sql/{association → associations}/one_to_one_through.rb +3 -2
  13. data/lib/rom/sql/associations/self_ref.rb +39 -0
  14. data/lib/rom/sql/attribute.rb +44 -54
  15. data/lib/rom/sql/errors.rb +2 -0
  16. data/lib/rom/sql/extensions/mysql.rb +1 -1
  17. data/lib/rom/sql/extensions/mysql/attributes_inferrer.rb +10 -0
  18. data/lib/rom/sql/extensions/postgres.rb +1 -1
  19. data/lib/rom/sql/extensions/postgres/{inferrer.rb → attributes_inferrer.rb} +4 -4
  20. data/lib/rom/sql/extensions/postgres/types.rb +9 -19
  21. data/lib/rom/sql/extensions/sqlite.rb +1 -1
  22. data/lib/rom/sql/extensions/sqlite/{inferrer.rb → attributes_inferrer.rb} +2 -2
  23. data/lib/rom/sql/gateway.rb +29 -30
  24. data/lib/rom/sql/index.rb +13 -0
  25. data/lib/rom/sql/migration.rb +10 -0
  26. data/lib/rom/sql/migration/inline_runner.rb +86 -0
  27. data/lib/rom/sql/migration/migrator.rb +17 -0
  28. data/lib/rom/sql/migration/schema_diff.rb +177 -0
  29. data/lib/rom/sql/plugin/associates.rb +11 -45
  30. data/lib/rom/sql/plugin/pagination.rb +4 -4
  31. data/lib/rom/sql/relation.rb +22 -42
  32. data/lib/rom/sql/relation/reading.rb +3 -3
  33. data/lib/rom/sql/schema.rb +14 -21
  34. data/lib/rom/sql/schema/associations_dsl.rb +7 -6
  35. data/lib/rom/sql/schema/attributes_inferrer.rb +164 -0
  36. data/lib/rom/sql/schema/inferrer.rb +40 -141
  37. data/lib/rom/sql/type_extensions.rb +44 -0
  38. data/lib/rom/sql/version.rb +1 -1
  39. data/lib/rom/sql/wrap.rb +25 -0
  40. data/rom-sql.gemspec +2 -2
  41. data/spec/integration/{association → associations}/many_to_many/custom_fks_spec.rb +4 -2
  42. data/spec/integration/{association → associations}/many_to_many/from_view_spec.rb +2 -2
  43. data/spec/integration/{association → associations}/many_to_many_spec.rb +25 -30
  44. data/spec/integration/{association → associations}/many_to_one/custom_fks_spec.rb +5 -3
  45. data/spec/integration/{association → associations}/many_to_one/from_view_spec.rb +3 -3
  46. data/spec/integration/{association → associations}/many_to_one/self_ref_spec.rb +2 -2
  47. data/spec/integration/{association → associations}/many_to_one_spec.rb +20 -38
  48. data/spec/integration/{association → associations}/one_to_many/custom_fks_spec.rb +4 -2
  49. data/spec/integration/{association → associations}/one_to_many/from_view_spec.rb +2 -2
  50. data/spec/integration/{association → associations}/one_to_many/self_ref_spec.rb +2 -2
  51. data/spec/integration/{association → associations}/one_to_many_spec.rb +24 -11
  52. data/spec/integration/{association → associations}/one_to_one_spec.rb +13 -9
  53. data/spec/integration/{association → associations}/one_to_one_through_spec.rb +15 -11
  54. data/spec/integration/auto_migrations/errors_spec.rb +31 -0
  55. data/spec/integration/auto_migrations/indexes_spec.rb +109 -0
  56. data/spec/integration/auto_migrations/managing_columns_spec.rb +156 -0
  57. data/spec/integration/auto_migrations/postgres/column_types_spec.rb +63 -0
  58. data/spec/integration/commands/create_spec.rb +2 -4
  59. data/spec/integration/commands/delete_spec.rb +2 -2
  60. data/spec/integration/commands/update_spec.rb +2 -0
  61. data/spec/integration/graph_spec.rb +9 -3
  62. data/spec/integration/plugins/associates_spec.rb +16 -55
  63. data/spec/integration/plugins/auto_restrictions_spec.rb +0 -11
  64. data/spec/integration/relation_schema_spec.rb +49 -25
  65. data/spec/integration/schema/inferrer/postgres_spec.rb +1 -1
  66. data/spec/integration/schema/inferrer_spec.rb +7 -18
  67. data/spec/integration/setup_spec.rb +4 -0
  68. data/spec/integration/{plugins/auto_wrap_spec.rb → wrap_spec.rb} +13 -36
  69. data/spec/shared/accounts.rb +4 -0
  70. data/spec/shared/database_setup.rb +2 -1
  71. data/spec/shared/notes.rb +2 -0
  72. data/spec/shared/posts.rb +2 -0
  73. data/spec/shared/puppies.rb +2 -0
  74. data/spec/shared/relations.rb +2 -2
  75. data/spec/shared/users.rb +2 -0
  76. data/spec/shared/users_and_tasks.rb +4 -0
  77. data/spec/spec_helper.rb +3 -6
  78. data/spec/support/helpers.rb +11 -8
  79. data/spec/support/test_configuration.rb +16 -0
  80. data/spec/unit/plugin/associates_spec.rb +5 -10
  81. data/spec/unit/plugin/pagination_spec.rb +9 -9
  82. data/spec/unit/plugin/timestamp_spec.rb +9 -9
  83. data/spec/unit/relation/dataset_spec.rb +7 -5
  84. data/spec/unit/relation/inner_join_spec.rb +2 -15
  85. data/spec/unit/relation/primary_key_spec.rb +1 -1
  86. data/spec/unit/schema_spec.rb +6 -4
  87. metadata +65 -70
  88. data/lib/rom/plugins/relation/sql/auto_combine.rb +0 -71
  89. data/lib/rom/plugins/relation/sql/auto_wrap.rb +0 -62
  90. data/lib/rom/sql/association.rb +0 -103
  91. data/lib/rom/sql/association/many_to_many.rb +0 -119
  92. data/lib/rom/sql/association/many_to_one.rb +0 -73
  93. data/lib/rom/sql/association/name.rb +0 -78
  94. data/lib/rom/sql/association/one_to_many.rb +0 -60
  95. data/lib/rom/sql/extensions/mysql/inferrer.rb +0 -10
  96. data/lib/rom/sql/qualified_attribute.rb +0 -53
  97. data/lib/rom/sql/schema/dsl.rb +0 -75
  98. data/spec/unit/association/many_to_many_spec.rb +0 -89
  99. data/spec/unit/association/many_to_one_spec.rb +0 -81
  100. data/spec/unit/association/name_spec.rb +0 -68
  101. data/spec/unit/association/one_to_many_spec.rb +0 -82
  102. data/spec/unit/association/one_to_one_spec.rb +0 -83
  103. data/spec/unit/association/one_to_one_through_spec.rb +0 -69
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 930bb93fc7cdf5236b363f9f1f343e400f567e92
4
- data.tar.gz: bc4abbac8eedc26e82b4599ce80657ad99dacab5
3
+ metadata.gz: ff0be19f60330b9224eaf421b85ad113000c1558
4
+ data.tar.gz: 3ccb799110fbc7543f3e9ef9ebd511193c700ab6
5
5
  SHA512:
6
- metadata.gz: 672c4a3ed57a3b3d2de8cb996fddfc0819da3de23af2dbdf6fdb6c962f4d2a5eda7e773e2e8768be403ed0643dd620124e0c3ac8f9c1e841e54d44d7887b0757
7
- data.tar.gz: 9c0573d506286947956602885042246478f1798ba82622f5574f959a7eca5b2eba4487de670cf3655d2ee50365011f487bca2b506c076fd8f0edf95045f54689
6
+ metadata.gz: fe36e8c1a886f3231385d3ff9709aa11a4ad13b63b313ec5fd07fc76af0537327184bef102af03c66331750b76d0edfd7838e1ec4e02e8189ac56f91c7749203
7
+ data.tar.gz: 3192a10d465305f01d780e4db7af846c14c3c09509afb59f5cdad770383234ab59fc80b49431270aa863adeb7a51f7f3867a05c48cdfde084c7ed1ac1ea83a19
data/CHANGELOG.md CHANGED
@@ -1,18 +1,24 @@
1
- ## v1.3.5 2017-10-12
1
+ ## v2.0.0 to-be-released
2
2
 
3
- ### Changed
3
+ ### Added
4
4
 
5
- * Added compatibility with `dry-types` 0.11 (flash-gordon)
5
+ * Support for schema plugins (flash-gordon)
6
+ * Support for auto migrations (flash-gordon)
6
7
 
7
- [Compare v1.3.4..v1.3.5](https://github.com/rom-rb/rom-sql/compare/v1.3.4...v1.3.5)
8
+ ### Changed
8
9
 
9
- ## v1.3.4 2017-09-12
10
+ * [BREAKING] based on rom 4.0 now
11
+ * [BREAKING] `Associates` command plugin requires associations now (solnic)
12
+ * `ManyToOne` no longer uses a join (solnic)
13
+ * `AutoCombine` and `AutoWrap` plugins were removed as this functionality is provided by core API (solnic)
10
14
 
11
15
  ### Fixed
12
16
 
13
- * A warning caused by using `EMPTY_BRACKET` from Sequel (flash-gordon)
17
+ * Self-ref associations work correctly with custom FKs (solnic)
18
+ * Aliased associations with custom FKs work correctly (solnic)
19
+ * Defining a custom dataset block no longer prevents default views like `by_pk` to be defined (solnic)
14
20
 
15
- [Compare v1.3.3..v1.3.4](https://github.com/rom-rb/rom-sql/compare/v1.3.3...v1.3.4)
21
+ [Compare v1.3.3...master](https://github.com/rom-rb/rom-sql/compare/v1.3.3...master)
16
22
 
17
23
  ## v1.3.3 2017-05-30
18
24
 
data/Gemfile CHANGED
@@ -2,7 +2,13 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rom', git: 'https://github.com/rom-rb/rom.git', branch: 'release-3.0'
5
+ gem 'dry-types', git: 'https://github.com/dry-rb/dry-types', branch: 'master'
6
+
7
+ gem 'rom', git: 'https://github.com/rom-rb/rom', branch: 'master' do
8
+ gem 'rom-core'
9
+ gem 'rom-mapper'
10
+ gem 'rom-repository', group: :tools
11
+ end
6
12
 
7
13
  group :test do
8
14
  gem 'pry-byebug', platforms: :mri
@@ -25,7 +31,3 @@ group :test do
25
31
  gem 'jdbc-sqlite3', platforms: :jruby
26
32
  gem 'ruby-oci8', platforms: :mri if ENV['ROM_USE_ORACLE']
27
33
  end
28
-
29
- group :tools do
30
- gem 'rom-repository', git: 'https://github.com/rom-rb/rom-repository.git', branch: 'master'
31
- end
@@ -1,12 +1,11 @@
1
+ require 'rom/support/notifications'
2
+
1
3
  module ROM
2
4
  module Plugins
3
5
  module Relation
4
6
  module SQL
5
7
  # Generates methods for restricting relations by their indexed attributes
6
8
  #
7
- # This plugin must be enabled for the whole adapter, `use` won't work as
8
- # schema is not yet available, unless it was defined explicitly.
9
- #
10
9
  # @example
11
10
  # rom = ROM.container(:sql, 'sqlite::memory') do |config|
12
11
  # config.create_table(:users) do
@@ -26,26 +25,21 @@ module ROM
26
25
  #
27
26
  # @api public
28
27
  module AutoRestrictions
29
- EmptySchemaError = Class.new(ArgumentError) do
30
- def initialize(klass)
31
- super("#{klass} relation has no schema. " \
32
- "Make sure :auto_restrictions is enabled after defining a schema")
33
- end
34
- end
28
+ extend Notifications::Listener
29
+
30
+ subscribe('configuration.relations.schema.set', adapter: :sql) do |event|
31
+ schema = event[:schema]
32
+ relation = event[:relation]
35
33
 
36
- def self.included(klass)
37
- super
38
- schema = klass.schema
39
- raise EmptySchemaError, klass if schema.nil?
40
- methods, mod = restriction_methods(schema)
41
- klass.include(mod)
42
- methods.each { |meth| klass.auto_curry(meth) }
34
+ methods, mod = AutoRestrictions.restriction_methods(schema)
35
+ relation.include(mod)
36
+ methods.each { |meth| relation.auto_curry(meth) }
43
37
  end
44
38
 
45
39
  def self.restriction_methods(schema)
46
40
  mod = Module.new
47
41
 
48
- indexed_attrs = schema.select { |attr| attr.meta[:index] }
42
+ indexed_attrs = schema.indexes.map { |index| index.attributes[0] }.uniq
49
43
 
50
44
  methods = indexed_attrs.map do |attr|
51
45
  meth_name = :"by_#{attr.name}"
data/lib/rom/sql.rb CHANGED
@@ -1,6 +1,6 @@
1
- require 'dry-equalizer'
1
+ require 'dry/equalizer'
2
2
  require 'sequel'
3
- require 'rom'
3
+ require 'rom/core'
4
4
 
5
5
  require 'rom/sql/version'
6
6
  require 'rom/sql/errors'
@@ -9,6 +9,7 @@ require 'rom/configuration_dsl'
9
9
 
10
10
  require 'rom/sql/plugins'
11
11
  require 'rom/sql/relation'
12
+ require 'rom/sql/associations'
12
13
  require 'rom/sql/gateway'
13
14
  require 'rom/sql/migration'
14
15
  require 'rom/sql/extensions'
@@ -0,0 +1,5 @@
1
+ require 'rom/sql/associations/many_to_many'
2
+ require 'rom/sql/associations/many_to_one'
3
+ require 'rom/sql/associations/one_to_many'
4
+ require 'rom/sql/associations/one_to_one'
5
+ require 'rom/sql/associations/one_to_one_through'
@@ -0,0 +1,20 @@
1
+ module ROM
2
+ module SQL
3
+ module Associations
4
+ # Core SQL association API
5
+ #
6
+ # @api private
7
+ module Core
8
+ # @api private
9
+ def preload(target, loaded)
10
+ source_key, target_key = join_keys.flatten(1)
11
+
12
+ target_pks = loaded.pluck(source_key.key)
13
+ target_pks.uniq!
14
+
15
+ target.where(target_key => target_pks)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,83 @@
1
+ require 'rom/associations/many_to_many'
2
+ require 'rom/sql/associations/core'
3
+
4
+ module ROM
5
+ module SQL
6
+ module Associations
7
+ class ManyToMany < ROM::Associations::ManyToMany
8
+ include Associations::Core
9
+
10
+ # @api public
11
+ def call(target: self.target)
12
+ left = join_assoc.(target: target)
13
+
14
+ schema =
15
+ if left.schema.key?(foreign_key)
16
+ if target != self.target
17
+ target.schema.merge(join_schema)
18
+ else
19
+ left.schema.project(*columns)
20
+ end
21
+ else
22
+ target_schema
23
+ end.qualified
24
+
25
+ relation = left.join(source.name.dataset, join_keys)
26
+
27
+ if view
28
+ apply_view(schema, relation)
29
+ else
30
+ schema.(relation)
31
+ end
32
+ end
33
+
34
+ # @api public
35
+ def join(type, source = self.source, target = self.target)
36
+ through_assoc = source.associations[through]
37
+ joined = through_assoc.join(type, source)
38
+ joined.__send__(type, target.name.dataset, join_keys).qualified
39
+ end
40
+
41
+ # @api public
42
+ def join_keys
43
+ { source_attr => target_attr }
44
+ end
45
+
46
+ # @api public
47
+ def source_attr
48
+ source[source_key].qualified
49
+ end
50
+
51
+ # @api public
52
+ def target_attr
53
+ join_relation[target_key].qualified
54
+ end
55
+
56
+ # @api private
57
+ def persist(children, parents)
58
+ join_tuples = associate(children, parents)
59
+ join_relation.multi_insert(join_tuples)
60
+ end
61
+
62
+ private
63
+
64
+ # @api private
65
+ def target_schema
66
+ target.schema.merge(join_schema)
67
+ end
68
+
69
+ # @api private
70
+ def join_schema
71
+ join_relation.schema.project(foreign_key)
72
+ end
73
+
74
+ # @api private
75
+ def columns
76
+ target_schema.map(&:name)
77
+ end
78
+
79
+ memoize :join_keys, :target_schema, :join_schema, :columns
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,55 @@
1
+ require 'rom/associations/many_to_one'
2
+ require 'rom/sql/associations/core'
3
+ require 'rom/sql/associations/self_ref'
4
+
5
+ module ROM
6
+ module SQL
7
+ module Associations
8
+ class ManyToOne < ROM::Associations::ManyToOne
9
+ include Associations::Core
10
+ include Associations::SelfRef
11
+
12
+ # @api public
13
+ def call(target: self.target, preload: false)
14
+ if preload
15
+ schema = target.schema.qualified
16
+ relation = target
17
+ else
18
+ right = source
19
+
20
+ target_pk = target.schema.primary_key_name
21
+ right_fk = target.foreign_key(source.name)
22
+
23
+ target_schema = target.schema
24
+ right_schema = right.schema.project_pk
25
+
26
+ schema =
27
+ if target.schema.key?(right_fk)
28
+ target_schema
29
+ else
30
+ target_schema.merge(right_schema.project_fk(target_pk => right_fk))
31
+ end.qualified
32
+
33
+ relation = target.join(source_table, join_keys)
34
+ end
35
+
36
+ if view
37
+ apply_view(schema, relation)
38
+ else
39
+ schema.(relation)
40
+ end
41
+ end
42
+
43
+ # @api public
44
+ def join(type, source = self.source, target = self.target)
45
+ source.__send__(type, target.name.dataset, join_keys).qualified
46
+ end
47
+
48
+ # @api private
49
+ def prepare(target)
50
+ call(target: target, preload: true)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,31 @@
1
+ require 'rom/associations/one_to_many'
2
+ require 'rom/sql/associations/core'
3
+ require 'rom/sql/associations/self_ref'
4
+
5
+ module ROM
6
+ module SQL
7
+ module Associations
8
+ class OneToMany < ROM::Associations::OneToMany
9
+ include Associations::Core
10
+ include Associations::SelfRef
11
+
12
+ # @api public
13
+ def call(target: self.target)
14
+ schema = target.schema.qualified
15
+ relation = target.join(source_table, join_keys)
16
+
17
+ if view
18
+ apply_view(schema, relation)
19
+ else
20
+ schema.(relation)
21
+ end
22
+ end
23
+
24
+ # @api public
25
+ def join(type, source = self.source, target = self.target)
26
+ source.__send__(type, target.name.dataset, join_keys).qualified
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,8 +1,9 @@
1
+ require 'rom/sql/associations/one_to_many'
2
+
1
3
  module ROM
2
4
  module SQL
3
- class Association
5
+ module Associations
4
6
  class OneToOne < OneToMany
5
- result :one
6
7
  end
7
8
  end
8
9
  end
@@ -1,8 +1,9 @@
1
+ require 'rom/sql/associations/many_to_many'
2
+
1
3
  module ROM
2
4
  module SQL
3
- class Association
5
+ module Associations
4
6
  class OneToOneThrough < ManyToMany
5
- result :one
6
7
  end
7
8
  end
8
9
  end
@@ -0,0 +1,39 @@
1
+ module ROM
2
+ module SQL
3
+ module Associations
4
+ module SelfRef
5
+ def self.included(klass)
6
+ super
7
+ klass.memoize :join_keys, :source_table, :source_alias, :source_attr, :target_attr
8
+ end
9
+
10
+ # @api public
11
+ def join_keys
12
+ { source_attr => target_attr }
13
+ end
14
+
15
+ # @api public
16
+ def source_attr
17
+ source[source_key].qualified(source_alias)
18
+ end
19
+
20
+ # @api public
21
+ def target_attr
22
+ target[target_key].qualified
23
+ end
24
+
25
+ protected
26
+
27
+ # @api private
28
+ def source_table
29
+ self_ref? ? Sequel.as(source.name.dataset, source_alias) : source.name.dataset
30
+ end
31
+
32
+ # @api private
33
+ def source_alias
34
+ self_ref? ? :"#{source.name.dataset.to_s[0]}_0" : source.name.dataset
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -2,6 +2,8 @@ require 'sequel/core'
2
2
  require 'dry/core/cache'
3
3
 
4
4
  require 'rom/schema/attribute'
5
+
6
+ require 'rom/sql/type_extensions'
5
7
  require 'rom/sql/projection_dsl'
6
8
 
7
9
  module ROM
@@ -12,57 +14,11 @@ module ROM
12
14
  class Attribute < ROM::Schema::Attribute
13
15
  OPERATORS = %i[>= <= > <].freeze
14
16
  NONSTANDARD_EQUALITY_VALUES = [true, false, nil].freeze
17
+ INDEXED = Set.new([true]).freeze
15
18
 
16
19
  # Error raised when an attribute cannot be qualified
17
20
  QualifyError = Class.new(StandardError)
18
21
 
19
- # Type-specific methods
20
- #
21
- # @api public
22
- module TypeExtensions
23
- class << self
24
- # Gets extensions for a type
25
- #
26
- # @param [Dry::Types::Type] type
27
- #
28
- # @return [Hash]
29
- #
30
- # @api public
31
- def [](wrapped)
32
- type = wrapped.default? ? wrapped.type : wrapped
33
- type = type.optional? ? type.right : type
34
- @types[type.meta[:database]][type.meta[:db_type]] || EMPTY_HASH
35
- end
36
-
37
- # Registers a set of operations supported for a specific type
38
- #
39
- # @example
40
- # ROM::SQL::Attribute::TypeExtensions.register(ROM::SQL::Types::PG::JSONB) do
41
- # def contain(type, expr, keys)
42
- # Attribute[Types::Bool].meta(sql_expr: expr.pg_jsonb.contains(value))
43
- # end
44
- # end
45
- #
46
- # @param [Dry::Types::Type] type Type
47
- #
48
- # @api public
49
- def register(type, &block)
50
- extensions = @types[type.meta[:database]]
51
- db_type = type.meta[:db_type]
52
-
53
- raise ArgumentError, "Type #{ type } already registered" if @types.key?(type)
54
- mod = Module.new(&block)
55
- ctx = Object.new.extend(mod)
56
- functions = mod.public_instance_methods.each_with_object({}) { |m, ms| ms[m] = ctx.method(m) }
57
- extensions[db_type] = functions
58
- end
59
- end
60
-
61
- @types = ::Hash.new do |hash, database|
62
- hash[database] = {}
63
- end
64
- end
65
-
66
22
  extend Dry::Core::Cache
67
23
 
68
24
  # @api private
@@ -104,12 +60,12 @@ module ROM
104
60
  # @return [SQL::Attribute]
105
61
  #
106
62
  # @api public
107
- def qualified
63
+ def qualified(table_alias = nil)
108
64
  return self if qualified?
109
65
 
110
66
  case sql_expr
111
67
  when Sequel::SQL::AliasedExpression, Sequel::SQL::Identifier
112
- type = meta(qualified: true)
68
+ type = meta(qualified: table_alias || true)
113
69
  type.meta(sql_expr: type.to_sql_name)
114
70
  else
115
71
  raise QualifyError, "can't qualify #{name.inspect} (#{sql_expr.inspect})"
@@ -155,7 +111,7 @@ module ROM
155
111
  #
156
112
  # @api public
157
113
  def qualified?
158
- meta[:qualified].equal?(true)
114
+ meta[:qualified].equal?(true) || meta[:qualified].is_a?(Symbol)
159
115
  end
160
116
 
161
117
  # Return a new attribute marked as a FK
@@ -188,9 +144,9 @@ module ROM
188
144
  def to_sym
189
145
  @_to_sym ||=
190
146
  if qualified? && aliased?
191
- :"#{source.dataset}__#{name}___#{meta[:alias]}"
147
+ :"#{table_name}__#{name}___#{meta[:alias]}"
192
148
  elsif qualified?
193
- :"#{source.dataset}__#{name}"
149
+ :"#{table_name}__#{name}"
194
150
  elsif aliased?
195
151
  :"#{name}___#{meta[:alias]}"
196
152
  else
@@ -319,9 +275,9 @@ module ROM
319
275
  def to_sql_name
320
276
  @_to_sql_name ||=
321
277
  if qualified? && aliased?
322
- Sequel.qualify(source.dataset, name).as(meta[:alias])
278
+ Sequel.qualify(table_name, name).as(meta[:alias])
323
279
  elsif qualified?
324
- Sequel.qualify(source.dataset, name)
280
+ Sequel.qualify(table_name, name)
325
281
  elsif aliased?
326
282
  Sequel.as(name, meta[:alias])
327
283
  else
@@ -329,6 +285,27 @@ module ROM
329
285
  end
330
286
  end
331
287
 
288
+ # @api public
289
+ def indexed?
290
+ !indexes.empty?
291
+ end
292
+
293
+ # @api public
294
+ def indexes
295
+ if meta[:index] == true
296
+ INDEXED
297
+ else
298
+ meta[:index] || EMPTY_SET
299
+ end
300
+ end
301
+
302
+ # @api private
303
+ def meta_ast
304
+ meta = super
305
+ meta[:index] = indexes if indexed?
306
+ meta
307
+ end
308
+
332
309
  private
333
310
 
334
311
  # Return Sequel Expression object for an attribute
@@ -372,6 +349,19 @@ module ROM
372
349
  type[value]
373
350
  end
374
351
  end
352
+
353
+ # Return source table name or its alias
354
+ #
355
+ # @api private
356
+ def table_name
357
+ if qualified? && meta[:qualified].is_a?(Symbol)
358
+ meta[:qualified]
359
+ else
360
+ source.dataset
361
+ end
362
+ end
363
+
364
+ memoize :joined, :to_sql_name, :table_name, :canonical
375
365
  end
376
366
  end
377
367
  end