postspec 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +5 -0
- data/README.md +36 -0
- data/Rakefile +6 -0
- data/TODO +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/postspec +40 -0
- data/lib/postspec/config.rb +38 -0
- data/lib/postspec/environment.rb +491 -0
- data/lib/postspec/frame.rb +147 -0
- data/lib/postspec/render.rb +178 -0
- data/lib/postspec/state.rb +112 -0
- data/lib/postspec/version.rb +3 -0
- data/lib/postspec.rb +367 -0
- data/lib/postspec_helper.rb +128 -0
- data/lib/share/postspec_schema.sql +137 -0
- data/performance/performance_spec.rb +114 -0
- data/postspec.gemspec +41 -0
- data/snippets/sequences.sql +19 -0
- data/snippets/serials.sql +13 -0
- data/snippets/triggers.sql +14 -0
- metadata +237 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 46c5d89777324cedb5b8468b0c33806b45dd908b6dd7ce839bd9d3290ad9d4a0
|
4
|
+
data.tar.gz: 927fb7974ae6a9f7063e0b9a90e94dab313860c2e367d1b20f73e6afef645193
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7fb4a38a74f0af6c527605789d127243b3624cf7f7073981a69bef007087809093c0bb273f4859f80b95aa3228da061b23674ca0d012920607b1bcf7b9e8159f
|
7
|
+
data.tar.gz: 23df58f3ba1eb8a48af8bed88ae3fedf8e151c5cf453fa5b4c24f211faaec732480c66c5560ec3e95832baeef379a7c4621bec6636033dc93091152b70e7bcf2
|
data/.gitignore
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
/.bundle/
|
2
|
+
/.yardoc
|
3
|
+
/_yardoc/
|
4
|
+
/coverage/
|
5
|
+
/doc/
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/tmp/
|
9
|
+
|
10
|
+
# rspec failure tracking
|
11
|
+
.rspec_status
|
12
|
+
|
13
|
+
# Ignore auto-generated main file
|
14
|
+
/main
|
15
|
+
|
16
|
+
# Ignore Gemfile.lock. See https://stackoverflow.com/questions/4151495/should-gemfile-lock-be-included-in-gitignore
|
17
|
+
/Gemfile.lock
|
18
|
+
|
19
|
+
# Put your personal ignore files in /home/clr/.config/git/ignore
|
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.7.1
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Postspec
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/postspec`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'postspec'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle install
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install postspec
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/postspec.
|
36
|
+
|
data/Rakefile
ADDED
data/TODO
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
o Also use prick anchors
|
2
|
+
o Modify all table to be unlogged for better performance: alter table table_name set unlogged
|
3
|
+
o Doesn't detect changes to the database by the developer between runs of
|
4
|
+
postspec). Can be fixed by inspecting postspec.[change-tables]
|
5
|
+
o Doesn't remove change-triggers after runs (this may be a feature)
|
6
|
+
o Needs a clean-postspec option that removes the postspec schema and triggers
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "postspec"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/exe/postspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg_graph'
|
4
|
+
require 'shellopts'
|
5
|
+
|
6
|
+
SPEC = "
|
7
|
+
@ Demo
|
8
|
+
|
9
|
+
Demonstration of reading and writing a database. Has actually nothing to do
|
10
|
+
with postspec
|
11
|
+
|
12
|
+
-r,reflections=EFILE @ Reflections file
|
13
|
+
|
14
|
+
-- DATABASE"
|
15
|
+
|
16
|
+
def timeit(label = nil, &block)
|
17
|
+
t0 = Time.now
|
18
|
+
r = yield
|
19
|
+
dt = Time.now - t0
|
20
|
+
if dt < 1
|
21
|
+
puts "#{label}: #{(1000.0 * dt).round(1)}ms"
|
22
|
+
else
|
23
|
+
puts "#{label}: #{dt.round(1)}s"
|
24
|
+
end
|
25
|
+
r
|
26
|
+
end
|
27
|
+
|
28
|
+
opts, args = ShellOpts.process(SPEC, ARGV)
|
29
|
+
|
30
|
+
database = args.expect(1)
|
31
|
+
|
32
|
+
puts "Reading and writing the given database"
|
33
|
+
indent {
|
34
|
+
conn = PgConn.new(database)
|
35
|
+
meta = timeit("Meta") { PgMeta.new(conn) }
|
36
|
+
type = timeit("Type") { PgGraph::Type.new(meta, opts.reflections) }
|
37
|
+
data = timeit("Read data") { PgGraph::Data.new(type, conn) }
|
38
|
+
load_data = timeit("Write data") { data.write(conn) }
|
39
|
+
}
|
40
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Used to initialize postspec from spec/spec_helper.rb or spec/postspec_helper.rb
|
2
|
+
#
|
3
|
+
module Postspec
|
4
|
+
Config = Struct.new(:database, :mode, :reflections, :anchors, :fail_fast)
|
5
|
+
|
6
|
+
@database = nil
|
7
|
+
@mode = nil
|
8
|
+
@reflections = nil
|
9
|
+
@anchors = nil
|
10
|
+
@fail_fast = nil
|
11
|
+
|
12
|
+
DEFAULT_MODE = :empty
|
13
|
+
DEFAULT_FAIL_FAST = true
|
14
|
+
|
15
|
+
def self.database() @database end
|
16
|
+
def self.mode() @mode end
|
17
|
+
def self.reflections() @reflections end
|
18
|
+
def self.anchors() @anchors end
|
19
|
+
def self.fail_fast() @fail_fast end
|
20
|
+
|
21
|
+
def self.configure(&block)
|
22
|
+
config = Config.new(@database, DEFAULT_MODE, nil, nil, DEFAULT_FAIL_FAST)
|
23
|
+
yield(config)
|
24
|
+
@database = config.database
|
25
|
+
@mode = config.mode || DEFAULT_MODE
|
26
|
+
@reflections = config.reflections
|
27
|
+
@anchors = config.anchors
|
28
|
+
@fail_fast = config.fail_fast || DEFAULT_FAIL_FAST
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.postspec()
|
33
|
+
!@database.nil? or raise Error, "Database unspecified"
|
34
|
+
@postspec ||= Postspec.new(
|
35
|
+
PgConn.new(@database), mode: mode, reflector: @reflections, anchors: @anchors, fail: @fail_fast)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,491 @@
|
|
1
|
+
|
2
|
+
module Postspec
|
3
|
+
class Environment
|
4
|
+
attr_reader :postspec
|
5
|
+
forward_to :postspec, :conn, :render
|
6
|
+
|
7
|
+
def uids() table_sequence_ids end # FIXME: What is this? And why not using @uids?
|
8
|
+
|
9
|
+
def initialize(postspec)
|
10
|
+
@postspec = postspec
|
11
|
+
end
|
12
|
+
|
13
|
+
def table_sequence_ids(all: false)
|
14
|
+
conn.map \
|
15
|
+
"select table_uid, record_id from postspec.table_sequence_ids()" +
|
16
|
+
(all ? "" : " where record_id is not null")
|
17
|
+
end
|
18
|
+
|
19
|
+
def table_seed_ids
|
20
|
+
conn.map "select table_uid, record_id from postspec.seeds"
|
21
|
+
end
|
22
|
+
|
23
|
+
def table_max_ids
|
24
|
+
result = table_sequence_ids(all: true)
|
25
|
+
postspec.type.tables.select(&:subtable?).each { |table|
|
26
|
+
result[table.uid] = result[table.supertable.uid] or raise "Oops"
|
27
|
+
}
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns map from table UID to record ID of the last record to be kept so
|
32
|
+
# that 'delete from table_uid where id > record_id' does the right thing.
|
33
|
+
# Note: This assumes that the change triggers has been installed beforehand
|
34
|
+
def dirty_tables
|
35
|
+
seed_ids = table_seed_ids
|
36
|
+
table_max_ids.map { |table_uid, record_id|
|
37
|
+
(seed_id = seed_ids[table_uid]) ? [table_uid, seed_id] : [table_uid, record_id]
|
38
|
+
}.compact.to_h
|
39
|
+
end
|
40
|
+
|
41
|
+
def create()
|
42
|
+
# puts "Environment#create"
|
43
|
+
conn.execute IO.read(Postspec::SHARE_DIR + "/postspec_schema.sql")
|
44
|
+
conn.execute render.change_triggers(:create)
|
45
|
+
end
|
46
|
+
|
47
|
+
def drop()
|
48
|
+
# puts "Environment#drop"
|
49
|
+
conn.execute "drop schema if exists postspec cascade"
|
50
|
+
end
|
51
|
+
|
52
|
+
def exist?()
|
53
|
+
conn.exist? "select 1 from pg_namespace where nspname = 'postspec'"
|
54
|
+
end
|
55
|
+
|
56
|
+
# Removes excess data and meta data, and resets sequences. It doens't change any triggers
|
57
|
+
def clean
|
58
|
+
# puts "Environment#clean"
|
59
|
+
@uids = {}
|
60
|
+
user_tables = dirty_tables
|
61
|
+
postspec_tables = CHANGE_TABLE_UIDS
|
62
|
+
sql = render.delete_tables(user_tables) +
|
63
|
+
render.delete_tables(postspec_tables)
|
64
|
+
conn.execute render.execution_unit(user_tables.keys, sql)
|
65
|
+
end
|
66
|
+
|
67
|
+
def setup(mode)
|
68
|
+
# puts "Environment#setup"
|
69
|
+
sql =
|
70
|
+
case mode
|
71
|
+
when :seed
|
72
|
+
@uids = table_max_ids
|
73
|
+
render.seed_triggers(:create, @uids)
|
74
|
+
when :empty
|
75
|
+
@uids = {}
|
76
|
+
[]
|
77
|
+
else
|
78
|
+
raise ArgumentError
|
79
|
+
end
|
80
|
+
conn.execute sql
|
81
|
+
end
|
82
|
+
|
83
|
+
def teardown(mode)
|
84
|
+
# puts "Environment#teardown"
|
85
|
+
@uids = nil
|
86
|
+
tables, reset_sql = reset_data
|
87
|
+
sql =
|
88
|
+
case mode
|
89
|
+
when :seed; render.seed_triggers(:drop) + render.delete_tables(SEED_TABLE_UIDS)
|
90
|
+
when :empty; []
|
91
|
+
else
|
92
|
+
raise ArgumentError
|
93
|
+
end + reset_sql
|
94
|
+
conn.execute render.execution_unit(tables, sql)
|
95
|
+
end
|
96
|
+
|
97
|
+
def reset()
|
98
|
+
# puts "Environment#reset"
|
99
|
+
conn.execute render.execution_unit(*reset_data)
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
# Generate SQL to delete data using the postspec.inserts table
|
104
|
+
def reset_data
|
105
|
+
uids = conn.map "select table_uid, min(record_id) from postspec.inserts group by table_uid"
|
106
|
+
sql = render.delete_tables(uids) + render.delete_tables(CHANGE_TABLE_UIDS)
|
107
|
+
[uids.keys, sql]
|
108
|
+
end
|
109
|
+
|
110
|
+
CHANGE_TABLE_UIDS = %w(postspec.inserts postspec.updates postspec.deletes)
|
111
|
+
SEED_TABLE_UIDS = %w(postspec.seeds)
|
112
|
+
RUN_TABLE_UIDS = %w(postspec.runs)
|
113
|
+
TABLE_UIDS = CHANGE_TABLE_UIDS + SEED_TABLE_UIDS + RUN_TABLE_UIDS
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
__END__
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
class Environment
|
123
|
+
attr_reader :postspec
|
124
|
+
forward_to :postspec, :conn, :render
|
125
|
+
|
126
|
+
attr_reader :uids # UID to ID map. Only used by the seed environment
|
127
|
+
|
128
|
+
def user_tables() @tables ||= postspec.tables.map(&:uid) end
|
129
|
+
|
130
|
+
CHANGE_TABLE_UIDS = %w(postspec.inserts postspec.updates postspec.deletes)
|
131
|
+
SEED_TABLE_UIDS = %w(postspec.seeds)
|
132
|
+
RUN_TABLE_UIDS = %w(postspec.runs)
|
133
|
+
TABLE_UIDS = CHANGE_TABLE_UIDS + SEED_TABLE_UIDS + RUN_TABLE_UIDS
|
134
|
+
|
135
|
+
def initialize(postspec)
|
136
|
+
@postspec = postspec
|
137
|
+
@uids = nil
|
138
|
+
setup_schema if !exist_schema?
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
# setup(mode); teardown(mode) is a NOP
|
144
|
+
|
145
|
+
def setup(mode) self.send :"setup_#{mode}_environment" end
|
146
|
+
def teardown(mode) self.send :"teardown_#{mode}_environment" end
|
147
|
+
def reset(mode, *type) self.send :"reset_#{mode}_environment", *type.compact end
|
148
|
+
|
149
|
+
def setup_schema
|
150
|
+
conn.execute(IO.read(SHARE_DIR + "/postspec_schema.sql"))
|
151
|
+
end
|
152
|
+
|
153
|
+
def teardown_schema
|
154
|
+
conn.execute "drop schema if exists postspec cascade"
|
155
|
+
end
|
156
|
+
|
157
|
+
def reset_schema
|
158
|
+
teardown_seed_environment
|
159
|
+
teardown_empty_environment
|
160
|
+
end
|
161
|
+
|
162
|
+
def exist_schema?
|
163
|
+
conn.exist? "select 1 from pg_namespace where nspname = 'postspec'"
|
164
|
+
end
|
165
|
+
|
166
|
+
def setup_change_environment
|
167
|
+
conn.exec render.change_triggers(:create)
|
168
|
+
end
|
169
|
+
|
170
|
+
def teardown_change_environment
|
171
|
+
sql =
|
172
|
+
render.change_triggers(:drop) +
|
173
|
+
render.delete_tables(CHANGE_TABLE_UIDS)
|
174
|
+
conn.exec render.execution_unit(CHANGE_TABLE_UIDS, sql)
|
175
|
+
end
|
176
|
+
|
177
|
+
# Not used - should be delegated to seed or empty environment
|
178
|
+
# def reset_change_environment
|
179
|
+
# end
|
180
|
+
|
181
|
+
|
182
|
+
|
183
|
+
def setup_seed_environment()
|
184
|
+
@uids = conn.map("select name, id from postspec.sequence_ids()")
|
185
|
+
sql = render.seed_triggers(:create, uids)
|
186
|
+
conn.exec sql
|
187
|
+
end
|
188
|
+
|
189
|
+
def teardown_seed_environment()
|
190
|
+
@uids = nil
|
191
|
+
uids = conn.map "select table_uid, min(record_id) from postspec.inserts"
|
192
|
+
sql =
|
193
|
+
render.seed_triggers(:drop) +
|
194
|
+
render.delete_tables(uids) +
|
195
|
+
render.delete_tables(CHANGE_TABLE_UIDS) +
|
196
|
+
render.delete_tables(SEED_TABLE_UIDS)
|
197
|
+
conn.exec render.execution_unit(uids.keys, sql)
|
198
|
+
end
|
199
|
+
|
200
|
+
def reset_seed_environment
|
201
|
+
uids = conn.map "select table_uid, min(record_id) from postspec.inserts"
|
202
|
+
sql =
|
203
|
+
render.delete_tables(uids) +
|
204
|
+
render.delete_tables(CHANGE_TABLE_UIDS)
|
205
|
+
conn.exec render.execution_unit(uids.keys, sql)
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
def setup_empty_environment
|
210
|
+
@uids = {}
|
211
|
+
sql = render.delete_tables(user_tables + CHANGE_TABLE_UIDS)
|
212
|
+
conn.exec render.execution_unit(tables, sql)
|
213
|
+
end
|
214
|
+
|
215
|
+
def teardown_empty_environment
|
216
|
+
@uids = nil
|
217
|
+
end
|
218
|
+
|
219
|
+
def reset_empty_environment
|
220
|
+
# Because we know the initial environment was empty we only need to
|
221
|
+
# inspect the postspect.inserts tables to find records to delete
|
222
|
+
changed_tables = conn.values "select distinct table_uid from inserts"
|
223
|
+
sql = render.delete_tables(changed_tables + CHANGE_TABLE_UIDS)
|
224
|
+
conn.exec render.execution_unit(tables, sql)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
__END__
|
230
|
+
|
231
|
+
end
|
232
|
+
|
233
|
+
def drop
|
234
|
+
|
235
|
+
class PostspecEnvironment
|
236
|
+
attr_reader :postspec
|
237
|
+
forward_to :postspec, :conn, :render
|
238
|
+
|
239
|
+
def initialize(postspec)
|
240
|
+
@postspec = postspec
|
241
|
+
self.ensure
|
242
|
+
end
|
243
|
+
|
244
|
+
def self.instance(postspec)
|
245
|
+
@instance ||= PostspecEnvironment.new(postspec)
|
246
|
+
end
|
247
|
+
|
248
|
+
def create
|
249
|
+
end
|
250
|
+
|
251
|
+
def drop
|
252
|
+
end
|
253
|
+
|
254
|
+
def reset
|
255
|
+
State.reset(postspec)
|
256
|
+
end
|
257
|
+
|
258
|
+
def ensure
|
259
|
+
if !postspec.meta.schemas.key?("postspec")
|
260
|
+
create
|
261
|
+
else
|
262
|
+
# meta knows about the postspec schema so we hide it
|
263
|
+
postspec.meta.schemas["postspec"].hidden = true
|
264
|
+
reset
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
private
|
269
|
+
@instance = nil
|
270
|
+
end
|
271
|
+
|
272
|
+
class Environment
|
273
|
+
attr_reader :postspec_environment
|
274
|
+
attr_reader :state
|
275
|
+
|
276
|
+
forward_to :postspec_environment, :postspec, :conn, :render
|
277
|
+
|
278
|
+
# :call-seq:
|
279
|
+
# ::new(postspec, state)
|
280
|
+
# ::new(postspec, mode)
|
281
|
+
def self.new(postspec, arg)
|
282
|
+
klass =
|
283
|
+
case mode
|
284
|
+
when :seed; SeedEnvironment
|
285
|
+
when :empty; EmptyEnvironment
|
286
|
+
else
|
287
|
+
KeepEnvironment
|
288
|
+
end
|
289
|
+
object = klass.allocate
|
290
|
+
state = arg.is_state? ? arg : State.create(postspec, arg)
|
291
|
+
object.send(:initialize, PostspecEnvironment.instance(postspec), state)
|
292
|
+
object
|
293
|
+
end
|
294
|
+
|
295
|
+
def terminate
|
296
|
+
state.write
|
297
|
+
end
|
298
|
+
|
299
|
+
def create() raise NotThis end
|
300
|
+
def drop() raise NotThis end
|
301
|
+
def reset() postspec_environment.reset end
|
302
|
+
|
303
|
+
protected
|
304
|
+
def initialize(postspec_environment, state)
|
305
|
+
@postspec_environment = postspec_environment
|
306
|
+
@state = state
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
class SeedEnvironment < Environment
|
311
|
+
def create
|
312
|
+
uids = @conn.map("select name, id from postspec.sequence_ids()", :name)
|
313
|
+
conn.exec render.seed_triggers(:create, uids)
|
314
|
+
conn.exec "delete from postspec.seeds"
|
315
|
+
end
|
316
|
+
|
317
|
+
def drop
|
318
|
+
conn.exec render.seed_triggers(:drop)
|
319
|
+
conn.exec "delete from postspec.seeds"
|
320
|
+
end
|
321
|
+
|
322
|
+
def reset # TODO: Merge with PgGraph::Data::SqlRender
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
class EmptyEnvironment < Environment
|
327
|
+
def create() end
|
328
|
+
def drop() end
|
329
|
+
|
330
|
+
def reset
|
331
|
+
super
|
332
|
+
conn.exec state.inserts.keys.map { |uid| "delete from #{uid}" }
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
class KeepEnvironment < Environment
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
__END__
|
341
|
+
|
342
|
+
class Environment
|
343
|
+
attr_reader :postspec
|
344
|
+
attr_reader :id
|
345
|
+
attr_reader :mode
|
346
|
+
attr_accessor :status
|
347
|
+
def duration() @duraction ||= Time.now - created_at end
|
348
|
+
attr_reader :created_at
|
349
|
+
|
350
|
+
forward_to :postspec, :conn
|
351
|
+
|
352
|
+
def initialize(postspec, id, mode, status, duration, created_at)
|
353
|
+
@postspec = postspec
|
354
|
+
@id = id
|
355
|
+
@mode = mode
|
356
|
+
@status = status
|
357
|
+
@duration = duration
|
358
|
+
@created_at = created_at
|
359
|
+
end
|
360
|
+
|
361
|
+
def update
|
362
|
+
sql = %(
|
363
|
+
update postspec.runs
|
364
|
+
set status = #{status},
|
365
|
+
duration = #{duration}
|
366
|
+
where id = #{id}
|
367
|
+
)
|
368
|
+
conn.exec(sql)
|
369
|
+
end
|
370
|
+
|
371
|
+
def self.create(conn, mode)
|
372
|
+
sql = %(
|
373
|
+
insert into postspec.runs (mode) values ('#{mode}') returning id, created_at
|
374
|
+
)
|
375
|
+
id, created_at = @conn.tuple(sql)
|
376
|
+
State.new(conn, id, mode, nil, nil, created_at)
|
377
|
+
end
|
378
|
+
|
379
|
+
def self.read_last(conn)
|
380
|
+
sql = %(
|
381
|
+
select id, mode, status, duration, created_at
|
382
|
+
from postspec.runs
|
383
|
+
order by desc id
|
384
|
+
limit 1
|
385
|
+
)
|
386
|
+
tuple = @conn.tuples(sql).first
|
387
|
+
tuple && State.new(conn, *tuple)
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
class SeedEnvironment < Environment
|
392
|
+
def initialize(postspec, id, mode, status, duration, created_at)
|
393
|
+
end
|
394
|
+
def create
|
395
|
+
super
|
396
|
+
conn.execute(render.readonly_triggers(:create, ids)
|
397
|
+
end
|
398
|
+
|
399
|
+
def update
|
400
|
+
end
|
401
|
+
|
402
|
+
def drop
|
403
|
+
conn.execute(render.readonly_triggers(:drop, ids)
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
class EmptyEnvironment < Environment
|
408
|
+
def create
|
409
|
+
super
|
410
|
+
conn.execute(render.delete_tables(postspec.tables.map(&:uid))
|
411
|
+
end
|
412
|
+
|
413
|
+
def update
|
414
|
+
end
|
415
|
+
|
416
|
+
def drop
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
class KeepEnvironment < Environment
|
421
|
+
end
|
422
|
+
|
423
|
+
|
424
|
+
|
425
|
+
|
426
|
+
|
427
|
+
class Environment
|
428
|
+
attr_reader :postspec
|
429
|
+
attr_reader :state
|
430
|
+
forward_to :postspec, :conn, :meta, :render
|
431
|
+
|
432
|
+
def initialize(postspec, mode)
|
433
|
+
@postspec = postspec
|
434
|
+
@state = State.create(postspec.conn, mode)
|
435
|
+
|
436
|
+
last_state
|
437
|
+
|
438
|
+
end
|
439
|
+
|
440
|
+
def create()
|
441
|
+
if meta.schemas.key?("postspec")
|
442
|
+
# meta knows about the postspec schema so we hide it
|
443
|
+
meta.schemas["postspec"].hidden = true
|
444
|
+
# @conn.execute render.delete_postspec_tables
|
445
|
+
else
|
446
|
+
# meta doesn't know about the postspec schema
|
447
|
+
conn.execute(IO.read(SHARE_DIR + "/postspec_schema.sql"))
|
448
|
+
end
|
449
|
+
conn.execute(render.change_triggers(:create))
|
450
|
+
end
|
451
|
+
|
452
|
+
def reset()
|
453
|
+
conn.execute(render.reset_postspec_tables)
|
454
|
+
end
|
455
|
+
|
456
|
+
def drop()
|
457
|
+
conn.execute(render.change_triggers(:drop))
|
458
|
+
conn.execute("drop schema postspec cascade")
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
class SeedEnvironment < Environment
|
463
|
+
def create
|
464
|
+
super
|
465
|
+
conn.execute(render.readonly_triggers(:create, ids)
|
466
|
+
end
|
467
|
+
|
468
|
+
def update
|
469
|
+
end
|
470
|
+
|
471
|
+
def drop
|
472
|
+
conn.execute(render.readonly_triggers(:drop, ids)
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
class EmptyEnvironment < Environment
|
477
|
+
def create
|
478
|
+
super
|
479
|
+
conn.execute(render.delete_tables(postspec.tables.map(&:uid))
|
480
|
+
end
|
481
|
+
|
482
|
+
def update
|
483
|
+
end
|
484
|
+
|
485
|
+
def drop
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
class KeepEnvironment < Environment
|
490
|
+
end
|
491
|
+
end
|