prick 0.18.0 → 0.20.2

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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +10 -4
  3. data/README.md +7 -7
  4. data/Rakefile +3 -1
  5. data/TODO +13 -11
  6. data/bin/console +2 -1
  7. data/doc/build-yml.txt +14 -0
  8. data/exe/prick +264 -28
  9. data/lib/builder/batch.rb +147 -0
  10. data/lib/builder/builder.rb +122 -0
  11. data/lib/builder/node.rb +189 -0
  12. data/lib/builder/node_pool.rb +105 -0
  13. data/lib/builder/parser.rb +120 -0
  14. data/lib/local/command.rb +193 -0
  15. data/lib/{prick → local}/git.rb +148 -22
  16. data/lib/local/timer.rb +98 -0
  17. data/lib/prick/constants.rb +54 -66
  18. data/lib/prick/diff.rb +28 -18
  19. data/lib/prick/prick_version.rb +161 -0
  20. data/lib/prick/state.rb +80 -165
  21. data/lib/prick/version.rb +2 -163
  22. data/lib/prick.rb +43 -27
  23. data/lib/share/init/.gitignore +10 -0
  24. data/lib/share/init/.prick-context +2 -0
  25. data/lib/share/init/.rspec +3 -0
  26. data/{share/schema/schema/public → lib/share/init/migration}/.keep +0 -0
  27. data/lib/share/init/prick.yml +6 -0
  28. data/lib/share/init/schema/.keep +0 -0
  29. data/lib/share/init/schema/build.yml +2 -0
  30. data/lib/share/init/schema/prick/.keep +0 -0
  31. data/lib/share/init/schema/prick/build.yml +5 -0
  32. data/lib/share/init/schema/prick/data.sql +6 -0
  33. data/{share/schema → lib/share/init}/schema/prick/tables.sql +2 -3
  34. data/lib/share/init/schema/public/.keep +0 -0
  35. data/lib/share/init/spec/prick_helper.rb +1 -0
  36. data/lib/share/init/spec/prick_spec.rb +6 -0
  37. data/lib/share/init/spec/spec_helper.rb +50 -0
  38. data/lib/share/migrate/migration/build.yml +4 -0
  39. data/lib/share/migrate/migration/diff.after-tables.sql +0 -0
  40. data/lib/share/migrate/migration/diff.before-tables.sql +0 -0
  41. data/lib/share/migrate/migration/diff.tables.sql +0 -0
  42. data/lib/subcommand/prick-build.rb +55 -0
  43. data/lib/subcommand/prick-create.rb +78 -0
  44. data/lib/subcommand/prick-drop.rb +25 -0
  45. data/lib/subcommand/prick-fox.rb +62 -0
  46. data/lib/subcommand/prick-init.rb +46 -0
  47. data/lib/subcommand/prick-make.rb +202 -0
  48. data/lib/subcommand/prick-migrate.rb +37 -0
  49. data/lib/subcommand/prick-release.rb +23 -0
  50. data/lib/subcommand/prick-setup.rb +20 -0
  51. data/lib/subcommand/prick-teardown.rb +18 -0
  52. data/prick.gemspec +43 -16
  53. metadata +161 -72
  54. data/.gitignore +0 -29
  55. data/.travis.yml +0 -7
  56. data/doc/create_release.txt +0 -17
  57. data/doc/flow.txt +0 -98
  58. data/doc/migra +0 -1
  59. data/doc/migrations.txt +0 -172
  60. data/doc/notes.txt +0 -116
  61. data/doc/prick.txt +0 -114
  62. data/doc/sh.prick +0 -316
  63. data/lib/ext/algorithm.rb +0 -14
  64. data/lib/ext/fileutils.rb +0 -26
  65. data/lib/ext/forward_method.rb +0 -18
  66. data/lib/ext/pg.rb +0 -18
  67. data/lib/ext/shortest_path.rb +0 -44
  68. data/lib/prick/archive.rb +0 -124
  69. data/lib/prick/branch.rb +0 -254
  70. data/lib/prick/builder.rb +0 -205
  71. data/lib/prick/cache.rb +0 -34
  72. data/lib/prick/command.rb +0 -102
  73. data/lib/prick/database.rb +0 -82
  74. data/lib/prick/dsort.rb +0 -151
  75. data/lib/prick/ensure.rb +0 -119
  76. data/lib/prick/exceptions.rb +0 -25
  77. data/lib/prick/head.rb +0 -183
  78. data/lib/prick/migration.rb +0 -70
  79. data/lib/prick/program.rb +0 -506
  80. data/lib/prick/project.rb +0 -626
  81. data/lib/prick/rdbms.rb +0 -137
  82. data/lib/prick/schema.rb +0 -27
  83. data/lib/prick/share.rb +0 -64
  84. data/libexec/strip-comments +0 -33
  85. data/make_releases +0 -72
  86. data/make_schema +0 -10
  87. data/share/diff/diff.after-tables.sql +0 -4
  88. data/share/diff/diff.before-tables.sql +0 -4
  89. data/share/diff/diff.tables.sql +0 -8
  90. data/share/features/diff.sql +0 -2
  91. data/share/features/feature/diff.sql +0 -2
  92. data/share/features/feature/migrate.sql +0 -2
  93. data/share/features/features.sql +0 -2
  94. data/share/features/features.yml +0 -2
  95. data/share/features/migrations.sql +0 -4
  96. data/share/gitignore +0 -2
  97. data/share/migration/diff.tables.sql +0 -8
  98. data/share/migration/features.yml +0 -6
  99. data/share/migration/migrate.sql +0 -3
  100. data/share/migration/migrate.yml +0 -8
  101. data/share/migration/tables.sql +0 -3
  102. data/share/schema/build.yml +0 -14
  103. data/share/schema/schema/build.yml +0 -3
  104. data/share/schema/schema/prick/build.yml +0 -14
  105. data/share/schema/schema/prick/data.sql +0 -7
  106. data/share/schema/schema/prick/schema.sql +0 -3
  107. data/share/schema/schema/public/build.yml +0 -13
  108. data/share/schema/schema.sql +0 -3
  109. data/test_assorted +0 -192
  110. data/test_feature +0 -112
  111. data/test_refactor +0 -34
  112. data/test_single_dev +0 -83
