rom-sql 0.3.2 → 0.4.0.beta1

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +55 -18
  4. data/.rubocop_todo.yml +15 -0
  5. data/.travis.yml +10 -5
  6. data/CHANGELOG.md +18 -0
  7. data/Gemfile +8 -1
  8. data/Guardfile +24 -0
  9. data/README.md +14 -22
  10. data/Rakefile +13 -5
  11. data/lib/rom/sql.rb +5 -5
  12. data/lib/rom/sql/commands.rb +7 -49
  13. data/lib/rom/sql/commands/create.rb +29 -0
  14. data/lib/rom/sql/commands/delete.rb +18 -0
  15. data/lib/rom/sql/commands/transaction.rb +17 -0
  16. data/lib/rom/sql/commands/update.rb +54 -0
  17. data/lib/rom/sql/commands_ext/postgres.rb +24 -0
  18. data/lib/rom/sql/header.rb +8 -9
  19. data/lib/rom/sql/migration.rb +26 -0
  20. data/lib/rom/sql/plugin/pagination.rb +93 -0
  21. data/lib/rom/sql/rake_task.rb +2 -0
  22. data/lib/rom/sql/relation.rb +320 -0
  23. data/lib/rom/sql/relation/associations.rb +104 -0
  24. data/lib/rom/sql/relation/class_methods.rb +47 -0
  25. data/lib/rom/sql/relation/inspection.rb +16 -0
  26. data/lib/rom/sql/repository.rb +59 -0
  27. data/lib/rom/sql/support/rails_log_subscriber.rb +1 -1
  28. data/lib/rom/sql/tasks/migration_tasks.rake +56 -0
  29. data/lib/rom/sql/version.rb +1 -1
  30. data/rom-sql.gemspec +2 -3
  31. data/spec/integration/commands/create_spec.rb +66 -8
  32. data/spec/integration/commands/delete_spec.rb +22 -3
  33. data/spec/integration/commands/update_spec.rb +57 -6
  34. data/spec/integration/read_spec.rb +42 -1
  35. data/spec/shared/database_setup.rb +10 -5
  36. data/spec/spec_helper.rb +17 -0
  37. data/spec/support/active_support_notifications_spec.rb +5 -4
  38. data/spec/support/rails_log_subscriber_spec.rb +2 -2
  39. data/spec/unit/logger_spec.rb +5 -3
  40. data/spec/unit/many_to_many_spec.rb +2 -2
  41. data/spec/unit/migration_spec.rb +34 -0
  42. data/spec/unit/migration_tasks_spec.rb +99 -0
  43. data/spec/unit/one_to_many_spec.rb +0 -2
  44. data/spec/unit/plugin/pagination_spec.rb +73 -0
  45. data/spec/unit/relation_spec.rb +49 -3
  46. data/spec/unit/repository_spec.rb +33 -0
  47. data/spec/unit/schema_spec.rb +5 -17
  48. metadata +32 -35
  49. data/lib/rom/sql/adapter.rb +0 -100
  50. data/lib/rom/sql/relation_inclusion.rb +0 -149
  51. data/lib/rom/sql/support/sequel_dataset_ext.rb +0 -33
  52. data/spec/unit/adapter_spec.rb +0 -48
  53. data/spec/unit/config_spec.rb +0 -54
@@ -3,7 +3,8 @@ require 'spec_helper'
3
3
  describe ROM::Relation do
4
4
  include_context 'users and tasks'
5
5
 
6
- subject(:users) { rom.relations.users }
6
+ let(:users) { rom.relations.users }
7
+ let(:tasks) { rom.relations.tasks }
7
8
 
8
9
  before do
9
10
  setup.relation(:users) do
@@ -13,6 +14,39 @@ describe ROM::Relation do
13
14
  end
14
15
  end
15
16
 
