sequel-inline_schema 0.0.1

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.
@@ -0,0 +1,401 @@
1
+ #!/usr/bin/env rspec -cfd
2
+ #encoding: utf-8
3
+
4
+ require_relative '../../spec_helper'
5
+
6
+ require 'securerandom'
7
+
8
+ require 'loggability'
9
+ require 'pg'
10
+ require 'rspec'
11
+ require 'sequel/plugins/inline_schema'
12
+
13
+
14
+ describe Sequel::Plugins::InlineSchema do
15
+
16
+ let( :db ) do
17
+ Sequel.mock( host: 'postgres', columns: nil, logger: Loggability.logger )
18
+ end
19
+
20
+ let( :table ) do
21
+ name = "test_table_%s" % [ SecureRandom.hex(8) ]
22
+ name.to_sym
23
+ end
24
+
25
+ let( :model_class ) do
26
+ mclass = Class.new( Sequel::Model )
27
+ mclass.set_dataset( db[table] )
28
+ mclass.plugin( :inline_schema )
29
+ mclass
30
+ end
31
+
32
+ let( :valid_pg_attributes ) do
33
+ [
34
+ {
35
+ name: "id",
36
+ oid: 23,
37
+ base_oid: nil,
38
+ db_base_type: nil,
39
+ db_type: "integer",
40
+ default: "nextval('people_id_seq'::regclass)",
41
+ allow_null: false,
42
+ primary_key: true,
43
+ },
44
+ {
45
+ name: "name",
46
+ oid: 25,
47
+ base_oid: nil,
48
+ db_base_type: nil,
49
+ db_type: "text",
50
+ default: nil,
51
+ allow_null: false,
52
+ primary_key: false,
53
+ },
54
+ {
55
+ name: "age",
56
+ oid: 23,
57
+ base_oid: nil,
58
+ db_base_type: nil,
59
+ db_type: "integer",
60
+ default: nil,
61
+ allow_null: false,
62
+ primary_key: false,
63
+ }
64
+ ]
65
+ end
66
+
67
+ let( :fake_db_fetcher ) do
68
+ created = false
69
+ Proc.new do |query|
70
+ case query
71
+ when /pg_attribute/
72
+ created ? [] : valid_pg_attributes
73
+ when /SELECT \* FROM "test_table/
74
+ if created
75
+ [{ id: 1, name: 'name', age: 20}]
76
+ else
77
+ raise PG::UndefinedTable.new( "No such table." )
78
+ end
79
+ when /SELECT NULL/
80
+ if created
81
+ {nil: nil}
82
+ else
83
+ raise PG::UndefinedTable.new("No such table.")
84
+ end
85
+ when /CREATE TABLE/
86
+ created = true
87
+ else
88
+ fail "Unhandled query"
89
+ end
90
+ end
91
+ end
92
+
93
+
94
+ it "sets require_valid_table to false when it declares a schema" do
95
+ model_class.set_schema { primary_key :id }
96
+ expect( model_class.require_valid_table ).to be_falsey
97
+ end
98
+
99
+
100
+ it "doesn't set require_valid_table if require_table is true" do
101
+ model_class.set_schema( require_table: true ) { primary_key :id }
102
+ expect( model_class.require_valid_table ).to be_truthy
103
+ end
104
+
105
+
106
+ it "allows a model to create its table" do
107
+ model_class.set_schema do
108
+ primary_key :id
109
+ String :name
110
+ Integer :age
111
+ end
112
+ db.fetch = fake_db_fetcher
113
+
114
+ model_class.create_table
115
+
116
+ expect( db.sqls ).to include(
117
+ %{CREATE TABLE "#{table}" ("id" serial PRIMARY KEY, "name" text, "age" integer)}
118
+ )
119
+ end
120
+
121
+
122
+ it "allows a model to re-create its table" do
123
+ model_class.set_schema do
124
+ primary_key :id
125
+ String :name
126
+ Integer :age
127
+ end
128
+ db.fetch = fake_db_fetcher
129
+
130
+ model_class.create_table!
131
+
132
+ expect( db.sqls ).to include(
133
+ %{DROP TABLE IF EXISTS "#{table}"},
134
+ %{CREATE TABLE "#{table}" ("id" serial PRIMARY KEY, "name" text, "age" integer)}
135
+ )
136
+ end
137
+
138
+
139
+ it "allows a model to create its table if it doesn't yet exist" do
140
+ model_class.set_schema do
141
+ primary_key :id
142
+ String :name
143
+ Integer :age
144
+ end
145
+ db.fetch = fake_db_fetcher
146
+
147
+ model_class.create_table?
148
+
149
+ expect( db.sqls ).to include(
150
+ %{CREATE TABLE "#{table}" ("id" serial PRIMARY KEY, "name" text, "age" integer)}
151
+ )
152
+ end
153
+
154
+
155
+ it "allows a model to declare its schema when it creates its table" do
156
+ model_class.create_table do
157
+ primary_key :id
158
+ String :name
159
+ Integer :age
160
+ end
161
+
162
+ expect( db.sqls ).to include(
163
+ %{CREATE TABLE "#{table}" ("id" serial PRIMARY KEY, "name" text, "age" integer)}
164
+ )
165
+ end
166
+
167
+
168
+ it "allows a model to determine whether its table exists or not" do
169
+ model_class.table_exists?
170
+ expect( db.sqls ).to include(
171
+ %{SELECT NULL AS "nil" FROM "#{table}" LIMIT 1}
172
+ )
173
+ end
174
+
175
+
176
+ it "allows a model to drop its table" do
177
+ model_class.drop_table
178
+ expect( db.sqls ).to include( %{DROP TABLE "#{table}"} )
179
+ end
180
+
181
+
182
+ describe "table-creation ordering" do
183
+
184
+ let( :fake_db_fetcher ) do
185
+ created = false
186
+ Proc.new do |query|
187
+ case query
188
+ when /pg_attribute/
189
+ created ? [] : valid_pg_attributes
190
+ when /SELECT \* FROM "test_table/
191
+ if created
192
+ [{ id: 1, name: 'name'}]
193
+ else
194
+ raise PG::UndefinedTable.new( "No such table." )
195
+ end
196
+ when /SELECT NULL/
197
+ if created
198
+ {nil: nil}
199
+ else
200
+ raise PG::UndefinedTable.new("No such table.")
201
+ end
202
+ when /CREATE TABLE/
203
+ created = true
204
+ else
205
+ fail "Unhandled query"
206
+ end
207
+ end
208
+ end
209
+
210
+ let( :base_class ) do
211
+ mclass = Class.new( Sequel::Model )
212
+ mclass.plugin( :inline_schema )
213
+ mclass
214
+ end
215
+
216
+ let!( :artist_class ) do
217
+ mclass = Class.new( base_class ) do
218
+ def self::name; "Artist"; end
219
+ end
220
+ mclass.set_dataset( db[:artists] )
221
+ mclass.set_schema do
222
+ primary_key :id
223
+ String :name
224
+ end
225
+ mclass
226
+ end
227
+
228
+ let!( :song_class ) do
229
+ mclass = Class.new( base_class ) do
230
+ def self::name; "Song"; end
231
+ end
232
+ mclass.set_dataset( db[:songs] )
233
+ mclass.set_schema do
234
+ primary_key :id
235
+ String :name
236
+ foreign_key :album_id, :albums
237
+ end
238
+ mclass.many_to_one :album, class: album_class
239
+ mclass
240
+ end
241
+
242
+ let!( :album_class ) do
243
+ mclass = Class.new( base_class ) do
244
+ def self::name; "Album"; end
245
+ end
246
+ mclass.set_dataset( db[:albums] )
247
+ mclass.set_schema do
248
+ primary_key :id
249
+ String :name
250
+ foreign_key :artist_id, :artists
251
+ end
252
+ mclass.many_to_one :artist, class: artist_class
253
+ mclass
254
+ end
255
+
256
+
257
+
258
+ it "returns model classes whose tables need to be created in dependency order" do
259
+ db.fetch = fake_db_fetcher
260
+ expect( base_class.uninstalled_tables ).to eq([
261
+ artist_class, album_class, song_class
262
+ ])
263
+ end
264
+
265
+
266
+ end
267
+
268
+
269
+ describe "hooks" do
270
+
271
+ let( :model_class ) do
272
+ class_obj = super()
273
+ class_obj.singleton_class.send( :attr_accessor, :called )
274
+ class_obj.called = {}
275
+ class_obj
276
+ end
277
+
278
+
279
+ it "calls a hook before creating the model's table" do
280
+ def model_class.before_create_table
281
+ self.called[ :before_create_table ] = true
282
+ super
283
+ end
284
+
285
+ model_class.create_table
286
+
287
+ expect( model_class.called ).to include( :before_create_table )
288
+ end
289
+
290
+
291
+ it "allows cancellation of create_table from the before_create_table hook" do
292
+ def model_class.before_create_table
293
+ self.called[ :before_create_table ] = true
294
+ cancel_action
295
+ end
296
+
297
+ expect {
298
+ model_class.create_table
299
+ }.to raise_error( Sequel::HookFailed, /hook failed/i )
300
+ end
301
+
302
+
303
+ it "allows cancellation of create_table with a message from the before_create_table hook" do
304
+ def model_class.before_create_table
305
+ self.called[ :before_create_table ] = true
306
+ cancel_action( "Wait, don't create yet!" )
307
+ end
308
+
309
+ expect {
310
+ model_class.create_table
311
+ }.to raise_error( Sequel::HookFailed, "Wait, don't create yet!" )
312
+ end
313
+
314
+
315
+ it "allows cancellation of create_table with a Symbol from the before_create_table hook" do
316
+ def model_class.before_create_table
317
+ self.called[ :before_create_table ] = true
318
+ cancel_action( :before_create_table )
319
+ end
320
+
321
+ expect {
322
+ model_class.create_table
323
+ }.to raise_error( Sequel::HookFailed, /before_create_table/ )
324
+ end
325
+
326
+
327
+ it "calls a hook after table creation" do
328
+ def model_class.after_create_table
329
+ super
330
+ self.called[ :after_create_table ] = true
331
+ end
332
+
333
+ model_class.create_table
334
+
335
+ expect( model_class.called ).to include( :after_create_table )
336
+ end
337
+
338
+
339
+ it "calls a hook before dropping the model's table" do
340
+ def model_class.before_drop_table
341
+ self.called[ :before_drop_table ] = true
342
+ super
343
+ end
344
+
345
+ model_class.drop_table
346
+
347
+ expect( model_class.called ).to include( :before_drop_table )
348
+ end
349
+
350
+
351
+ it "allows cancellation of drop_table from the before_drop_table hook" do
352
+ def model_class.before_drop_table
353
+ self.called[ :before_drop_table ] = true
354
+ cancel_action
355
+ end
356
+
357
+ expect {
358
+ model_class.drop_table
359
+ }.to raise_error( Sequel::HookFailed, /hook failed/i )
360
+ end
361
+
362
+
363
+ it "allows cancellation of drop_table with a message from the before_drop_table hook" do
364
+ def model_class.before_drop_table
365
+ self.called[ :before_drop_table ] = true
366
+ cancel_action( "Wait, don't drop yet!" )
367
+ end
368
+
369
+ expect {
370
+ model_class.drop_table
371
+ }.to raise_error( Sequel::HookFailed, "Wait, don't drop yet!" )
372
+ end
373
+
374
+
375
+ it "allows cancellation of drop_table with a Symbol from the before_drop_table hook" do
376
+ def model_class.before_drop_table
377
+ self.called[ :before_drop_table ] = true
378
+ cancel_action( :before_drop_table )
379
+ end
380
+
381
+ expect {
382
+ model_class.drop_table
383
+ }.to raise_error( Sequel::HookFailed, /before_drop_table/ )
384
+ end
385
+
386
+
387
+ it "calls a hook after a class's table is dropped" do
388
+ def model_class.after_drop_table
389
+ super
390
+ self.called[ :after_drop_table ] = true
391
+ end
392
+
393
+ model_class.drop_table
394
+
395
+ expect( model_class.called ).to include( :after_drop_table )
396
+ end
397
+
398
+ end
399
+
400
+ end
401
+
@@ -0,0 +1,24 @@
1
+ # -*- ruby -*-
2
+ #encoding: utf-8
3
+
4
+ require 'simplecov' if ENV['COVERAGE']
5
+
6
+ require 'pg'
7
+ require 'rspec'
8
+ require 'sequel'
9
+ require 'loggability/spechelpers'
10
+
11
+
12
+ # Mock with RSpec
13
+ RSpec.configure do |config|
14
+ config.run_all_when_everything_filtered = true
15
+ config.filter_run :focus
16
+ config.order = 'random'
17
+ config.mock_with( :rspec ) do |mock|
18
+ mock.syntax = :expect
19
+ end
20
+
21
+ config.include( Loggability::SpecHelpers )
22
+ end
23
+
24
+
metadata ADDED
@@ -0,0 +1,217 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sequel-inline_schema
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Michael Granger
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIEbDCCAtSgAwIBAgIBATANBgkqhkiG9w0BAQUFADA+MQwwCgYDVQQDDANnZWQx
14
+ GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
15
+ HhcNMTcwOTI3MDAzMDQ0WhcNMTgwOTI3MDAzMDQ0WjA+MQwwCgYDVQQDDANnZWQx
16
+ GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
17
+ ggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC/JWGRHO+USzR97vXjkFgt
18
+ 83qeNf2KHkcvrRTSnR64i6um/ziin0I0oX23H7VYrDJC9A/uoUa5nGRJS5Zw/+wW
19
+ ENcvWVZS4iUzi4dsYJGY6yEOsXh2CcF46+QevV8iE+UmbkU75V7Dy1JCaUOyizEt
20
+ TH5UHsOtUU7k9TYARt/TgYZKuaoAMZZd5qyVqhF1vV+7/Qzmp89NGflXf2xYP26a
21
+ 4MAX2qqKX/FKXqmFO+AGsbwYTEds1mksBF3fGsFgsQWxftG8GfZQ9+Cyu2+l1eOw
22
+ cZ+lPcg834G9DrqW2zhqUoLr1MTly4pqxYGb7XoDhoR7dd1kFE2a067+DzWC/ADt
23
+ +QkcqWUm5oh1fN0eqr7NsZlVJDulFgdiiYPQiIN7UNsii4Wc9aZqBoGcYfBeQNPZ
24
+ soo/6za/bWajOKUmDhpqvaiRv9EDpVLzuj53uDoukMMwxCMfgb04+ckQ0t2G7wqc
25
+ /D+K9JW9DDs3Yjgv9k4h7YMhW5gftosd+NkNC/+Y2CkCAwEAAaN1MHMwCQYDVR0T
26
+ BAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFHKN/nkRusdqCJEuq3lgB3fJvyTg
27
+ MBwGA1UdEQQVMBOBEWdlZEBGYWVyaWVNVUQub3JnMBwGA1UdEgQVMBOBEWdlZEBG
28
+ YWVyaWVNVUQub3JnMA0GCSqGSIb3DQEBBQUAA4IBgQB/qyi5pCjK8ceoKalfVAjS
29
+ vG64FEnLnD1bm39T5UaFIRmo+abZtfpg2QhwKvPbPjOicau2+m+MDQ2Cc3tgyaC3
30
+ dZxcP6w8APFg4AId09uWAZKf0xajvBMS2aOz8Bbmag6fwqRRkTMqsNYnmqcF7aRT
31
+ DuEzbEMfaOUYjU9RuB48vr4q8yRft0ww+3jq5iwNkrX1buL2pwBbyvgms6D/BV41
32
+ MaTVMjsHqJUwU2xVfhGtxGAWAer5S1HGYHkbio6mGVtiie0uWjmnzi7ppIlMr48a
33
+ 7BNTsoZ+/JRk3iQWmmNsyFT7xfqBKye7cH11BX8V8P4MeGB5YWlMI+Myj5DZY3fQ
34
+ st2AGD4rb1l0ia7PfubcBThSIdz61eCb8gRi/RiZZwb3/7+eyEncLJzt2Ob9fGSF
35
+ X0qdrKi+2aZZ0NGuFj9AItBsVmAvkBGIpX4TEKQp5haEbPpmaqO5nIIhV26PXmyT
36
+ OMKv6pWsoS81vw5KAGBmfX8nht/Py90DQrbRvakATGI=
37
+ -----END CERTIFICATE-----
38
+ date: 2018-07-10 00:00:00.000000000 Z
39
+ dependencies:
40
+ - !ruby/object:Gem::Dependency
41
+ name: sequel
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '5.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '5.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: hoe-mercurial
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.4'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.4'
68
+ - !ruby/object:Gem::Dependency
69
+ name: hoe-deveiate
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.10'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.10'
82
+ - !ruby/object:Gem::Dependency
83
+ name: hoe-highline
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.2'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0.2'
96
+ - !ruby/object:Gem::Dependency
97
+ name: simplecov
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '0.13'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '0.13'
110
+ - !ruby/object:Gem::Dependency
111
+ name: rdoc-generator-fivefish
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '0.3'
117
+ type: :development
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '0.3'
124
+ - !ruby/object:Gem::Dependency
125
+ name: rdoc
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '4.0'
131
+ type: :development
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '4.0'
138
+ - !ruby/object:Gem::Dependency
139
+ name: hoe
140
+ requirement: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '3.16'
145
+ type: :development
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '3.16'
152
+ description: |-
153
+ This is a set of plugins for Sequel for declaring a model's table schema and
154
+ any migrations in the class itself (similar to the legacy `schema` plugin).
155
+
156
+ It has only really been tested with PostgreSQL, but patches that make it more generic are welcomed.
157
+
158
+ The two plugins are:
159
+
160
+ * Sequel::Plugins::InlineSchema
161
+ * Sequel::Plugins::InlineMigrations
162
+
163
+ Examples and usage documentation are included there.
164
+ email:
165
+ - ged@FaerieMUD.org
166
+ executables: []
167
+ extensions: []
168
+ extra_rdoc_files:
169
+ - History.md
170
+ - LICENSE.txt
171
+ - Manifest.txt
172
+ - README.md
173
+ files:
174
+ - ".document"
175
+ - ".editorconfig"
176
+ - ".rdoc_options"
177
+ - ".simplecov"
178
+ - ChangeLog
179
+ - History.md
180
+ - LICENSE.txt
181
+ - Manifest.txt
182
+ - README.md
183
+ - Rakefile
184
+ - lib/sequel/inline_schema.rb
185
+ - lib/sequel/plugins/inline_migrations.rb
186
+ - lib/sequel/plugins/inline_schema.rb
187
+ - spec/sequel/plugins/inline_migrations_spec.rb
188
+ - spec/sequel/plugins/inline_schema_spec.rb
189
+ - spec/spec_helper.rb
190
+ homepage: http://bitbucket.org/ged/sequel-inline_schema
191
+ licenses:
192
+ - BSD-3-Clause
193
+ metadata: {}
194
+ post_install_message:
195
+ rdoc_options:
196
+ - "--main"
197
+ - README.md
198
+ require_paths:
199
+ - lib
200
+ required_ruby_version: !ruby/object:Gem::Requirement
201
+ requirements:
202
+ - - ">="
203
+ - !ruby/object:Gem::Version
204
+ version: 2.4.0
205
+ required_rubygems_version: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - ">="
208
+ - !ruby/object:Gem::Version
209
+ version: '0'
210
+ requirements: []
211
+ rubyforge_project:
212
+ rubygems_version: 2.7.7
213
+ signing_key:
214
+ specification_version: 4
215
+ summary: This is a set of plugins for Sequel for declaring a model's table schema
216
+ and any migrations in the class itself (similar to the legacy `schema` plugin)
217
+ test_files: []