data/lib/prick/branch.rb DELETED
@@ -1,254 +0,0 @@
1
- require "prick/state.rb"
2
-
3
- module Prick
4
- class Branch
5
- # Branch name. It is usually equal to the version but migrations use a
6
- # <base_version>_<version> format instead
7
- attr_reader :name
8
-
9
- # Version of this branch. Note that version and base_version are the same
10
- # for feature branches
11
- attr_reader :version
12
-
13
- # Base version
14
- attr_reader :base_version
15
-
16
- # The release directory. It contains the release's .prick-migration file
17
- attr_reader :directory
18
-
19
- # The Schema object. This is shared by many all branches
20
- attr_reader :schema
21
-
22
- # Migration object. Running the migration object on the base release will
23
- # migrate it to this release
24
- attr_reader :migration
25
-
26
- # Database name
27
- def database() name end
28
-
29
- # Classifiers
30
- def release?() self.is_a?(Release) && !prerelease? end
31
- def prerelease?() self.is_a?(PreRelease) end
32
- def feature?() self.is_a?(Feature) end
33
- def migration?() self.is_a?(MigrationRelease) end
34
-
35
- # Note that `name` can be nil. It defaults to `version.to_s`
36
- def initialize(name, version, base_version, directory, migration)
37
- @name = name || migration.version.to_s
38
- @version = version
39
- @base_version = base_version
40
- @directory = directory
41
- @schema = Schema.new
42
- @migration = migration
43
- end
44
-
45
- def dump
46
- puts "#{self.class}"
47
- indent {
48
- puts "name: #{name}"
49
- puts "version: #{version}"
50
- puts "base_version: #{base_version}"
51
- puts "directory: #{directory}"
52
- print "migration: "
53
- migration.dump
54
- puts "database: #{database}"
55
- }
56
- end
57
-
58
- def self.load(name) raise NotThis end
59
-
60
- # True if the branch exists in git
61
- def exist?() self.class.exist?(name) end
62
-
63
- def create()
64
- !exist? or raise Error, "Can't create branch #{name}, exists already"
65
- Git.create_branch(name)
66
- Git.checkout_branch(name)
67
- prepare if !prepared?
68
- self
69
- end
70
-
71
- # True if the branch exists on disk
72
- def present?() self.class.present?(name) end
73
-
74
- def prepared?() @migration.exist? end
75
- def prepare() @migration.create end
76
-
77
- def include(feature_version) @migration.append_feature(feature_version) end
78
-
79
- def build(database) schema.build(database) end
80
-
81
- # Used to checkout migrations. MigrationReleases checks out the
82
- # corresponding branch while Release and PreRelease checks out a tag
83
- def checkout_release() Git.checkout_branch(version) end
84
-
85
- def migrate(database)
86
- @migration.migrate(database)
87
- end
88
-
89
- def migrate_features(database)
90
- @migration.migrate_features(database)
91
- end
92
-
93
- def self.directory(name) raise NotThis end
94
- def self.exist?(name) Git.branch?(name) || Git.tag?(name) end
95
- def self.present?(name) File.exist?(directory(name)) end
96
-
97
- def <=>(other)
98
- if !self.is_a?(MigrationRelease) && other.is_a?(MigrationRelease)
99
- compare(other.base_version, other.version)
100
- else
101
- compare(other.version, other.base_version)
102
- end
103
- end
104
-
105
- private
106
- def compare(other_version, other_base_version)
107
- r = version <=> other_version
108
- return r if r != 0
109
- if base_version.nil?
110
- other_base_version.nil? ? 0 : -1
111
- elsif other_base_version.nil?
112
- 1
113
- else
114
- base_version <=> other_base_version
115
- end
116
- end
117
- end
118
-
119
- class AbstractRelease < Branch
120
- def create(schema_version = self.version)
121
- super()
122
- schema.version = schema_version
123
- Git.add schema.version_file
124
- self
125
- end
126
-
127
- def checkout_release() Git.checkout_tag(version) end
128
-
129
- def tag!() Git.create_tag(version) end
130
- end
131
-
132
- class Release < AbstractRelease
133
- def initialize(version, base_version)
134
- !version.zero? || base_version.nil? or raise Internal, "Version 0.0.0 has no base release"
135
- directory = self.class.directory(version.to_s)
136
- migration = ReleaseMigration.new(version, base_version)
137
- super(nil, version, base_version, directory, migration)
138
- end
139
-
140
- def self.load(name)
141
- migration = ReleaseMigration.load(directory(name))
142
- self.new(migration.version, migration.base_version)
143
- end
144
-
145
- def self.directory(name)
146
- File.join(RELEASES_DIR, name)
147
- end
148
- end
149
-
150
- class PreRelease < AbstractRelease
151
- attr_reader :prerelease_version
152
-
153
- def database() version.to_s end
154
-
155
- def initialize(prerelease_version, base_version)
156
- @prerelease_version = prerelease_version
157
- version = prerelease_version.truncate(:pre)
158
- directory = Release.directory(version.to_s)
159
- migration = ReleaseMigration.new(version, base_version)
160
- super(prerelease_version.to_s, version, base_version, directory, migration)
161
- end
162
-
163
- def self.load(name, prerelease_version)
164
- migration = ReleaseMigration.load(directory(name))
165
- self.new(prerelease_version, migration.base_version)
166
- end
167
-
168
- def create()
169
- super(prerelease_version)
170
- end
171
-
172
- def increment
173
- PreRelease.new(prerelease_version.increment(:pre), base_version)
174
- end
175
-
176
- def self.directory(name)
177
- version = Version.new(name)
178
- Release.directory(version.truncate(:pre).to_s)
179
- end
180
- end
181
-
182
- class MigrationRelease < Branch
183
- def database() version.to_s end
184
-
185
- def initialize(version, base_version)
186
- migration = MigrationMigration.new(version, base_version)
187
- super(migration.name, version, base_version, migration.dir, migration)
188
- end
189
-
190
- def self.load(name)
191
- directory = self.directory(name)
192
- migration_state = MigrationState.new(directory).read
193
- self.new(migration_state.version, migration_state.base_version)
194
- end
195
-
196
- def self.directory(name)
197
- File.join(MIGRATIONS_DIR, name)
198
- end
199
- end
200
-
201
- # Feature maintains a migration in the parent release but it is ignored when
202
- # including the feature
203
- class Feature < Branch
204
- attr_reader :feature_name
205
-
206
- def database() base_version.to_s end
207
-
208
- def initialize(feature_name, base_version)
209
- version = Version.new(base_version, feature: feature_name)
210
- migration = FeatureMigration.new(feature_name, base_version)
211
- super(version.to_s, version, base_version, migration.features_dir, migration)
212
- @feature_name = feature_name
213
- end
214
-
215
- def create
216
- super()
217
- schema.version = version
218
- Git.add schema.version_file
219
- self
220
- end
221
-
222
- def include(feature_version) @migration.insert_feature(feature_version) end
223
-
224
- def rebase(base_version)
225
- new_version = Version.new(new_base_version, feature: feature_name)
226
- name = new_version.to_s
227
-
228
- Git.create_branch(name)
229
- Git.checkout_branch(name)
230
-
231
- symlink = self.directory(name)
232
- FileUtils.ln_sr(directory, symlink, force: true)
233
- Git.add(symlink)
234
-
235
- migration.base_version = new_base_version
236
- migration.save
237
-
238
- schema.version = new_version
239
- Git.add ect.schema.version_file
240
- end
241
-
242
- def self.load(name)
243
- directory = self.directory(name)
244
- migration_state = MigrationState.new(directory).read
245
- self.new(migration_state.version.feature, migration_state.base_version)
246
- end
247
-
248
- def self.directory(name)
249
- version = Version.new(name)
250
- File.join(Release.directory(version.truncate(:feature).to_s), version.feature.to_s)
251
- end
252
- end
253
- end
254
-
data/lib/prick/builder.rb DELETED
@@ -1,205 +0,0 @@
1
- require "prick/state.rb"
2
-
3
- module Prick
4
- # Builder is a procedural object for building schemas and executing
5
- # migrations. Builder use resources that can be executables, SQL files, YAML
6
- # files, or directories. A resource is identified by a name (eg. 'my-tables')
7
- # and is used to match a build file. Build files are looked up in the
8
- # following order:
9
- #
10
- # #{name} executable
11
- # #{name}.* executable
12
- # #{name}.yml
13
- # #{name}.sql
14
- # #{name}/
15
- #
16
- # The output from executable objects is expected to be SQL statements that
17
- # are fed into postgres
18
- #
19
- # When a resource match a directory, the directory can contain a special
20
- # default resource ('build' or 'migrate') that takes over the rest of the
21
- # build process for that directory. Typically, you'll use the 'build.yml' or
22
- # 'migrate.yml' to control the build order of the other resources. If a
23
- # directory doesn't contain a build resource, the resources in the directory
24
- # are built in alphabetic order
25
- #
26
- # Build (but not migration) SQL scripts and executables are executed with
27
- # search path set to containing schema
28
- #
29
- class Builder
30
- attr_reader :database
31
- attr_reader :directory
32
- attr_reader :default # either "build" or "migrate"
33
- attr_reader :lines
34
-
35
- def initialize(database, directory, default)
36
- @database = database
37
- @directory = directory
38
- @default = default
39
- @execute = true
40
- @lines = []
41
- @cwd = Dir.getwd # used in error messages
42
- end
43
-
44
- def build(subject = default, execute: true)
45
- @execute = execute
46
- @lines = []
47
- # puts "Building #{subject.inspect}"
48
- Dir.chdir(directory) {
49
- if subject
50
- build_subject(subject)
51
- else
52
- build_directory(".")
53
- end
54
- }
55
- @lines.reject! { |l| l =~ /^\s*--/ || l =~ /^\s*$/ }
56
- self
57
- end
58
-
59
- def self.yml_file(directory) raise NotThis end
60
-
61
- protected
62
- def do_dir(path, &block)
63
- # puts "do_dir(#{path.inspect})"
64
- dir, file = File.split(path)
65
- Dir.chdir(dir) { yield(file) }
66
- end
67
-
68
- def do_sql(path, schema: nil)
69
- # puts "do_sql(#{path})"
70
- do_dir(path) { |file|
71
- if @execute
72
- begin
73
- Rdbms.exec_file(database.name, file, user: database.user, schema: schema)
74
- rescue Command::Error => ex
75
- $stderr.puts ex.stderr
76
- $stderr.puts "in #{reldir}/#{file}"
77
- exit 1
78
- end
79
- else
80
- @lines += IO.readlines(file).map(&:chomp)
81
- end
82
- }
83
- true
84
- end
85
-
86
- def do_exe(path, args = [], schema: nil)
87
- # puts "do_exe(#{path.inspect}, #{args.inspect})"
88
- do_dir(path) { |file|
89
- cmd = (["./#{file}"] + args).join(" ")
90
- lines = Command.command cmd, stdin: [database.name, database.user]
91
- if @execute
92
- begin
93
- Rdbms.exec_sql(database.name, lines.join("\n"), user: database.user, schema: schema)
94
- rescue Command::Error => ex
95
- $stderr.puts ex.stderr
96
- $stderr.puts "from #{reldir}/#{file}"
97
- exit 1
98
- end
99
- else
100
- @lines += lines
101
- end
102
- }
103
- true
104
- end
105
-
106
- def do_yml(path)
107
- # puts "do_yml(#{path})"
108
- dir, file = File.split(path)
109
- YAML.load(File.read(path))&.each { |subject| build_subject(File.join(dir, subject)) }
110
- true
111
- end
112
-
113
- # A subject can be both an abstract subject or a concrete file (*.yml, *.sql)
114
- def build_subject(subject)
115
- cmd, *args = subject.split(/\s+/)
116
- if File.file?(cmd) && File.executable?(cmd)
117
- do_exe(cmd, args)
118
- elsif File.file?(subject) && subject.end_with?(".yml")
119
- do_yml(subject)
120
- elsif File.file?(subject) && subject.end_with?(".sql")
121
- do_sql(subject)
122
- elsif File.exist?(yml_file = "#{subject}.yml")
123
- do_yml(yml_file)
124
- elsif File.exist?(sql_file = "#{subject}.sql")
125
- do_sql(sql_file)
126
- elsif File.directory?(subject)
127
- build_directory(subject)
128
- else
129
- false
130
- end
131
- end
132
-
133
- def build_directory(path)
134
- Dir.chdir(path) {
135
- build_subject(File.join(path, @default)) || begin
136
- if Dir["#{path}/#{default}", "#{path}/#{default}.yml", "#{path}/#{default}.sql"]
137
- subjects = [default]
138
- else
139
- exes = candidates.select { |file| File.file?(file) && File.executable?(file) }
140
- ymls = candidates.select { |file| file.end_with?(".yml") }.map { |f| f.sub(/\.yml$/, "") }
141
- sqls = candidates.select { |file| file.end_with?(".sql") }.map { |f| f.sub(/\.sql$/, "") }
142
- dirs = candidates.select { |file| File.directory?(file) }
143
- subjects = (exes + ymls + sqls + dirs).uniq.sort.reject { |f| f != "diff" }
144
- end
145
- subjects.inject(false) { |a, s| build_subject(s) || a }
146
- end
147
- }
148
- end
149
-
150
- private
151
- # Return the relative path to the current directory from the directory of
152
- # the time of the instantiation of the Builder object. Used in error
153
- # messages
154
- def reldir
155
- Dir.getwd.sub(/^#{@cwd}\//, "")
156
- end
157
- end
158
-
159
- class MigrationBuilder < Builder
160
- def initialize(database, directory)
161
- super(database, directory, "migrate")
162
- end
163
-
164
- def self.yml_file(directory) File.join(directory, "migrate") + ".yml" end
165
- end
166
-
167
- class SchemaBuilder < Builder
168
- def initialize(database, directory)
169
- super(database, directory, "build")
170
- end
171
-
172
- def build(subject = nil, execute: true)
173
- if subject
174
- @execute = execute
175
- @lines = []
176
- Dir.chdir(directory) {
177
- if File.executable?(subject)
178
- do_exe(subject)
179
- elsif subject.end_with?(".sql")
180
- do_sql(subject)
181
- else
182
- build_subject(subject)
183
- end
184
- }
185
- else
186
- super(execute: execute)
187
- end
188
- self
189
- end
190
-
191
- def self.yml_file(directory) File.join(directory, "build") + ".yml" end
192
-
193
- protected
194
- def do_sql(path)
195
- schema = Dir.getwd.sub(/^.*schema\/([^\/]+)(?:\/.*)?$/, '\1')
196
- super(path, schema: schema)
197
- end
198
-
199
- def do_exe(path, args = [])
200
- schema = Dir.getwd.sub(/^.*schema\/([^\/]+)(?:\/.*)?$/, '\1')
201
- super(path, args, schema: schema)
202
- end
203
- end
204
- end
205
-
data/lib/prick/cache.rb DELETED
@@ -1,34 +0,0 @@
1
-
2
- module Prick
3
- class Cache
4
- def initialize
5
- end
6
-
7
- def exist?(version)
8
- File.exist?(file(version))
9
- end
10
-
11
- def list
12
- Dir.glob(File.join(CACHE_DIR, "*.sql.gz"))
13
- end
14
-
15
- def load(database, version)
16
- Rdbms.load(database, file(version))
17
- end
18
-
19
- def save(database, version = database.version)
20
- Rdbms.save(database, file(version))
21
- end
22
-
23
- # Returns list of removed files
24
- def clean
25
- l = list
26
- FileUtils.rm(l)
27
- l
28
- end
29
-
30
- def file(version)
31
- File.join(CACHE_DIR, "#{version}.sql.gz")
32
- end
33
- end
34
- end
data/lib/prick/command.rb DELETED
@@ -1,102 +0,0 @@
1
- require 'fcntl'
2
-
3
- module Command
4
- class Error < RuntimeError
5
- attr_reader :status
6
- attr_reader :stdout
7
- attr_reader :stderr
8
-
9
- def initialize(message, status, stdout, stderr)
10
- super(message)
11
- @status = status
12
- @stdout = stdout
13
- @stderr = stderr
14
- end
15
- end
16
-
17
- # Execute the shell command 'cmd' and return standard output as an array of
18
- # strings. while stderr is passed through unless stderr: is false. If stderr:
19
- # is true, it returns a tuple of [stdout, stderr] instead. The shell command
20
- # is executed with the `errexit` and `pipefail` bash options
21
- #
22
- # The :stdin option is a line or an array of lines that'll be fed to the
23
- # standard input of the command. Default is nil
24
- #
25
- # It raises a Command::Error exception if the command fails unless :fail is
26
- # true. The exit status of the last command is stored in ::status
27
- #
28
- def command(cmd, stdin: nil, stderr: false, fail: true)
29
- cmd = "set -o errexit\nset -o pipefail\n#{cmd}"
30
-
31
- pw = IO::pipe # pipe[0] for read, pipe[1] for write
32
- pr = IO::pipe
33
- pe = IO::pipe
34
-
35
- STDOUT.flush
36
-
37
- pid = fork {
38
- pw[1].close
39
- pr[0].close
40
- pe[0].close
41
-
42
- STDIN.reopen(pw[0])
43
- pw[0].close
44
-
45
- STDOUT.reopen(pr[1])
46
- pr[1].close
47
-
48
- STDERR.reopen(pe[1])
49
- pe[1].close
50
-
51
- exec(cmd)
52
- }
53
-
54
- pw[0].close
55
- pr[1].close
56
- pe[1].close
57
-
58
- if stdin
59
- pw[1].puts(stdin)
60
- pw[1].flush
61
- pw[1].close
62
- end
63
-
64
- @status = Process.waitpid2(pid)[1].exitstatus
65
-
66
- out = pr[0].readlines.collect { |line| line.chop }
67
- err = pe[0].readlines.collect { |line| line.chop }.grep_v(/^NOTICE:/)
68
-
69
- pw[1].close if !stdin
70
- pr[0].close
71
- pe[0].close
72
-
73
- result =
74
- case stderr
75
- when true; [out, err]
76
- when false; out
77
- when NilClass; $stderr.puts err
78
- else
79
- raise Internal, "Unexpected value for :stderr - #{stderr.inspect}"
80
- end
81
-
82
- if @status == 0 || fail == false
83
- result
84
- elsif fail
85
- raise Command::Error.new("\n" + cmd + "\n" + (out + err).join("\n") + "\n", status, out, err)
86
- end
87
- end
88
-
89
- # Exit status of the last command
90
- def status() @status end
91
-
92
- # Like command but returns true if the command exited with the expected status
93
- def command?(cmd, expect: 0)
94
- command(cmd, fail: false)
95
- @status == expect
96
- end
97
-
98
- module_function :command
99
- module_function :status
100
- module_function :command?
101
- end
102
-
@@ -1,82 +0,0 @@
1
-
2
- module Prick
3
- class Database
4
- attr_reader :name
5
- attr_reader :user
6
-
7
- def initialize(name, user)
8
- name != "" or raise "Illegal database name"
9
- @name = name
10
- @user = user
11
- @version = nil
12
- end
13
-
14
- def version(cache: true)
15
- if cache && @version
16
- @version
17
- else
18
- @version = begin
19
- version =
20
- if exist? && Rdbms.exist_table?(name, "prick", "versions")
21
- Rdbms.select(name, "select version from prick.versions")&.first&.first
22
- else
23
- nil
24
- end
25
- version && Version.new(version)
26
- end
27
- end
28
- end
29
-
30
- def version=(version)
31
- @version = version && Version.new(version)
32
- Rdbms.exec_sql(name, %(
33
- update prick.versions
34
- set major = '#{@version.major}',
35
- minor = '#{@version.minor}',
36
- patch = '#{@version.patch}',
37
- pre = '#{@version.pre}',
38
- version = '#{@version.to_s}'
39
- )) if @version
40
- @version
41
- end
42
-
43
- def exist?() Rdbms.exist_database?(name) end
44
- def create() Rdbms.create_database(name, owner: user) end
45
- def recreate() drop if exist?; create; @version = nil end
46
- def drop() Rdbms.drop_database(name, fail: false); @version = nil end
47
-
48
- def loaded?() !version.nil? end
49
-
50
- def load(file)
51
- !loaded? or raise Internal, "Database #{name} is already loaded"
52
- Rdbms.load(name, file, user: user)
53
- version # Provoke load of version
54
- end
55
-
56
- def save(file)
57
- loaded? or raise Internal, "Database #{name} is not loaded"
58
- Rdbms.save(name, file)
59
- @version = nil
60
- end
61
-
62
- # Hollow-out a database without dropping it. This is useful compared to a
63
- # simple drop database since it wont block on other sessions wont block
64
- def clean()
65
- if exist?
66
- schemas = Rdbms.select_values(
67
- "postgres",
68
- "select nspname from pg_namespace where nspowner != 10")
69
- for schema in schemas
70
- Rdbms.exec_sql(name, "drop schema \"#{schema}\" cascade")
71
- end
72
- Rdbms.exec_sql(name, "drop schema if exists public cascade")
73
- Rdbms.exec_sql(name, "create schema public authorization postgres")
74
- Rdbms.exec_sql(name, "grant usage, create on schema public to public")
75
- else
76
- create
77
- end
78
- end
79
-
80
- def to_s() name end
81
- end
82
- end