17
+ describe '#map' do
18
+ it 'yields tuples' do
19
+ result = []
20
+ users.map { |tuple| result << tuple }
21
+ expect(result).to eql([{ id: 1, name: 'Piotr' }])
22
+ end
23
+ end
24
+
25
+ describe '#inner_join' do
26
+ it 'joins relations using inner join' do
27
+ conn[:users].insert(id: 2, name: 'Jane')
28
+
29
+ result = users.inner_join(:tasks, user_id: :id).select(:name, :title)
30
+
31
+ expect(result.to_a).to match_array([
32
+ { name: 'Piotr', title: 'Finish ROM' }
33
+ ])
34
+ end
35
+ end
36
+
37
+ describe '#left_join' do
38
+ it 'joins relations using left outer join' do
39
+ conn[:users].insert(id: 2, name: 'Jane')
40
+
41
+ result = users.left_join(:tasks, user_id: :id).select(:name, :title)
42
+
43
+ expect(result.to_a).to match_array([
44
+ { name: 'Piotr', title: 'Finish ROM' },
45
+ { name: 'Jane', title: nil }
46
+ ])
47
+ end
48
+ end
49
+
16
50
  describe '#project' do
17
51
  it 'projects the dataset using new column names' do
18
52
  projected = users.sorted.project(:name)
@@ -59,9 +93,21 @@ describe ROM::Relation do
59
93
  end
60
94
 
61
95
  describe '#inspect' do
62
- it 'includes dataset and header' do
63
- expect(users.inspect).to include('header')
96
+ it 'includes dataset' do
64
97
  expect(users.inspect).to include('dataset')
65
98
  end
66
99
  end
100
+
101
+ describe '#unique?' do
102
+ before { tasks.delete }
103
+
104
+ it 'returns true when there is only one tuple matching criteria' do
105
+ expect(tasks.unique?(title: 'Task One')).to be(true)
106
+ end
107
+
108
+ it 'returns true when there are more than one tuple matching criteria' do
109
+ tasks.insert(title: 'Task One')
110
+ expect(tasks.unique?(title: 'Task One')).to be(false)
111
+ end
112
+ end
67
113
  end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ require 'rom/lint/spec'
4
+
5
+ describe ROM::SQL::Repository do
6
+ include_context 'users and tasks'
7
+
8
+ let(:repository) { rom.repositories[:default] }
9
+
10
+ it_behaves_like 'a rom repository' do
11
+ let(:identifier) { :sql }
12
+ let(:repository) { ROM::SQL::Repository }
13
+ let(:uri) { 'postgres://localhost/rom' }
14
+ end
15
+
16
+ describe '#dataset?' do
17
+ it 'returns true if a table exists' do
18
+ expect(repository.dataset?(:users)).to be(true)
19
+ end
20
+
21
+ it 'returns false if a table does not exist' do
22
+ expect(repository.dataset?(:not_here)).to be(false)
23
+ end
24
+ end
25
+
26
+ describe '#disconnect' do
27
+ it 'disconnects via sequel connection' do
28
+ # FIXME: no idea how to test it in a different way
29
+ expect(repository.connection).to receive(:disconnect)
30
+ repository.disconnect
31
+ end
32
+ end
33
+ end
@@ -1,32 +1,20 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'Inferring schema from database' do
4
- let(:setup) { ROM.setup(postgres: "postgres://localhost/rom") }
4
+ include_context 'database setup'
5
5
 
6
6
  context "when database schema exists" do
7
- after { rom.postgres.connection.drop_table?(:people) }
8
-
9
- let(:rom) { setup.finalize }
10
-
11
7
  it "infers the schema from the database relations" do
12
- setup.postgres.connection.create_table :people do
13
- primary_key :id
14
- String :name
15
- end
16
-
17
- schema = rom.schema
18
-
19
- expect(schema.people.to_a).to eql(rom.postgres.people.to_a)
20
- expect(schema.people.header).to eql([:id, :name])
8
+ expect(rom.relations.users.to_a)
9
+ .to eql(rom.repositories[:default][:users].to_a)
21
10
  end
22
11
  end
23
12
 
24
13
  context "for empty database schemas" do
25
14
  it "returns an empty schema" do
26
- rom = setup.finalize
27
- schema = rom.schema
15
+ drop_tables
28
16
 
29
- expect { schema.postgres }.to raise_error(NoMethodError)
17
+ expect { rom.not_here }.to raise_error(NoMethodError)
30
18
  end
31
19
  end
