rom-sql 0.7.0 → 0.8.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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/.travis.yml +12 -7
  4. data/CHANGELOG.md +28 -0
  5. data/Gemfile +6 -9
  6. data/README.md +5 -4
  7. data/circle.yml +10 -0
  8. data/lib/rom/plugins/relation/sql/auto_combine.rb +16 -3
  9. data/lib/rom/plugins/relation/sql/auto_wrap.rb +3 -2
  10. data/lib/rom/sql/association.rb +75 -0
  11. data/lib/rom/sql/association/many_to_many.rb +86 -0
  12. data/lib/rom/sql/association/many_to_one.rb +60 -0
  13. data/lib/rom/sql/association/name.rb +70 -0
  14. data/lib/rom/sql/association/one_to_many.rb +9 -0
  15. data/lib/rom/sql/association/one_to_one.rb +46 -0
  16. data/lib/rom/sql/association/one_to_one_through.rb +9 -0
  17. data/lib/rom/sql/commands.rb +2 -0
  18. data/lib/rom/sql/commands/create.rb +2 -2
  19. data/lib/rom/sql/commands/delete.rb +0 -1
  20. data/lib/rom/sql/commands/postgres.rb +76 -0
  21. data/lib/rom/sql/commands/update.rb +6 -3
  22. data/lib/rom/sql/commands_ext/postgres.rb +17 -0
  23. data/lib/rom/sql/gateway.rb +23 -15
  24. data/lib/rom/sql/header.rb +7 -1
  25. data/lib/rom/sql/plugin/assoc_macros.rb +3 -3
  26. data/lib/rom/sql/plugin/associates.rb +50 -9
  27. data/lib/rom/sql/qualified_attribute.rb +53 -0
  28. data/lib/rom/sql/relation.rb +76 -25
  29. data/lib/rom/sql/relation/reading.rb +138 -35
  30. data/lib/rom/sql/relation/writing.rb +21 -0
  31. data/lib/rom/sql/schema.rb +35 -0
  32. data/lib/rom/sql/schema/associations_dsl.rb +68 -0
  33. data/lib/rom/sql/schema/dsl.rb +27 -0
  34. data/lib/rom/sql/schema/inferrer.rb +80 -0
  35. data/lib/rom/sql/support/active_support_notifications.rb +27 -17
  36. data/lib/rom/sql/types.rb +11 -0
  37. data/lib/rom/sql/types/pg.rb +26 -0
  38. data/lib/rom/sql/version.rb +1 -1
  39. data/rom-sql.gemspec +4 -2
  40. data/spec/integration/association/many_to_many_spec.rb +137 -0
  41. data/spec/integration/association/many_to_one_spec.rb +110 -0
  42. data/spec/integration/association/one_to_many_spec.rb +58 -0
  43. data/spec/integration/association/one_to_one_spec.rb +57 -0
  44. data/spec/integration/association/one_to_one_through_spec.rb +90 -0
  45. data/spec/integration/combine_spec.rb +24 -24
  46. data/spec/integration/commands/create_spec.rb +215 -168
  47. data/spec/integration/commands/delete_spec.rb +88 -46
  48. data/spec/integration/commands/update_spec.rb +141 -60
  49. data/spec/integration/commands/upsert_spec.rb +83 -0
  50. data/spec/integration/gateway_spec.rb +9 -17
  51. data/spec/integration/migration_spec.rb +3 -5
  52. data/spec/integration/plugins/associates_spec.rb +168 -0
  53. data/spec/integration/plugins/auto_wrap_spec.rb +46 -0
  54. data/spec/integration/read_spec.rb +80 -77
  55. data/spec/integration/relation_schema_spec.rb +180 -0
  56. data/spec/integration/schema_inference_spec.rb +67 -0
  57. data/spec/integration/setup_spec.rb +22 -0
  58. data/spec/{support → integration/support}/active_support_notifications_spec.rb +0 -0
  59. data/spec/{support → integration/support}/rails_log_subscriber_spec.rb +0 -0
  60. data/spec/shared/database_setup.rb +46 -8
  61. data/spec/shared/relations.rb +8 -0
  62. data/spec/shared/users_and_accounts.rb +10 -0
  63. data/spec/shared/users_and_tasks.rb +20 -2
  64. data/spec/spec_helper.rb +64 -11
  65. data/spec/support/helpers.rb +9 -0
  66. data/spec/unit/association/many_to_many_spec.rb +89 -0
  67. data/spec/unit/association/many_to_one_spec.rb +81 -0
  68. data/spec/unit/association/name_spec.rb +68 -0
  69. data/spec/unit/association/one_to_many_spec.rb +62 -0
  70. data/spec/unit/association/one_to_one_spec.rb +62 -0
  71. data/spec/unit/association/one_to_one_through_spec.rb +69 -0
  72. data/spec/unit/association_errors_spec.rb +2 -4
  73. data/spec/unit/gateway_spec.rb +12 -3
  74. data/spec/unit/migration_tasks_spec.rb +3 -3
  75. data/spec/unit/migrator_spec.rb +2 -4
  76. data/spec/unit/{combined_associations_spec.rb → plugin/assoc_macros/combined_associations_spec.rb} +13 -19
  77. data/spec/unit/{many_to_many_spec.rb → plugin/assoc_macros/many_to_many_spec.rb} +9 -15
  78. data/spec/unit/{many_to_one_spec.rb → plugin/assoc_macros/many_to_one_spec.rb} +9 -14
  79. data/spec/unit/plugin/assoc_macros/one_to_many_spec.rb +78 -0
  80. data/spec/unit/plugin/base_view_spec.rb +11 -11
  81. data/spec/unit/plugin/pagination_spec.rb +62 -62
  82. data/spec/unit/relation_spec.rb +218 -146
  83. data/spec/unit/schema_spec.rb +15 -14
  84. data/spec/unit/types_spec.rb +40 -0
  85. metadata +105 -21
  86. data/.rubocop.yml +0 -74
  87. data/.rubocop_todo.yml +0 -21
  88. data/spec/unit/one_to_many_spec.rb +0 -83
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 017ad7f1a32c576596913c9f86d7d5781efad7e6
4
- data.tar.gz: ee55e2a05c6733c1b10dbedad0a638c7d0da066d
3
+ metadata.gz: 5da70a1471f9c0b3a27f10cacf6af54f060090be
4
+ data.tar.gz: 1f391fdbd269bbf0df9d0af23a5fc112948ce1f2
5
5
  SHA512:
6
- metadata.gz: 1675cade8ac1b92697582e6cfd0ccd17bc3af848a2677a0fbab6e39d188d660e16b937d7d2643ffbd9d94fca60bcdb9af758255abde5af9bc7c0c3298f78790f
7
- data.tar.gz: c9bc786e8e52a805453bca55cfb3f6ca236761455d5f68d598bc476463282d8c74d4d383343693d3a1e4abefec5e444bef6cd06a4319f312c61630af33443805
6
+ metadata.gz: f91c5854d45dc52b26ddb0eaca6dc465ff02db69bd145d6ce010c6eaa93571ac46842d68a6897e0b88fffb7639efe26c94435a035c0d4a0790be37defd846fa2
7
+ data.tar.gz: 879cf6a660eb79ab84b1adbfb33ede96613d786356457182d81bc3f00f2a7165fbe939d25b7bd0755242710469cffae650976252c9c19eeda37067a89a0407ec
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --color
2
2
  --order random
3
+ --require ./spec/spec_helper
data/.travis.yml CHANGED
@@ -1,28 +1,33 @@
1
1
  language: ruby
2
2
  sudo: false
3
3
  cache: bundler
4
+ services:
5
+ - postgresql
6
+ - mysql
4
7
  bundler_args: --without yard guard benchmarks tools
5
8
  before_script:
6
9
  - psql -c 'create database rom_sql;' -U postgres
10
+ - mysql -e 'create database rom_sql;'
7
11
  script: "bundle exec rake ci"
8
12
  rvm:
9
- - 2.0
10
- - 2.1
11
- - 2.2
12
- - 2.3.0
13
+ - 2.1.9
14
+ - 2.2.5
15
+ - 2.3.1
13
16
  - rbx-2
14
- - jruby-9000
15
- - jruby-head
17
+ - jruby-9.0.5.0
16
18
  - ruby-head