32
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rom-sql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-01 00:00:00.000000000 Z
11
+ date: 2015-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '4.17'
19
+ version: '4.18'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '4.17'
26
+ version: '4.18'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: equalizer
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -50,20 +50,14 @@ dependencies:
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '0.5'
54
- - - ">="
55
- - !ruby/object:Gem::Version
56
- version: 0.5.0
53
+ version: 0.6.0.beta1
57
54
  type: :runtime
58
55
  prerelease: false
59
56
  version_requirements: !ruby/object:Gem::Requirement
60
57
  requirements:
61
58
  - - "~>"
62
59
  - !ruby/object:Gem::Version
63
- version: '0.5'
64
- - - ">="
65
- - !ruby/object:Gem::Version
66
- version: 0.5.0
60
+ version: 0.6.0.beta1
67
61
  - !ruby/object:Gem::Dependency
68
62
  name: bundler
69
63
  requirement: !ruby/object:Gem::Requirement
@@ -92,20 +86,6 @@ dependencies:
92
86
  - - "~>"
93
87
  - !ruby/object:Gem::Version
94
88
  version: '10.0'
95
- - !ruby/object:Gem::Dependency
96
- name: rubocop
97
- requirement: !ruby/object:Gem::Requirement
98
- requirements:
99
- - - "~>"
100
- - !ruby/object:Gem::Version
101
- version: 0.28.0
102
- type: :development
103
- prerelease: false
104
- version_requirements: !ruby/object:Gem::Requirement
105
- requirements:
106
- - - "~>"
107
- - !ruby/object:Gem::Version
108
- version: 0.28.0
109
89
  description: SQL databases support for ROM
110
90
  email:
111
91
  - piotr.solnica@gmail.com
@@ -116,22 +96,35 @@ files:
116
96
  - ".gitignore"
117
97
  - ".rspec"
118
98
  - ".rubocop.yml"
99
+ - ".rubocop_todo.yml"
119
100
  - ".travis.yml"
120
101
  - CHANGELOG.md
121
102
  - Gemfile
103
+ - Guardfile
122
104
  - LICENSE.txt
123
105
  - README.md
124
106
  - Rakefile
125
107
  - lib/rom-sql.rb
126
108
  - lib/rom/sql.rb
127
- - lib/rom/sql/adapter.rb
128
109
  - lib/rom/sql/commands.rb
110
+ - lib/rom/sql/commands/create.rb
111
+ - lib/rom/sql/commands/delete.rb
112
+ - lib/rom/sql/commands/transaction.rb
113
+ - lib/rom/sql/commands/update.rb
114
+ - lib/rom/sql/commands_ext/postgres.rb
129
115
  - lib/rom/sql/header.rb
130
- - lib/rom/sql/relation_inclusion.rb
116
+ - lib/rom/sql/migration.rb
117
+ - lib/rom/sql/plugin/pagination.rb
118
+ - lib/rom/sql/rake_task.rb
119
+ - lib/rom/sql/relation.rb
120
+ - lib/rom/sql/relation/associations.rb
121
+ - lib/rom/sql/relation/class_methods.rb
122
+ - lib/rom/sql/relation/inspection.rb
123
+ - lib/rom/sql/repository.rb
131
124
  - lib/rom/sql/spec/support.rb
132
125
  - lib/rom/sql/support/active_support_notifications.rb
133
126
  - lib/rom/sql/support/rails_log_subscriber.rb
134
- - lib/rom/sql/support/sequel_dataset_ext.rb
127
+ - lib/rom/sql/tasks/migration_tasks.rake
135
128
  - lib/rom/sql/version.rb
136
129
  - log/.gitkeep
137
130
  - rom-sql.gemspec
@@ -144,14 +137,16 @@ files:
144
137
  - spec/spec_helper.rb
145
138
  - spec/support/active_support_notifications_spec.rb
146
139
  - spec/support/rails_log_subscriber_spec.rb
147
- - spec/unit/adapter_spec.rb
148
140
  - spec/unit/combined_associations_spec.rb
149
- - spec/unit/config_spec.rb
150
141
  - spec/unit/logger_spec.rb
151
142
  - spec/unit/many_to_many_spec.rb
152
143
  - spec/unit/many_to_one_spec.rb