17
19
  env:
18
20
  global:
19
21
  - CODECLIMATE_REPO_TOKEN=03d7f66589572702b12426d2bc71c4de6281a96139e33b335b894264b1f8f0b0
20
22
  - JRUBY_OPTS='--dev -J-Xmx1024M'
23
+ - PG_LTE_95='false'
21
24
  matrix:
22
25
  allow_failures:
23
- - rvm: jruby-9000
24
26
  - rvm: ruby-head
25
27
  - rvm: jruby-head
28
+ include:
29
+ - rvm: jruby-head
30
+ before_install: gem install bundler --no-ri --no-rdoc
26
31
  notifications:
27
32
  webhooks:
28
33
  urls:
data/CHANGELOG.md CHANGED
@@ -1,3 +1,31 @@
1
+ ## v0.8.0 2016-07-27
2
+
3
+ ### Added
4
+
5
+ * Support for relation schemas with SQL-specific data types (solnic + flash-gordon)
6
+ * One-To-Many support in schemas (solnic + flash-gordon)
7
+ * One-To-One support in schemas (solnic + flash-gordon)
8
+ * One-To-One-Through support in schemas (solnic + flash-gordon)
9
+ * Many-To-One support in schemas (solnic + flash-gordon)
10
+ * Many-To-Many support in schemas (solnic + flash-gordon)
11
+ * Support for `has_many`, `has_one` and `belongs_to` convenient methods in schema DSL (solnic)
12
+ * Support for custom PG types: `Types::PG::Array`, `Types::PG::Hash`, `Types::PG::JSON`, and `Types::PG::Bytea` (solnic + flash-gordon)
13
+ * Optional automatic schema inference for attributes and foreign keys based on DB metadata provided by Sequel (flash-gordon)
14
+ * Support for arbitrary dataset and FK names in schemas (flash-gordon)
15
+ * Support for native upserts in PostgreSQL >= 9.5 via `Commands::Postgres::Upsert` (gotar + flash-gordon)
16
+
17
+ ### Changed
18
+
19
+ * `Create` and `Update` commands have `:schema` plugin enabled by default which sets input handler based on schema definition automatically (solnic)
20
+ * `associates` command plugin uses schema associations now (solnic)
21
+ * Dropped MRI 2.0.x support
22
+
23
+ ### Fixed
24
+
25
+ * `Create` command properly materialize result when `:one` is set (AMHOL)
26
+
27
+ [Compare v0.7.0...v0.8.0](https://github.com/rom-rb/rom-sql/compare/v0.7.0...v0.8.0)
28
+
1
29
  ## v0.7.0 2016-01-06
2
30
 
3
31
  ### Added
data/Gemfile CHANGED
@@ -6,16 +6,13 @@ group :test do
6
6
  gem 'byebug', platforms: :mri
7
7
  gem 'anima', '~> 0.2.0'
8
8
  gem 'virtus'
9
- gem 'activesupport'
9
+ gem 'activesupport', '~> 4.2'
10
10
  gem 'rspec', '~> 3.1'
11
11
  gem 'codeclimate-test-reporter', require: false
12
12
  gem 'pg', platforms: [:mri, :rbx]
13
- gem 'pg_jruby', platforms: :jruby
14
- end
15
-
16
- group :tools do
17
- gem 'guard'
18
- gem 'guard-rspec'
19
- gem 'guard-rubocop'
20
- gem 'rubocop', '~> 0.28'
13
+ gem 'mysql2', platforms: [:mri, :rbx]
14
+ gem 'jdbc-postgres', platforms: :jruby
15
+ gem 'jdbc-mysql', platforms: :jruby
16
+ gem 'sqlite3', platforms: [:mri, :rbx]
17
+ gem 'jdbc-sqlite3', platforms: :jruby
21
18
  end
data/README.md CHANGED
@@ -4,11 +4,11 @@
4
4
  [codeclimate]: https://codeclimate.com/github/rom-rb/rom-sql
5
5
  [inchpages]: http://inch-ci.org/github/rom-rb/rom-sql
6
6
 
7
- # ROM::SQL
7
+ # rom-sql
8
8
 
9
9
  [![Gem Version](https://badge.fury.io/rb/rom-sql.svg)][gem]
10
10
  [![Build Status](https://travis-ci.org/rom-rb/rom-sql.svg?branch=master)][travis]
11
- [![Dependency Status](https://gemnasium.com/rom-rb/rom-sql.png)][gemnasium]
11
+ [![Dependency Status](https://gemnasium.com/rom-rb/rom-sql.svg)][gemnasium]
12
12
  [![Code Climate](https://codeclimate.com/github/rom-rb/rom-sql/badges/gpa.svg)][codeclimate]
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]
@@ -17,7 +17,8 @@ RDBMS support for [Ruby Object Mapper](https://github.com/rom-rb/rom).
17
17
 
18
18
  Resources:
19
19
 
20
- - [Guides](http://rom-rb.org/guides/adapters/sql/)
20
+ - [User Documentation](http://rom-rb.org/learn/sql/)
21
+ - [API Documentation](http://rubydoc.info/gems/rom-sql)
21
22
 
22
23
  ## Installation
23
24
 
@@ -35,7 +36,7 @@ Or install it yourself as:
35
36
 
36
37
  $ gem install rom-sql
37
38
 
38
- Check out [SQL guide](http://rom-rb.org/guides/adapters/sql/) for usage examples.
39
+ Check out [SQL guide](http://rom-rb.org/learn/adapters/sql/) for usage examples.
39
40
 
40
41
  ## ROADMAP
41
42
 
data/circle.yml ADDED
@@ -0,0 +1,10 @@
1
+ machine:
2
+ ruby:
3
+ version: 2.3.1
4
+ dependencies:
5
+ bundler:
6
+ without: [yard guard benchmarks tools]
7
+ database:
8
+ override:
9
+ - psql -c 'create database rom_sql;' -U postgres
10
+ - mysql -e 'create database rom_sql;'
@@ -16,6 +16,7 @@ module ROM
16
16
  def inherited(klass)
17
17
  super
18
18
  klass.auto_curry :for_combine
19
+ klass.auto_curry :preload
19
20
  end
20
21
  end
21
22
 
@@ -27,9 +28,21 @@ module ROM
27
28
  # @return [SQL::Relation]
28
29
  #
29
30
  # @api private
30
- def for_combine(keys, relation)
31
- pk, fk = keys.to_a.flatten
32
- where(fk => relation.map { |tuple| tuple[pk] })
31
+ def for_combine(spec)
32
+ source_key, target_key, target =
33
+ case spec
34
+ when ROM::SQL::Association
35
+ [*spec.join_keys(__registry__).flatten, spec.call(__registry__)]
36
+ else
37
+ [*spec.flatten, self]
38
+ end
39
+
40
+ target.preload(source_key, target_key)
41
+ end
42
+
43
+ # @api private
44
+ def preload(source_key, target_key, source)
45
+ where(target_key => source.pluck(source_key.to_sym))
33
46
  end
34
47
  end
35
48
  end
@@ -29,10 +29,11 @@ module ROM
29
29
  # @api private
30
30
  def for_wrap(keys, name)
31
31
  other = __registry__[name]
32
+ other_dataset = other.name.dataset
32
33
 
33
- inner_join(name, keys)
34
+ inner_join(other_dataset, keys)
34
35
  .select(*qualified.header.columns)
35
- .select_append(*other.prefix(other.name).qualified.header)
36
+ .select_append(*other.prefix(other_dataset).qualified.header)
36
37
  end
37
38
  end
38
39
  end
@@ -0,0 +1,75 @@
1
+ require 'rom/support/constants'
2
+ require 'rom/sql/qualified_attribute'
3
+ require 'rom/sql/association/name'
4
+
5
+ module ROM
6
+ module SQL
7
+ # Abstract association class
8
+ #
9
+ # @api public
10
+ class Association
11
+ include Dry::Equalizer(:source, :target, :result)
12
+ include Options
13
+ extend ClassMacros
14
+
15
+ defines :result
16
+
17
+ # @!attribute [r] source
18
+ # @return [ROM::Relation::Name] the source relation name
19
+ attr_reader :source
20
+
21
+ # @!attribute [r] target
22
+ # @return [ROM::Relation::Name] the target relation name
23
+ attr_reader :target
24
+
25
+ # @!attribute [r] relation
26
+ # @return [Symbol] an optional relation identifier for the target
27
+ option :relation, accepts: [Symbol], reader: true
28
+
29
+ # @!attribute [r] result
30
+ # @return [Symbol] either :one or :many
31
+ option :result, accepts: [Symbol], reader: true, default: -> assoc { assoc.class.result }
32
+
33
+ # @!attribute [r] as
34
+ # @return [Symbol] an optional association alias name
35
+ option :as, accepts: [Symbol], reader: true, default: -> assoc { assoc.target.to_sym }
36
+
37
+ alias_method :name, :as
38
+
39
+ # @api private
40
+ def initialize(source, target, options = EMPTY_HASH)
41
+ @source = Name[source]
42
+ @target = Name[options[:relation] || target, target, options[:as] || target]
43
+ super
44
+ end
45
+
46
+ # Returns a qualified attribute name for a given dataset
47
+ #
48
+ # This is compatible with Sequel's SQL generator and can be used in query
49
+ # DSL methods
50
+ #
51
+ # @param name [ROM::Relation::Name]
52
+ # @param attribute [Symbol]
53
+ #
54
+ # @return [QualifiedAttribute]
55
+ #
56
+ # @api public
57
+ def qualify(name, attribute)
58
+ QualifiedAttribute[name.dataset, attribute]
59
+ end
60
+
61
+ protected
62
+
63
+ # @api private
64
+ def join_key_map(relations)
65
+ join_keys(relations).to_a.flatten.map(&:to_sym)
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ require 'rom/sql/association/one_to_one'
72
+ require 'rom/sql/association/one_to_many'
73
+ require 'rom/sql/association/many_to_many'
74
+ require 'rom/sql/association/many_to_one'
75
+ require 'rom/sql/association/one_to_one_through'
@@ -0,0 +1,86 @@
1
+ module ROM
2
+ module SQL
3
+ class Association
4
+ class ManyToMany < Association
5
+ attr_reader :through
6
+
7
+ result :many
8
+
9
+ option :through, default: nil, type: Symbol
10
+
11
+ # @api private
12
+ def initialize(*)
13
+ super
14
+ @through = Relation::Name[
15
+ options[:through] || options[:through_relation], options[:through]
16
+ ]
17
+ end
18
+
19
+ # @api public
20
+ def call(relations)
21
+ join_rel = join_relation(relations)
22
+ assocs = join_rel.associations
23
+
24
+ left = assocs[target].call(relations)
25
+ right = relations[target.relation]
26
+
27
+ left_fk = join_rel.foreign_key(source.relation)
28
+
29
+ columns = right.header.exclude(left_fk).qualified.to_a
30
+ columns << left_fk unless right.header.names.include?(left_fk)
31
+
32
+ relation = left
33
+ .inner_join(source, join_keys(relations))
34
+ .select(*columns)
35
+ .order(*right.header.project(*right.primary_key).qualified)
36
+
37
+ relation.with(attributes: relation.header.names)
38
+ end
39
+
40
+ # @api public
41
+ def join_keys(relations)
42
+ with_keys(relations) { |source_key, target_key|
43
+ { qualify(source, source_key) => qualify(through, target_key) }
44
+ }
45
+ end
46
+
47
+ # @api public
48
+ def combine_keys(relations)
49
+ Hash[*with_keys(relations)]
50
+ end
51
+
52
+ # @api private
53
+ def associate(relations, children, parent)
54
+ ((spk, sfk), (tfk, tpk)) = join_key_map(relations)
55
+
56
+ children.map { |tuple|
57
+ { sfk => tuple.fetch(spk), tfk => parent.fetch(tpk) }
58
+ }
59
+ end
60
+
61
+ # @api private
62
+ def join_relation(relations)
63
+ relations[through.relation]
64
+ end
65
+
66
+ protected
67
+
68
+ # @api private
69
+ def with_keys(relations, &block)
70
+ source_key = relations[source.relation].primary_key
71
+ target_key = relations[through.relation].foreign_key(source.relation)
72
+ return [source_key, target_key] unless block
73
+ yield(source_key, target_key)
74
+ end
75
+
76
+ # @api private
77
+ def join_key_map(relations)
78
+ left = super
79
+ right = join_relation(relations).associations[target].join_key_map(relations)
80
+
81
+ [left, right]
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,60 @@
1
+ module ROM
2
+ module SQL
3
+ class Association
4
+ class ManyToOne < Association
5
+ result :one
6
+
7
+ # @api public
8
+ def call(relations)
9
+ left = relations[target.relation]
10
+ right = relations[source.relation]
11
+
12
+ right_pk = right.schema.primary_key.map { |a| a.meta[:name] }
13
+ right_fk = right.foreign_key(target.relation)
14
+
15
+ pk_to_fk = Hash[right_pk.product(Array(left.foreign_key(source.relation)))]
16
+
17
+ columns = left.header.qualified.to_a + right.header
18
+ .project(*right_pk)
19
+ .rename(pk_to_fk)
20
+ .qualified.to_a
21
+
22
+ relation = left
23
+ .inner_join(source, right_fk => left.primary_key)
24
+ .select(*columns)
25
+ .order(*right.header.project(*right.primary_key).qualified)
26
+
27
+ relation.with(attributes: relation.header.names)
28
+ end
29
+
30
+ # @api public
31
+ def combine_keys(relations)
32
+ Hash[*with_keys(relations)]
33
+ end
34
+
35
+ # @api public
36
+ def join_keys(relations)
37
+ with_keys(relations) { |source_key, target_key|
38
+ { qualify(source, source_key) => qualify(target, target_key) }
39
+ }
40
+ end
41
+
42
+ # @api private
43
+ def associate(relations, child, parent)
44
+ fk, pk = join_key_map(relations)
45
+ child.merge(fk => parent.fetch(pk))
46
+ end
47
+
48
+ protected
49
+
50
+ # @api private
51
+ def with_keys(relations, &block)
52
+ source_key = relations[source.relation].foreign_key(target.relation)
53
+ target_key = relations[target.relation].primary_key
54
+ return [source_key, target_key] unless block
55
+ yield(source_key, target_key)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,70 @@
1
+ require 'dry/equalizer'
2
+ require 'rom/relation/name'
3
+ require 'rom/support/cache'
4
+
5
+ module ROM
6
+ module SQL
7
+ class Association
8
+ class Name
9
+ include Dry::Equalizer.new(:relation_name, :key)
10
+
11
+ extend Cache
12
+
13
+ attr_reader :relation_name
14
+
15
+ attr_reader :key
16
+
17
+ alias_method :to_sym, :key
18
+
19
+ def self.[](*args)
20
+ fetch_or_store(args) do
21
+ rel, ds, aliaz = args
22
+
23
+ if rel.is_a?(ROM::Relation::Name)
24
+ new(rel, rel.dataset)
25
+ elsif rel.is_a?(self)
26
+ rel
27
+ elsif aliaz
28
+ new(ROM::Relation::Name[rel, ds], aliaz)
29
+ elsif ds.nil?
30
+ new(ROM::Relation::Name[rel], rel)
31
+ else
32
+ new(ROM::Relation::Name[rel, ds], ds)
33
+ end
34
+ end
35
+ end
36
+
37
+ def initialize(relation_name, aliaz)
38
+ @relation_name = relation_name
39
+ @aliased = relation_name.dataset != aliaz
40
+ @key = aliased? ? aliaz : relation_name.dataset
41
+ end
42
+
43
+ def aliased?
44
+ @aliased
45
+ end
46
+
47
+ def inspect
48
+ if aliased?
49
+ "#{self.class}(#{relation_name.to_s} as #{key})"
50
+ else
51
+ "#{self.class}(#{relation_name.to_s})"
52
+ end
53
+ end
54
+ alias_method :to_s, :inspect
55
+
56
+ def dataset
57
+ relation_name.dataset
58
+ end
59
+
60
+ def relation
61
+ relation_name.relation
62
+ end
63
+
64
+ def sql_literal_append(ds, sql)
65
+ ds.literal_append(sql, dataset)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end