144
+ - spec/unit/migration_spec.rb
145
+ - spec/unit/migration_tasks_spec.rb
153
146
  - spec/unit/one_to_many_spec.rb
147
+ - spec/unit/plugin/pagination_spec.rb
154
148
  - spec/unit/relation_spec.rb
149
+ - spec/unit/repository_spec.rb
155
150
  - spec/unit/schema_spec.rb
156
151
  homepage: http://rom-rb.org
157
152
  licenses:
@@ -168,9 +163,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
168
163
  version: '0'
169
164
  required_rubygems_version: !ruby/object:Gem::Requirement
170
165
  requirements:
171
- - - ">="
166
+ - - ">"
172
167
  - !ruby/object:Gem::Version
173
- version: '0'
168
+ version: 1.3.1
174
169
  requirements: []
175
170
  rubyforge_project:
176
171
  rubygems_version: 2.2.2
@@ -187,13 +182,15 @@ test_files:
187
182
  - spec/spec_helper.rb
188
183
  - spec/support/active_support_notifications_spec.rb
189
184
  - spec/support/rails_log_subscriber_spec.rb
190
- - spec/unit/adapter_spec.rb
191
185
  - spec/unit/combined_associations_spec.rb
192
- - spec/unit/config_spec.rb
193
186
  - spec/unit/logger_spec.rb
194
187
  - spec/unit/many_to_many_spec.rb
195
188
  - spec/unit/many_to_one_spec.rb
189
+ - spec/unit/migration_spec.rb
190
+ - spec/unit/migration_tasks_spec.rb
196
191
  - spec/unit/one_to_many_spec.rb
192
+ - spec/unit/plugin/pagination_spec.rb
197
193
  - spec/unit/relation_spec.rb
194
+ - spec/unit/repository_spec.rb
198
195
  - spec/unit/schema_spec.rb
199
196
  has_rdoc:
@@ -1,100 +0,0 @@
1
- require 'logger'
2
-
3
- require 'rom/sql/commands'
4
-
5
- module ROM
6
- module SQL
7
- class Adapter < ROM::Adapter
8
- attr_reader :logger
9
-
10
- def self.schemes
11
- [:ado, :amalgalite, :cubrid, :db2, :dbi, :do, :fdbsql, :firebird,
12
- :ibmdb, :informix, :jdbc, :mysql, :mysql2, :odbc, :openbase, :oracle,
13
- :postgres, :sqlanywhere, :sqlite, :sqlite3, :swift, :tinytds]
14
- end
15
-
16
- def self.normalize_scheme(input)
17
- scheme = input.dup
18
- scheme = 'sqlite' if scheme == 'sqlite3'
19
-
20
- if RUBY_ENGINE == 'jruby' && scheme != 'postgres'
21
- scheme.prepend('jdbc:')
22
- end
23
-
24
- scheme
25
- end
26
-
27
- def self.database_file?(scheme)
28
- scheme.to_s.include?('sqlite')
29
- end
30
-
31
- def initialize(*args)
32
- super
33
- @connection = ::Sequel.connect(uri.to_s, options)
34
- end
35
-
36
- def disconnect
37
- connection.disconnect
38
- end
39
-
40
- def [](name)
41
- connection[name]
42
- end
43
-
44
- def logger=(logger)
45
- @logger = logger
46
- connection.loggers << logger
47
- end
48
-
49
- def schema
50
- tables.map { |table| [table, dataset(table), columns(table)] }
51
- end
52
-
53
- def dataset?(name)
54
- tables.include?(name)
55
- end
56
-
57
- def extend_relation_class(klass)
58
- klass.send(:include, RelationInclusion)
59
- end
60
-
61
- def extend_relation_instance(relation)
62
- model = relation.model
63
- model.set_dataset(relation.dataset)
64
- model.dataset.naked!
65
- end
66
-
67
- def command_namespace
68
- SQL::Commands
69
- end
70
-
71
- private
72
-
73
- def tables
74
- connection.tables
75
- end
76
-
77
- def columns(table)
78
- dataset(table).columns
79
- end
80
-
81
- def dataset(table)
82
- connection[table]
83
- end
84
-
85
- def attributes(table)
86
- map_attribute_types connection.schema(table)
87
- end
88
-
89
- def map_attribute_types(attrs)
90
- attrs.map do |column, opts|
91
- [column, { type: map_schema_type(opts[:type]) }]
92
- end.to_h
93
- end
94
-
95
- def map_schema_type(type)
96
- connection.class::SCHEMA_TYPE_CLASSES.fetch(type)
97
- end
98
- end
99
- end
100
- end
@@ -1,149 +0,0 @@
1
- module ROM
2
- module SQL
3
- # Sequel-specific relation extensions
4
- #
5
- module RelationInclusion
6
- def self.included(klass)
7
- klass.extend(AssociationDSL)
8
-
9
- klass.send(:undef_method, :select)
10
- klass.send(:attr_reader, :model)
11
-
12
- klass.class_eval do
13
- class << self
14
- attr_accessor :model
15
- end
16
-
17
- self.model = Class.new(Sequel::Model)
18
- end
19
- end
20
-
21
- def initialize(*args)
22
- super
23
- @model = self.class.model
24
- @header = dataset.header
25
- end
26
-
27
- # Join configured association.
28
- #
29
- # Uses INNER JOIN type.
30
- #
31
- # @example
32
- #
33
- # setup.relation(:tasks)
34
- #
35
- # setup.relations(:users) do
36
- # one_to_many :tasks, key: :user_id
37
- #
38
- # def with_tasks
39
- # association_join(:tasks, select: [:title])
40
- # end
41
- # end
42
- #
43
- # @api public
44
- def association_join(name, options = {})
45
- graph_join(name, :inner, options)
46
- end
47
-
48
- # Join configured association
49
- #
50
- # Uses LEFT JOIN type.
51
- #
52
- # @example
53
- #
54
- # setup.relation(:tasks)
55
- #
56
- # setup.relations(:users) do
57
- # one_to_many :tasks, key: :user_id
58
- #
59
- # def with_tasks
60
- # association_left_join(:tasks, select: [:title])
61
- # end
62
- # end
63
- #
64
- # @api public
65
- def association_left_join(name, options = {})
66
- graph_join(name, :left_outer, options)
67
- end
68
-
69
- # @api private
70
- def primary_key
71
- model.primary_key
72
- end
73
-
74
- # @api private
75
- def graph_join(name, join_type, options = {})
76
- assoc = model.association_reflection(name)
77
-
78
- key = assoc[:key]
79
- type = assoc[:type]
80
-
81
- if type == :many_to_many
82
- select = options[:select] || {}
83
-
84
- l_select, r_select =
85
- if select.is_a?(Hash)
86
- [select[assoc[:join_table]] || [], select[name]]
87
- else
88
- [[], select]
89
- end
90
-
91
- l_graph = graph(
92
- assoc[:join_table],
93
- { assoc[:left_key] => primary_key },
94
- select: l_select, implicit_qualifier: self.name
95
- )
96
-
97
- l_graph.graph(
98
- name, { primary_key => assoc[:right_key] }, select: r_select
99
- )
100
- else
101
- join_keys =
102
- if type == :many_to_one
103
- { primary_key => key }
104
- else
105
- { key => primary_key }
106
- end
107
-
108
- graph(
109
- name,
110
- join_keys,
111
- options.merge(join_type: join_type, implicit_qualifier: self.name)
112
- )
113
- end
114
- end
115
-
116
- module AssociationDSL
117
- def one_to_many(name, options)
118
- associations << [__method__, name, options.merge(relation: name)]
119
- end
120
-
121
- def many_to_many(name, options = {})
122
- associations << [__method__, name, options.merge(relation: name)]
123
- end
124
-
125
- def many_to_one(name, options = {})
126
- new_options = options.merge(relation: Inflecto.pluralize(name).to_sym)
127
- associations << [__method__, name, new_options]
128
- end
129
-
130
- def finalize(relations, relation)
131
- associations.each do |*args, options|
132
- model = relation.model
133
- other = relations[options.fetch(:relation)].model
134
-
135
- model.public_send(*args, options.merge(class: other))
136
- end
137
-
138
- model.freeze
139
-
140
- super
141
- end
142
-
143
- def associations
144
- @associations ||= []
145
- end
146
- end
147
- end
148
- end
149
- end