sequel-pg-comment 1.0.0 → 2.0.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.
- checksums.yaml +4 -4
- data/lib/sequel/extensions/pg_comment.rb +49 -9
- data/lib/sequel/extensions/pg_comment/database_methods.rb +132 -79
- data/lib/sequel/extensions/pg_comment/dataset_methods.rb +16 -1
- data/spec/alter_table_comment_spec.rb +1 -9
- data/spec/comment_for_spec.rb +10 -9
- data/spec/comment_on_spec.rb +22 -4
- data/spec/create_table_comment_spec.rb +3 -22
- data/spec/dataset_comment_spec.rb +20 -0
- data/spec/normalise_comment_spec.rb +2 -2
- metadata +3 -6
- data/lib/sequel/extensions/pg_comment/alter_table_generator_methods.rb +0 -126
- data/lib/sequel/extensions/pg_comment/create_table_generator_methods.rb +0 -159
- data/lib/sequel/extensions/pg_comment/sql_generator.rb +0 -257
- data/spec/sql_generator_spec.rb +0 -96
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3110fff14db57745785e517abfc96b0c67c8f806
|
4
|
+
data.tar.gz: 48ebb162456d9d455557dd019b6e706766bd9024
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d96a82d756893a528156fed4eeb202fc73d1b60bd7e4ad9c3f6863769427c2763216370d0093e25486191cbbd82b20cda1994363f8bcf30d5603b71b7b8b5614
|
7
|
+
data.tar.gz: 4a0d8e466cce89d873d9ea1061561ebbbc527813d35c52171925cdc76eb3215641f42fbd320787a4b76cf48fbc66a9c138bd9f16b2af8a95c76017206a2fbabe
|
@@ -1,9 +1,52 @@
|
|
1
|
-
module Sequel::
|
1
|
+
module Sequel::Postgres; end #:nodoc:
|
2
2
|
|
3
3
|
# PostgreSQL-specific extension to set and retrieve comments on
|
4
4
|
# all database objects.
|
5
|
-
#
|
6
|
-
module Sequel::
|
5
|
+
#
|
6
|
+
module Sequel::Postgres::Comment
|
7
|
+
# The types of PostgreSQL object that are commented on in their own
|
8
|
+
# right.
|
9
|
+
STANDALONE_TYPES = [
|
10
|
+
:aggregate,
|
11
|
+
:cast,
|
12
|
+
:collation,
|
13
|
+
:conversion,
|
14
|
+
:database,
|
15
|
+
:domain,
|
16
|
+
:extension,
|
17
|
+
:event_trigger,
|
18
|
+
:foreign_data_wrapper,
|
19
|
+
:foreign_table,
|
20
|
+
:function,
|
21
|
+
:index,
|
22
|
+
:large_object,
|
23
|
+
:materialized_view,
|
24
|
+
:operator,
|
25
|
+
:operator_class,
|
26
|
+
:operator_family,
|
27
|
+
:language,
|
28
|
+
:procedural_language,
|
29
|
+
:role,
|
30
|
+
:schema,
|
31
|
+
:sequence,
|
32
|
+
:server,
|
33
|
+
:table,
|
34
|
+
:tablespace,
|
35
|
+
:text_search_configuration,
|
36
|
+
:text_search_dictionary,
|
37
|
+
:text_search_parser,
|
38
|
+
:text_search_template,
|
39
|
+
:type,
|
40
|
+
:view
|
41
|
+
]
|
42
|
+
|
43
|
+
CONTAINED_TYPES = [
|
44
|
+
:column,
|
45
|
+
:constraint,
|
46
|
+
:rule,
|
47
|
+
:trigger
|
48
|
+
]
|
49
|
+
|
7
50
|
# Strip indenting whitespace from a comment string.
|
8
51
|
#
|
9
52
|
# Two rules are applied by this method:
|
@@ -49,7 +92,7 @@ module Sequel::Extension::PgComment
|
|
49
92
|
# @param comment [String] The comment to mangle for whitespace.
|
50
93
|
#
|
51
94
|
# @return [String] The normalised comment, with whitespace removed.
|
52
|
-
#
|
95
|
+
#
|
53
96
|
def self.normalise_comment(comment)
|
54
97
|
comment.tap do |s|
|
55
98
|
s.gsub!(/\A\n+/, '')
|
@@ -61,13 +104,10 @@ module Sequel::Extension::PgComment
|
|
61
104
|
end
|
62
105
|
end
|
63
106
|
|
64
|
-
require_relative 'pg_comment/sql_generator'
|
65
107
|
require_relative 'pg_comment/database_methods'
|
66
108
|
require_relative 'pg_comment/dataset_methods'
|
67
|
-
require_relative 'pg_comment/create_table_generator_methods'
|
68
|
-
require_relative 'pg_comment/alter_table_generator_methods'
|
69
109
|
|
70
110
|
Sequel::Database.register_extension(:pg_comment) do |db|
|
71
|
-
db.extend Sequel::
|
72
|
-
db.extend_datasets Sequel::
|
111
|
+
db.extend Sequel::Postgres::Comment::DatabaseMethods
|
112
|
+
db.extend_datasets Sequel::Postgres::Comment::DatasetMethods
|
73
113
|
end
|
@@ -1,42 +1,51 @@
|
|
1
1
|
# Support for setting and retrieving comments on all object types
|
2
2
|
# in a PostgreSQL database.
|
3
3
|
#
|
4
|
-
module Sequel::
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# that
|
11
|
-
# the
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
4
|
+
module Sequel::Postgres::Comment::DatabaseMethods
|
5
|
+
# @param type [Symbol] The object type you're looking to set the comment
|
6
|
+
# on. This is just the PostgreSQL type name, lowercased, with spaces
|
7
|
+
# replaced with underscores.
|
8
|
+
#
|
9
|
+
# @param id [Symbol, String, Array<Symbol, String>] The identifier of the
|
10
|
+
# object that you wish to comment on. For most types of object, this
|
11
|
+
# should be the literal name of the object. However, for objects which
|
12
|
+
# are "contained" in another object (columns in tables/views, and
|
13
|
+
# constraints, triggers, and rules in tables) you must pass the
|
14
|
+
# identifier as a two-element array, where the first element is the
|
15
|
+
# container table or view, and the second element is the contained
|
16
|
+
# object (column, constraint, rule, or trigger).
|
17
|
+
#
|
18
|
+
# In any event, when a `Symbol` is encountered, it is quoted for
|
19
|
+
# safety, and split into a schema and object name pair, if appropriate.
|
20
|
+
# If a `String` is passed, then **no escaping or quoting is done**.
|
21
|
+
# While this is a slight risk, it is necessary to allow you to
|
22
|
+
# reference complex object names which can't reasonably be described
|
23
|
+
# otherwise (`FUNCTION`, I'm looking at you).
|
18
24
|
#
|
19
25
|
# @param comment [String] The comment you wish to set for the database
|
20
26
|
# object.
|
21
27
|
#
|
22
|
-
# @
|
28
|
+
# @raise [Sequel::Error] if the specified `type` isn't recognised.
|
29
|
+
#
|
30
|
+
# @see {Sequel::Postgres::Comment.normalise_comment} for details on
|
23
31
|
# how the comment string is interpreted.
|
24
32
|
#
|
25
33
|
def comment_on(type, id, comment)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
34
|
+
if Sequel::Postgres::Comment::STANDALONE_TYPES.include?(type)
|
35
|
+
comment_on_standalone_type(type, id, comment)
|
36
|
+
elsif Sequel::Postgres::Comment::CONTAINED_TYPES.include?(type)
|
37
|
+
comment_on_contained_type(type, id, comment)
|
38
|
+
else
|
39
|
+
raise Sequel::Error,
|
40
|
+
"Unknown object type: #{type.inspect}"
|
31
41
|
end
|
32
|
-
|
33
|
-
execute(gen.generate)
|
34
42
|
end
|
35
43
|
|
44
|
+
|
36
45
|
# Retrieve the comment for a database object.
|
37
46
|
#
|
38
47
|
# @param object [#to_s] The name of the database object to retrieve. For
|
39
|
-
# most objects, this should be the literal name of the object.
|
48
|
+
# most objects, this should be the literal name of the object.
|
40
49
|
# However, for columns on tables and views, the name of the table/view
|
41
50
|
# should be a separated from the name of the column by a double
|
42
51
|
# underscore (ie `__`).
|
@@ -50,14 +59,19 @@ module Sequel::Extension::PgComment::DatabaseMethods
|
|
50
59
|
if object.index("__")
|
51
60
|
tbl, col = object.split("__", 2)
|
52
61
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
)
|
62
|
+
(select(Sequel.function(:col_description, :c__oid, :a__attnum).as(:comment)).
|
63
|
+
from(Sequel.as(:pg_class, :c)).
|
64
|
+
join(Sequel.as(:pg_attribute, :a), :c__oid => :a__attrelid).
|
65
|
+
where(:c__relname => tbl).
|
66
|
+
and(:a__attname => col).first || {})[:comment]
|
59
67
|
else
|
60
|
-
|
68
|
+
(select(
|
69
|
+
Sequel.function(
|
70
|
+
:obj_description,
|
71
|
+
Sequel.cast(object, :regclass),
|
72
|
+
"pg_class"
|
73
|
+
).as(:comment)
|
74
|
+
).first || {})[:comment]
|
61
75
|
end
|
62
76
|
end
|
63
77
|
|
@@ -78,51 +92,47 @@ module Sequel::Extension::PgComment::DatabaseMethods
|
|
78
92
|
end
|
79
93
|
|
80
94
|
#:nodoc:
|
81
|
-
# Enhanced
|
82
|
-
#
|
95
|
+
# Enhanced to support creating comments on columns, after the table
|
96
|
+
# itself (and hence all its columns) have been created.
|
83
97
|
#
|
84
|
-
def
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
98
|
+
def create_table_from_generator(name, generator, options)
|
99
|
+
generator.columns.each do |col|
|
100
|
+
if col[:comment]
|
101
|
+
comment_on(:column, [name, col[:name]], col[:comment])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
generator.constraints.each do |c|
|
106
|
+
case c[:type]
|
107
|
+
when :primary_key
|
108
|
+
c_name = c[:name] || "#{name}_pkey".to_sym
|
109
|
+
comment_on(:index, c_name, c[:comment])
|
110
|
+
when :foreign_key, :check
|
111
|
+
if c[:type] == :check && c[:name].nil?
|
112
|
+
raise Sequel::Error,
|
113
|
+
"Setting comments on unnamed check constraints is not supported"
|
114
|
+
end
|
115
|
+
c_name = c[:name] || "#{name}_#{c[:columns].first}_fkey".to_sym
|
116
|
+
comment_on(:constraint, [name, c_name], c[:comment])
|
117
|
+
when :unique
|
118
|
+
c_name = c[:name] || ([name] + c[:columns] + ["key"]).join("_").to_sym
|
119
|
+
comment_on(:index, c_name, c[:comment])
|
120
|
+
end
|
89
121
|
end
|
90
122
|
end
|
91
123
|
|
92
124
|
#:nodoc:
|
93
|
-
# Enhanced
|
94
|
-
#
|
95
|
-
#
|
96
|
-
# If you're wondering why we override the
|
97
|
-
# create_table_indexes_from_generator method, rather than
|
98
|
-
# create_table_from_generator, it's because the indexes method runs last,
|
99
|
-
# and we can only create our comments after the objects we're commenting
|
100
|
-
# on have been created. We *could* set some comments in
|
101
|
-
# create_table_from_generator, and then set index comments in
|
102
|
-
# create_table_indexes_from_generator, but why override two methods when
|
103
|
-
# you can just override one to get the same net result?
|
125
|
+
# Enhanced to support creating comments on indexes, after the indexes
|
126
|
+
# themselves have been created.
|
104
127
|
#
|
105
128
|
def create_table_indexes_from_generator(name, generator, options)
|
106
129
|
super
|
107
130
|
|
108
|
-
generator.
|
109
|
-
if
|
110
|
-
|
131
|
+
generator.indexes.each do |idx|
|
132
|
+
if idx[:comment]
|
133
|
+
i_name = idx[:name] || ([name] + idx[:columns] + ["index"]).join("_").to_sym
|
134
|
+
comment_on(:index, i_name, idx[:comment])
|
111
135
|
end
|
112
|
-
|
113
|
-
execute(sql_gen.generate)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
#:nodoc:
|
118
|
-
# Enhanced version to support setting comments on objects created in a
|
119
|
-
# block-form `alter_table` statement.
|
120
|
-
#
|
121
|
-
def alter_table_generator(&block)
|
122
|
-
super do
|
123
|
-
extend Sequel::Extension::PgComment::AlterTableGeneratorMethods
|
124
|
-
@comments = []
|
125
|
-
instance_eval(&block) if block
|
126
136
|
end
|
127
137
|
end
|
128
138
|
|
@@ -133,12 +143,30 @@ module Sequel::Extension::PgComment::DatabaseMethods
|
|
133
143
|
def apply_alter_table_generator(name, generator)
|
134
144
|
super
|
135
145
|
|
136
|
-
|
137
|
-
|
138
|
-
|
146
|
+
schema, table = schema_and_table(name)
|
147
|
+
fqtable = [schema, table].compact.map { |e| literal e.to_sym }.join('.')
|
148
|
+
|
149
|
+
generator.operations.each do |op|
|
150
|
+
if op[:comment]
|
151
|
+
case op[:op]
|
152
|
+
when :add_column
|
153
|
+
comment_on(:column, [name, op[:name]], op[:comment])
|
154
|
+
when :add_constraint
|
155
|
+
case op[:type]
|
156
|
+
when :primary_key
|
157
|
+
comment_on(:index, "#{name}_pkey".to_sym, op[:comment])
|
158
|
+
when :foreign_key, :check
|
159
|
+
c_name = op[:name] || "#{name}_#{op[:columns].first}_fkey".to_sym
|
160
|
+
comment_on(:constraint, [name, c_name], op[:comment])
|
161
|
+
when :unique
|
162
|
+
c_name = op[:name] || ([name] + op[:columns] + ["key"]).join("_").to_sym
|
163
|
+
comment_on(:index, c_name, op[:comment])
|
164
|
+
end
|
165
|
+
when :add_index
|
166
|
+
c_name = op[:name] || ([name] + op[:columns] + ["index"]).join("_").to_sym
|
167
|
+
comment_on(:index, c_name, op[:comment])
|
168
|
+
end
|
139
169
|
end
|
140
|
-
|
141
|
-
execute(sql_gen.generate)
|
142
170
|
end
|
143
171
|
end
|
144
172
|
|
@@ -160,16 +188,41 @@ module Sequel::Extension::PgComment::DatabaseMethods
|
|
160
188
|
|
161
189
|
private
|
162
190
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
191
|
+
def comment_on_standalone_type(type, id, comment)
|
192
|
+
run "COMMENT ON #{type.to_s.gsub("_", " ").upcase} #{quoted_schema_and_table id} IS #{literal comment}"
|
193
|
+
end
|
194
|
+
|
195
|
+
def comment_on_contained_type(type, id, comment)
|
196
|
+
unless id.is_a?(Array) and id.length == 2
|
197
|
+
raise Sequel::Error,
|
198
|
+
"Invalid ID for #{type.inspect}: must be a two-element array"
|
199
|
+
end
|
200
|
+
|
201
|
+
fqtable = quoted_schema_and_table(id[0])
|
202
|
+
fqname = if id[1].is_a?(Symbol)
|
203
|
+
quote_identifier id[1]
|
204
|
+
elsif id[1].is_a?(String)
|
205
|
+
id[1]
|
206
|
+
else
|
207
|
+
raise Sequel::Error,
|
208
|
+
"Invalid type for object ID: must be a Symbol or String"
|
209
|
+
end
|
210
|
+
|
211
|
+
if type == :column
|
212
|
+
run "COMMENT ON COLUMN #{fqtable}.#{fqname} IS #{literal comment}"
|
213
|
+
else
|
214
|
+
run "COMMENT ON #{type.to_s.gsub("_", " ").upcase} #{fqname} ON #{fqtable} IS #{literal comment}"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def quoted_schema_and_table(id)
|
219
|
+
if id.is_a?(Symbol)
|
220
|
+
literal id
|
221
|
+
elsif id.is_a?(String)
|
222
|
+
id
|
171
223
|
else
|
172
|
-
|
224
|
+
raise Sequel::Error,
|
225
|
+
"Invalid type for ID: #{id.inspect} (must by symbol or string)"
|
173
226
|
end
|
174
227
|
end
|
175
228
|
end
|
@@ -6,7 +6,7 @@
|
|
6
6
|
# Will retrieve the comment for `foo_tbl.some_column`, if such a
|
7
7
|
# column exists.
|
8
8
|
#
|
9
|
-
module Sequel::
|
9
|
+
module Sequel::Postgres::Comment::DatasetMethods
|
10
10
|
# Retrieve the comment for the column named `col` in the "primary" table
|
11
11
|
# for this dataset.
|
12
12
|
#
|
@@ -19,4 +19,19 @@ module Sequel::Extension::PgComment::DatasetMethods
|
|
19
19
|
def comment_for(col)
|
20
20
|
db.comment_for("#{first_source_table}__#{col}")
|
21
21
|
end
|
22
|
+
|
23
|
+
# Retrieve the comment for the "primary" table in the dataset.
|
24
|
+
#
|
25
|
+
# @return [String, NilClass] The comment for the table, or `nil` if there
|
26
|
+
# is no comment defined.
|
27
|
+
#
|
28
|
+
# @example Simple, single-table dataset
|
29
|
+
# db[:foo].comment # => comment for table foo
|
30
|
+
#
|
31
|
+
# @example Multi-table dataset
|
32
|
+
# db[:foo].join(:bar, ...).where { id < 20 }.comment # => comment for table foo
|
33
|
+
#
|
34
|
+
def comment
|
35
|
+
db.comment_for(first_source_table)
|
36
|
+
end
|
22
37
|
end
|
@@ -38,14 +38,6 @@ describe "schema modification" do
|
|
38
38
|
to eq("COMMENT ON COLUMN \"foo\".\"bar_id\" IS 'Over there!'")
|
39
39
|
end
|
40
40
|
|
41
|
-
it "sets a column comment on add_foreign_key with custom constraint name" do
|
42
|
-
db.alter_table :foo do
|
43
|
-
add_foreign_key :bar_id, :bar, :comment => "Over there!", :name => :fkr
|
44
|
-
end
|
45
|
-
expect(db.sqls.last).
|
46
|
-
to eq("COMMENT ON COLUMN \"foo\".\"bar_id\" IS 'Over there!'")
|
47
|
-
end
|
48
|
-
|
49
41
|
it "sets a constraint comment on composite add_foreign_key" do
|
50
42
|
db.alter_table :foo do
|
51
43
|
add_foreign_key [:name, :dob], :bar, :comment => "Over there!"
|
@@ -96,7 +88,7 @@ describe "schema modification" do
|
|
96
88
|
|
97
89
|
it "sets a constraint comment" do
|
98
90
|
db.alter_table :foo do
|
99
|
-
add_constraint(:min_length, :comment => "Bigger is better!") do
|
91
|
+
add_constraint(:name => :min_length, :comment => "Bigger is better!") do
|
100
92
|
char_length(name) > 2
|
101
93
|
end
|
102
94
|
end
|
data/spec/comment_for_spec.rb
CHANGED
@@ -9,26 +9,27 @@ describe "#comment_for" do
|
|
9
9
|
it "gets a table comment" do
|
10
10
|
db.comment_for(:foo)
|
11
11
|
expect(db.sqls).
|
12
|
-
to eq([
|
12
|
+
to eq([%{SELECT obj_description(CAST('foo' AS regclass), 'pg_class') } +
|
13
|
+
%{AS \"comment\" LIMIT 1}])
|
13
14
|
end
|
14
15
|
|
15
16
|
it "gets a column comment" do
|
16
17
|
db.comment_for(:foo__column)
|
17
18
|
expect(db.sqls).
|
18
|
-
to eq([
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
to eq([%{SELECT col_description("c"."oid", "a"."attnum") AS "comment" } +
|
20
|
+
%{FROM "pg_class" AS "c" } +
|
21
|
+
%{INNER JOIN "pg_attribute" AS "a" ON ("c"."oid" = "a"."attrelid") } +
|
22
|
+
%{WHERE (("c"."relname" = 'foo') AND ("a"."attname" = 'column')) LIMIT 1}
|
22
23
|
])
|
23
24
|
end
|
24
25
|
|
25
26
|
it "gets a column comment via the dataset" do
|
26
27
|
db[:foo].comment_for(:column)
|
27
28
|
expect(db.sqls).
|
28
|
-
to eq([
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
to eq([%{SELECT col_description("c"."oid", "a"."attnum") AS "comment" } +
|
30
|
+
%{FROM "pg_class" AS "c" } +
|
31
|
+
%{INNER JOIN "pg_attribute" AS "a" ON ("c"."oid" = "a"."attrelid") } +
|
32
|
+
%{WHERE (("c"."relname" = 'foo') AND ("a"."attname" = 'column')) LIMIT 1}
|
32
33
|
])
|
33
34
|
end
|
34
35
|
end
|
data/spec/comment_on_spec.rb
CHANGED
@@ -12,8 +12,8 @@ describe "#comment_on" do
|
|
12
12
|
to eq(["COMMENT ON TABLE \"foo\" IS 'Ohai!'"])
|
13
13
|
end
|
14
14
|
|
15
|
-
it "accepts a
|
16
|
-
db.comment_on(
|
15
|
+
it "accepts a symbol as object name" do
|
16
|
+
db.comment_on(:table, :foo, "Ohai!")
|
17
17
|
expect(db.sqls).
|
18
18
|
to eq(["COMMENT ON TABLE \"foo\" IS 'Ohai!'"])
|
19
19
|
end
|
@@ -39,7 +39,19 @@ describe "#comment_on" do
|
|
39
39
|
it "explodes if an invalid object type is given" do
|
40
40
|
expect do
|
41
41
|
db.comment_on(:foobooblee, :foo, "O'hai!")
|
42
|
-
end.to raise_error(
|
42
|
+
end.to raise_error(Sequel::Error)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "explodes if an invalid ID type is given for a table" do
|
46
|
+
expect do
|
47
|
+
db.comment_on(:table, [:foo, :bar], "Ohai!")
|
48
|
+
end.to raise_error(Sequel::Error)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "explodes if an invalid ID type is given for a column" do
|
52
|
+
expect do
|
53
|
+
db.comment_on(:column, :foo, "Ohai!")
|
54
|
+
end.to raise_error(Sequel::Error)
|
43
55
|
end
|
44
56
|
|
45
57
|
it "quotes the object name" do
|
@@ -49,8 +61,14 @@ describe "#comment_on" do
|
|
49
61
|
end
|
50
62
|
|
51
63
|
it "sets a column comment correctly" do
|
52
|
-
db.comment_on(:column, :
|
64
|
+
db.comment_on(:column, [:foo, :bar_id], "Ohai, column!")
|
53
65
|
expect(db.sqls).
|
54
66
|
to eq(["COMMENT ON COLUMN \"foo\".\"bar_id\" IS 'Ohai, column!'"])
|
55
67
|
end
|
68
|
+
|
69
|
+
it "sets a trigger comment correctly" do
|
70
|
+
db.comment_on(:trigger, [:foo, :bar_id], "Whoa there, trigger!")
|
71
|
+
expect(db.sqls).
|
72
|
+
to eq(["COMMENT ON TRIGGER \"bar_id\" ON \"foo\" IS 'Whoa there, trigger!'"])
|
73
|
+
end
|
56
74
|
end
|
@@ -43,17 +43,6 @@ describe "schema creation" do
|
|
43
43
|
to eq("COMMENT ON COLUMN \"foo\".\"id\" IS 'I am unique'")
|
44
44
|
end
|
45
45
|
|
46
|
-
it "sets a primary key comment on a custom constraint name" do
|
47
|
-
db.create_table :foo do
|
48
|
-
primary_key :id,
|
49
|
-
:comment => "I am unique",
|
50
|
-
:name => :custom_pk
|
51
|
-
end
|
52
|
-
|
53
|
-
expect(db.sqls.last).
|
54
|
-
to eq("COMMENT ON COLUMN \"foo\".\"id\" IS 'I am unique'")
|
55
|
-
end
|
56
|
-
|
57
46
|
it "sets a composite primary key comment" do
|
58
47
|
db.create_table :foo do
|
59
48
|
primary_key [:bar, :baz],
|
@@ -90,7 +79,7 @@ describe "schema creation" do
|
|
90
79
|
end
|
91
80
|
|
92
81
|
expect(db.sqls.last).
|
93
|
-
to eq("COMMENT ON CONSTRAINT \"
|
82
|
+
to eq("COMMENT ON CONSTRAINT \"foo_bar_name_fkey\" ON \"foo\" IS 'Over there!'")
|
94
83
|
end
|
95
84
|
|
96
85
|
it "sets a composite foreign_key comment with custom name" do
|
@@ -168,26 +157,18 @@ describe "schema creation" do
|
|
168
157
|
|
169
158
|
it "sets a constraint comment" do
|
170
159
|
db.create_table :foo do
|
171
|
-
constraint :clamp, :
|
160
|
+
constraint({ :name => :clamp, :comment => "Toight" }, :num => 1..5)
|
172
161
|
end
|
173
162
|
|
174
163
|
expect(db.sqls.last).
|
175
164
|
to eq("COMMENT ON CONSTRAINT \"clamp\" ON \"foo\" IS 'Toight'")
|
176
165
|
end
|
177
166
|
|
178
|
-
it "blows up trying to an unnamed constraint comment" do
|
179
|
-
expect do
|
180
|
-
db.create_table :foo do
|
181
|
-
constraint nil, :num => 1..5, :comment => "Kaboom"
|
182
|
-
end
|
183
|
-
end.to raise_error(/not supported/i)
|
184
|
-
end
|
185
|
-
|
186
167
|
it "blows up trying to comment on a check" do
|
187
168
|
expect do
|
188
169
|
db.create_table :foo do
|
189
170
|
check(:comment => "Kaboom") { char_length(name) > 2 }
|
190
171
|
end
|
191
|
-
end.to raise_error(/not supported/i)
|
172
|
+
end.to raise_error(Sequel::Error, /not supported/i)
|
192
173
|
end
|
193
174
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require 'sequel'
|
3
|
+
|
4
|
+
describe "Dataset#comment" do
|
5
|
+
let(:db) { Sequel.connect("mock://postgres").extension(:pg_comment) }
|
6
|
+
|
7
|
+
it "gets the comment for the table" do
|
8
|
+
db[:foo].comment
|
9
|
+
expect(db.sqls).
|
10
|
+
to eq([%{SELECT obj_description(CAST('foo' AS regclass), 'pg_class') } +
|
11
|
+
%{AS "comment" LIMIT 1}])
|
12
|
+
end
|
13
|
+
|
14
|
+
it "gets the comment for the first table" do
|
15
|
+
db[:foo].join(:bar, :id => :bar_id).where { foo__id < 20 }.comment
|
16
|
+
expect(db.sqls).
|
17
|
+
to eq([%{SELECT obj_description(CAST('foo' AS regclass), 'pg_class') } +
|
18
|
+
%{AS "comment" LIMIT 1}])
|
19
|
+
end
|
20
|
+
end
|
@@ -2,9 +2,9 @@ require_relative 'spec_helper'
|
|
2
2
|
require 'sequel'
|
3
3
|
require 'sequel/extensions/pg_comment'
|
4
4
|
|
5
|
-
context "Sequel::
|
5
|
+
context "Sequel::Postgres::Comment.normalise_comment" do
|
6
6
|
def nc(s)
|
7
|
-
Sequel::
|
7
|
+
Sequel::Postgres::Comment.normalise_comment(s)
|
8
8
|
end
|
9
9
|
|
10
10
|
it "does nothing to a string with no leading whitespace" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel-pg-comment
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Palmer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: git-version-bump
|
@@ -199,11 +199,8 @@ files:
|
|
199
199
|
- README.md
|
200
200
|
- Rakefile
|
201
201
|
- lib/sequel/extensions/pg_comment.rb
|
202
|
-
- lib/sequel/extensions/pg_comment/alter_table_generator_methods.rb
|
203
|
-
- lib/sequel/extensions/pg_comment/create_table_generator_methods.rb
|
204
202
|
- lib/sequel/extensions/pg_comment/database_methods.rb
|
205
203
|
- lib/sequel/extensions/pg_comment/dataset_methods.rb
|
206
|
-
- lib/sequel/extensions/pg_comment/sql_generator.rb
|
207
204
|
- sequel-pg-comment.gemspec
|
208
205
|
- spec/alter_table_comment_spec.rb
|
209
206
|
- spec/comment_for_spec.rb
|
@@ -211,10 +208,10 @@ files:
|
|
211
208
|
- spec/create_join_table_comment_spec.rb
|
212
209
|
- spec/create_table_comment_spec.rb
|
213
210
|
- spec/create_view_comment_spec.rb
|
211
|
+
- spec/dataset_comment_spec.rb
|
214
212
|
- spec/extension_spec.rb
|
215
213
|
- spec/normalise_comment_spec.rb
|
216
214
|
- spec/spec_helper.rb
|
217
|
-
- spec/sql_generator_spec.rb
|
218
215
|
homepage: http://theshed.hezmatt.org/sequel-pg-comment
|
219
216
|
licenses: []
|
220
217
|
metadata: {}
|
@@ -1,126 +0,0 @@
|
|
1
|
-
#:nodoc:
|
2
|
-
# Enhancements to the standard schema modification methods in a
|
3
|
-
# block-form `alter_table` method, to support setting comments via the
|
4
|
-
# `:comment` option.
|
5
|
-
#
|
6
|
-
# Note that not every schema modification method is enhanced in this module;
|
7
|
-
# some modifications are implemneted in terms of more fundamental methods,
|
8
|
-
# and so do not require their own method here. For example, `add_foreign_key`
|
9
|
-
# with a single column is handled by `add_column`, and so doesn't require its
|
10
|
-
# own implementation. Rest assured that all schema modification methods
|
11
|
-
# *should* accept a `:comment` option, and set a comment in the database. If
|
12
|
-
# you find one that doesn't, please file a bug.
|
13
|
-
#
|
14
|
-
module Sequel::Extension::PgComment::AlterTableGeneratorMethods
|
15
|
-
attr_reader :comments
|
16
|
-
|
17
|
-
include Sequel::Extension::PgComment
|
18
|
-
|
19
|
-
# Enhanced version of the `add_column` schema modification method,
|
20
|
-
# which supports setting a comment on the column.
|
21
|
-
#
|
22
|
-
# @option [String] :comment The comment to set on the column
|
23
|
-
# that is being added.
|
24
|
-
#
|
25
|
-
def add_column(*args)
|
26
|
-
super
|
27
|
-
|
28
|
-
if args.last.is_a?(Hash) && args.last[:comment]
|
29
|
-
comments << SqlGenerator.create(:column, args.first, args.last[:comment])
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# Enhanced version of the `add_composite_primary_key` schema modification
|
34
|
-
# method, which supports setting a comment on the index.
|
35
|
-
#
|
36
|
-
# @option [String] :comment The comment to set on the index that is being
|
37
|
-
# added.
|
38
|
-
#
|
39
|
-
def add_composite_primary_key(columns, opts)
|
40
|
-
super
|
41
|
-
|
42
|
-
if opts[:comment]
|
43
|
-
comments << PrefixSqlGenerator.new(:index, :_pkey, opts[:comment])
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# Enhanced version of the `add_composite_foreign_key` schema modification
|
48
|
-
# method, which supports setting a comment on the constraint.
|
49
|
-
#
|
50
|
-
# @option [String] :comment The comment to set on the constraint that is being
|
51
|
-
# added.
|
52
|
-
#
|
53
|
-
def add_composite_foreign_key(columns, table, opts)
|
54
|
-
super
|
55
|
-
|
56
|
-
if opts[:comment]
|
57
|
-
comments << if opts[:name]
|
58
|
-
SqlGenerator.create(:constraint, opts[:name], opts[:comment])
|
59
|
-
else
|
60
|
-
PrefixSqlGenerator.new(
|
61
|
-
:constraint,
|
62
|
-
"_#{columns.first}_fkey".to_sym,
|
63
|
-
opts[:comment]
|
64
|
-
)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Enhanced version of the `add_index` schema modification method, which
|
70
|
-
# supports setting a comment on the index.
|
71
|
-
#
|
72
|
-
# @option [String] :comment The comment to set on the index that is being
|
73
|
-
# added.
|
74
|
-
#
|
75
|
-
def add_index(columns, opts = OPTS)
|
76
|
-
if opts[:comment]
|
77
|
-
comments << if opts[:name]
|
78
|
-
SqlGenerator.create(:index, opts[:name], opts[:comment])
|
79
|
-
else
|
80
|
-
PrefixSqlGenerator.new(
|
81
|
-
:index,
|
82
|
-
"_#{[columns].flatten.map(&:to_s).join("_")}_index".to_sym,
|
83
|
-
opts[:comment]
|
84
|
-
)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
# Enhanced version of the `add_constraint` schema modification method,
|
90
|
-
# which supports setting a comment on the constraint.
|
91
|
-
#
|
92
|
-
# @option [String] :comment The comment to set on the constraint that is
|
93
|
-
# being added.
|
94
|
-
#
|
95
|
-
def add_constraint(name, *args, &block)
|
96
|
-
super
|
97
|
-
|
98
|
-
opts = args.last.is_a?(Hash) ? args.last : {}
|
99
|
-
|
100
|
-
if opts[:comment]
|
101
|
-
comments << SqlGenerator.create(:constraint, name, opts[:comment])
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# Enhanced version of the `add_unique_constraint` schema modification
|
106
|
-
# method, which supports setting a comment on the index.
|
107
|
-
#
|
108
|
-
# @option [String] :comment The comment to set on the index that is being
|
109
|
-
# added.
|
110
|
-
#
|
111
|
-
def add_unique_constraint(columns, opts = OPTS)
|
112
|
-
super
|
113
|
-
|
114
|
-
if opts[:comment]
|
115
|
-
comments << if opts[:name]
|
116
|
-
SqlGenerator.create(:index, opts[:name], opts[:comment])
|
117
|
-
else
|
118
|
-
PrefixSqlGenerator.new(
|
119
|
-
:index,
|
120
|
-
"_#{[columns].flatten.map(&:to_s).join("_")}_key".to_sym,
|
121
|
-
opts[:comment]
|
122
|
-
)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
@@ -1,159 +0,0 @@
|
|
1
|
-
#:nodoc:
|
2
|
-
# Enhancements to the standard schema modification methods in a
|
3
|
-
# block-form `create_table` method, to support setting comments via the
|
4
|
-
# `:comment` option.
|
5
|
-
#
|
6
|
-
module Sequel::Extension::PgComment::CreateTableGeneratorMethods
|
7
|
-
# An array of all the comments that this generator has seen fit to
|
8
|
-
# create.
|
9
|
-
#
|
10
|
-
# @return [Array<SqlGenerator>]
|
11
|
-
#
|
12
|
-
attr_reader :comments
|
13
|
-
|
14
|
-
include Sequel::Extension::PgComment
|
15
|
-
|
16
|
-
# Enhanced version of the `column` table definition method, which
|
17
|
-
# supports setting a comment on the column.
|
18
|
-
#
|
19
|
-
# @option [String] :comment The comment to set on the column that is
|
20
|
-
# being defined.
|
21
|
-
#
|
22
|
-
def column(*args)
|
23
|
-
super
|
24
|
-
|
25
|
-
if args.last.is_a?(Hash) && args.last[:comment]
|
26
|
-
comments << SqlGenerator.create(:column, args.first, args.last[:comment])
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# Enhanced version of the `primary_key` table definition method, which
|
31
|
-
# supports setting a comment on either the column or constraint.
|
32
|
-
#
|
33
|
-
# If the primary key is composite (`name` is an array), then the comment
|
34
|
-
# will be placed on the index. Otherwise, the comment will be set
|
35
|
-
# on the column itself.
|
36
|
-
#
|
37
|
-
# @option [String] :comment The comment to set on the column or
|
38
|
-
# index that is being defined.
|
39
|
-
#
|
40
|
-
def primary_key(name, *args)
|
41
|
-
if args.last.is_a?(Hash) && args.last[:comment] and !name.is_a? Array
|
42
|
-
# The composite primary key case will be handled by the
|
43
|
-
# `composite_primary_key` method, so we don't have to deal with it
|
44
|
-
# here.
|
45
|
-
comments << SqlGenerator.create(:column, name, args.last[:comment])
|
46
|
-
end
|
47
|
-
|
48
|
-
super
|
49
|
-
end
|
50
|
-
|
51
|
-
# Enhanced version of the `composite_primary_key` table definition method,
|
52
|
-
# which supports setting a comment on the primary key index.
|
53
|
-
#
|
54
|
-
# @option [String] :comment The comment to set on the primary key index.
|
55
|
-
#
|
56
|
-
def composite_primary_key(columns, *args)
|
57
|
-
if args.last.is_a?(Hash) and args.last[:comment]
|
58
|
-
if args.last[:name]
|
59
|
-
comments << SqlGenerator.create(
|
60
|
-
:index,
|
61
|
-
args.last[:name],
|
62
|
-
args.last[:comment]
|
63
|
-
)
|
64
|
-
else
|
65
|
-
comments << PrefixSqlGenerator.new(:index, :_pkey, args.last[:comment])
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
super
|
70
|
-
end
|
71
|
-
|
72
|
-
# Enhanced version of the `composite_foreign_key` table definition method,
|
73
|
-
# which supports setting a comment on the FK constraint.
|
74
|
-
#
|
75
|
-
# @option [String] :comment The comment to set on the foreign key constraint.
|
76
|
-
#
|
77
|
-
def composite_foreign_key(columns, opts)
|
78
|
-
if opts.is_a?(Hash) and opts[:comment] and opts[:table]
|
79
|
-
if opts[:name]
|
80
|
-
comments << SqlGenerator.create(
|
81
|
-
:constraint,
|
82
|
-
opts[:name],
|
83
|
-
opts[:comment]
|
84
|
-
)
|
85
|
-
else
|
86
|
-
comments << SqlGenerator.create(
|
87
|
-
:constraint,
|
88
|
-
"#{opts[:table]}_#{columns.first}_fkey".to_sym,
|
89
|
-
opts[:comment]
|
90
|
-
)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
super
|
95
|
-
end
|
96
|
-
|
97
|
-
# Enhanced version of the `index` table definition method,
|
98
|
-
# which supports setting a comment on the index.
|
99
|
-
#
|
100
|
-
# @option [String] :comment The comment to set on the index that is being
|
101
|
-
# defined.
|
102
|
-
#
|
103
|
-
def index(columns, opts = OPTS)
|
104
|
-
if opts[:comment]
|
105
|
-
if opts[:name]
|
106
|
-
comments << SqlGenerator.create(:index, opts[:name], opts[:comment])
|
107
|
-
else
|
108
|
-
comments << PrefixSqlGenerator.new(
|
109
|
-
:index,
|
110
|
-
("_" + [columns].flatten.map(&:to_s).join('_') + "_index").to_sym,
|
111
|
-
opts[:comment]
|
112
|
-
)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
super
|
117
|
-
end
|
118
|
-
|
119
|
-
# Enhanced version of the `unique` table definition method,
|
120
|
-
# which supports setting a comment on the unique index.
|
121
|
-
#
|
122
|
-
# @option [String] :comment The comment to set on the index that will be
|
123
|
-
# defined.
|
124
|
-
#
|
125
|
-
def unique(columns, opts = OPTS)
|
126
|
-
if opts[:comment]
|
127
|
-
if opts[:name]
|
128
|
-
comments << SqlGenerator.create(:index, opts[:name], opts[:comment])
|
129
|
-
else
|
130
|
-
comments << PrefixSqlGenerator.new(
|
131
|
-
:index,
|
132
|
-
("_" + [columns].flatten.map(&:to_s).join('_') + "_key").to_sym,
|
133
|
-
opts[:comment]
|
134
|
-
)
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
super
|
139
|
-
end
|
140
|
-
|
141
|
-
# Enhanced version of the `constraint` table definition method,
|
142
|
-
# which supports setting a comment on the constraint.
|
143
|
-
#
|
144
|
-
# @option [String] :comment The comment to set on the constraint that is
|
145
|
-
# being defined.
|
146
|
-
#
|
147
|
-
def constraint(name, *args, &block)
|
148
|
-
opts = name.is_a?(Hash) ? name : (args.last.is_a?(Hash) ? args.last : {})
|
149
|
-
|
150
|
-
if opts[:comment]
|
151
|
-
if name
|
152
|
-
comments << SqlGenerator.create(:constraint, name, opts[:comment])
|
153
|
-
else
|
154
|
-
raise RuntimeError,
|
155
|
-
"Setting comments on unnamed or check constraints is not supported"
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
@@ -1,257 +0,0 @@
|
|
1
|
-
module Sequel::Extension::PgComment
|
2
|
-
#:nodoc:
|
3
|
-
# Generate SQL to set a comment.
|
4
|
-
#
|
5
|
-
class SqlGenerator
|
6
|
-
# The PostgreSQL object types which this class knows how to generate
|
7
|
-
# comment SQL for.
|
8
|
-
#
|
9
|
-
OBJECT_TYPES = %w{AGGREGATE
|
10
|
-
CAST
|
11
|
-
COLLATION
|
12
|
-
CONVERSION
|
13
|
-
DATABASE
|
14
|
-
DOMAIN
|
15
|
-
EXTENSION
|
16
|
-
EVENT\ TRIGGER
|
17
|
-
FOREIGN\ DATA\ WRAPPER
|
18
|
-
FOREIGN\ TABLE
|
19
|
-
FUNCTION
|
20
|
-
INDEX
|
21
|
-
LARGE\ OBJECT
|
22
|
-
MATERIALIZED\ VIEW
|
23
|
-
OPERATOR
|
24
|
-
OPERATOR\ CLASS
|
25
|
-
OPERATOR\ FAMILY
|
26
|
-
PROCEDURAL\ LANGUAGE
|
27
|
-
LANGUAGE
|
28
|
-
ROLE
|
29
|
-
SCHEMA
|
30
|
-
SEQUENCE
|
31
|
-
SERVER
|
32
|
-
TABLE
|
33
|
-
TABLESPACE
|
34
|
-
TEXT\ SEARCH\ CONFIGURATION
|
35
|
-
TEXT\ SEARCH\ DICTIONARY
|
36
|
-
TEXT\ SEARCH\ PARSER
|
37
|
-
TEXT\ SEARCH\ TEMPLATE
|
38
|
-
TYPE
|
39
|
-
VIEW
|
40
|
-
}
|
41
|
-
|
42
|
-
# Find the correct class for a given object type, and instantiate a
|
43
|
-
# new one of them.
|
44
|
-
#
|
45
|
-
# @param object_type [String, Symbol] The type of object we're going
|
46
|
-
# to comment on. Strings and symbols are both fine, and any case
|
47
|
-
# is fine, too. Any underscores get turned into spaces. Apart from
|
48
|
-
# that, it needs to be the exact name that PostgreSQL uses for the given
|
49
|
-
# type.
|
50
|
-
#
|
51
|
-
# @param object_name [String, Symbol] The name of the database object to
|
52
|
-
# set the comment on. A string is considered "already quoted", and hence
|
53
|
-
# is not escaped any further. A symbol is run through the usual Sequel
|
54
|
-
# identifier escaping code before being unleashed on the world.
|
55
|
-
#
|
56
|
-
# @param comment [String] The comment to set.
|
57
|
-
#
|
58
|
-
# @return [SqlGenerator] Some sort of `SqlGenerator` object, or a subclass.
|
59
|
-
#
|
60
|
-
# @raise [ArgumentError] if you passed in an `object_type` that we don't
|
61
|
-
# know about.
|
62
|
-
#
|
63
|
-
def self.create(object_type, object_name, comment)
|
64
|
-
generators.each do |gclass|
|
65
|
-
if gclass.handles?(object_type)
|
66
|
-
return gclass.new(object_type, object_name, comment)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
raise ArgumentError,
|
71
|
-
"Unrecognised object type #{object_type.inspect}"
|
72
|
-
end
|
73
|
-
|
74
|
-
# Return whether or not this class supports the specified object type.
|
75
|
-
#
|
76
|
-
# @param object_type [String, Symbol] @see {.create}
|
77
|
-
#
|
78
|
-
# @return [TrueClass, FalseClass] whether or not this class can handle
|
79
|
-
# the object type you passed.
|
80
|
-
#
|
81
|
-
def self.handles?(object_type)
|
82
|
-
self.const_get(:OBJECT_TYPES).include?(object_type.to_s.upcase.gsub('_', ' '))
|
83
|
-
end
|
84
|
-
|
85
|
-
private
|
86
|
-
|
87
|
-
# Return all known `SqlGenerator` classes.
|
88
|
-
#
|
89
|
-
def self.generators
|
90
|
-
@generators ||= ObjectSpace.each_object(Class).select do |klass|
|
91
|
-
klass.ancestors.include?(self)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
# We just need this so we can quote things.
|
96
|
-
def self.mock_db
|
97
|
-
@mock_db ||= Sequel.connect("mock://postgres")
|
98
|
-
end
|
99
|
-
|
100
|
-
public
|
101
|
-
|
102
|
-
# The canonicalised string (that is, all-uppercase, with words
|
103
|
-
# separated by spaces) for the object type of this SQL generator.
|
104
|
-
#
|
105
|
-
attr_reader :object_type
|
106
|
-
|
107
|
-
# The raw (might-be-a-symbol, might-be-a-string) object name that
|
108
|
-
# was passed to us originally.
|
109
|
-
#
|
110
|
-
attr_reader :object_name
|
111
|
-
|
112
|
-
# The comment.
|
113
|
-
attr_reader :comment
|
114
|
-
|
115
|
-
# Spawn a new SqlGenerator.
|
116
|
-
#
|
117
|
-
# @see {.create}
|
118
|
-
#
|
119
|
-
def initialize(object_type, object_name, comment)
|
120
|
-
@object_type = object_type.to_s.upcase.gsub('_', ' ')
|
121
|
-
@object_name = object_name
|
122
|
-
@comment = comment
|
123
|
-
end
|
124
|
-
|
125
|
-
# SQL to set a comment on the object of our affection.
|
126
|
-
#
|
127
|
-
# @return [String] The SQL needed to set the comment.
|
128
|
-
#
|
129
|
-
def generate
|
130
|
-
quoted_object_name = case object_name
|
131
|
-
when Symbol
|
132
|
-
literal object_name
|
133
|
-
else
|
134
|
-
object_name
|
135
|
-
end
|
136
|
-
|
137
|
-
"COMMENT ON #{object_type} #{quoted_object_name} IS #{literal comment.to_s}"
|
138
|
-
end
|
139
|
-
|
140
|
-
private
|
141
|
-
|
142
|
-
# Quote the provided database object (a symbol) or string value
|
143
|
-
# (a string).
|
144
|
-
#
|
145
|
-
def literal(s)
|
146
|
-
self.class.mock_db.literal(s)
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
#:nodoc:
|
151
|
-
# A specialised generator for object types that live "inside" a
|
152
|
-
# table. Specifically, those types are columns, constraints,
|
153
|
-
# rules, and triggers.
|
154
|
-
#
|
155
|
-
# They get their own subclass because these object types can be
|
156
|
-
# manipulated inside a `create_table` or `alter_table` block, and at the
|
157
|
-
# time the block is evaluated, the code doesn't know the name of the
|
158
|
-
# table in which they are contained. So, we just stuff what we *do* know
|
159
|
-
# into these generators, and then when all's done, we can go to each of
|
160
|
-
# these generators, say "this is your table name", and then ask for the
|
161
|
-
# generated SQL.
|
162
|
-
#
|
163
|
-
class TableObjectSqlGenerator < SqlGenerator
|
164
|
-
# The few object types that this class handles.
|
165
|
-
OBJECT_TYPES = %w{COLUMN CONSTRAINT RULE TRIGGER}
|
166
|
-
|
167
|
-
# The name of the object which contains the object which is the direct
|
168
|
-
# target of this SQL generator. Basically, it's the table name.
|
169
|
-
attr_accessor :table_name
|
170
|
-
|
171
|
-
# Overridden constructor to deal with the double-underscore-separated
|
172
|
-
# names that we all know and love.
|
173
|
-
#
|
174
|
-
# @see {SqlGenerator#initialize}
|
175
|
-
#
|
176
|
-
def initialize(object_type, object_name, comment)
|
177
|
-
super
|
178
|
-
|
179
|
-
if object_name.is_a?(Symbol) and object_name.to_s.index("__")
|
180
|
-
@table_name, @object_name = object_name.to_s.split("__", 2).map(&:to_sym)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
# Generate special SQL.
|
185
|
-
#
|
186
|
-
# @see {SqlGenerator#generate}
|
187
|
-
#
|
188
|
-
def generate
|
189
|
-
if table_name.nil?
|
190
|
-
raise ArgumentError,
|
191
|
-
"Cannot generate SQL for #{object_type} #{object_name} " +
|
192
|
-
"without a table_name"
|
193
|
-
end
|
194
|
-
|
195
|
-
qualified_object_name = case object_type
|
196
|
-
when "COLUMN"
|
197
|
-
"#{maybe_escape table_name}.#{maybe_escape object_name}"
|
198
|
-
when "CONSTRAINT", "RULE", "TRIGGER"
|
199
|
-
"#{maybe_escape object_name} ON #{maybe_escape table_name}"
|
200
|
-
end
|
201
|
-
|
202
|
-
"COMMENT ON #{object_type} #{qualified_object_name} IS #{literal comment}"
|
203
|
-
end
|
204
|
-
|
205
|
-
private
|
206
|
-
|
207
|
-
# Handle with the vagaries of having both strings and symbols as
|
208
|
-
# possible names -- we escape symbols, but leave strings to their own
|
209
|
-
# devices.
|
210
|
-
#
|
211
|
-
def maybe_escape(s)
|
212
|
-
Symbol === s ? literal(s) : s
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
#:nodoc:
|
217
|
-
# This is an annoying corner-case generator -- it doesn't handle any
|
218
|
-
# types by default, but it will handle any *other* type where the name of
|
219
|
-
# a table needs to be prefixed by a name. The only known use case for
|
220
|
-
# this at present is "implicit" (that is, automatically generated by the
|
221
|
-
# database) constraints and indexes that get prefixed by the table name,
|
222
|
-
# and which are generated at a time when the calling code doesn't know the
|
223
|
-
# name of the table that it is generating SQL for.
|
224
|
-
#
|
225
|
-
class PrefixSqlGenerator < SqlGenerator
|
226
|
-
# This class doesn't handle any object types directly, and must be
|
227
|
-
# instantiated directly when needed
|
228
|
-
OBJECT_TYPES = %w{}
|
229
|
-
|
230
|
-
# The name of the table which should be prefixed to the object name
|
231
|
-
# that was specified when this instance was created.
|
232
|
-
#
|
233
|
-
attr_accessor :table_name
|
234
|
-
|
235
|
-
# Generate super-dooper special SQL.
|
236
|
-
#
|
237
|
-
# @see {SqlGenerator#generate}
|
238
|
-
#
|
239
|
-
def generate
|
240
|
-
if table_name.nil?
|
241
|
-
raise ArgumentError,
|
242
|
-
"Cannot generate SQL for #{object_type} #{object_name} " +
|
243
|
-
"without a table_name"
|
244
|
-
end
|
245
|
-
|
246
|
-
prefixed_object_name = "#{table_name}#{object_name}"
|
247
|
-
|
248
|
-
if Symbol === table_name || Symbol === object_name
|
249
|
-
prefixed_object_name = prefixed_object_name.to_sym
|
250
|
-
end
|
251
|
-
|
252
|
-
g = SqlGenerator.create(object_type, prefixed_object_name, comment)
|
253
|
-
g.table_name = table_name if g.respond_to? :table_name
|
254
|
-
g.generate
|
255
|
-
end
|
256
|
-
end
|
257
|
-
end
|
data/spec/sql_generator_spec.rb
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
require_relative 'spec_helper'
|
2
|
-
|
3
|
-
require 'sequel'
|
4
|
-
require 'sequel/extensions/pg_comment'
|
5
|
-
|
6
|
-
describe "SqlGenerator" do
|
7
|
-
SqlGenerator = Sequel::Extension::PgComment::SqlGenerator
|
8
|
-
PrefixSqlGenerator = Sequel::Extension::PgComment::PrefixSqlGenerator
|
9
|
-
|
10
|
-
context "a simple type expressed as a string" do
|
11
|
-
let(:generator) { SqlGenerator.create("TABLE", :foo, "Ohai!") }
|
12
|
-
|
13
|
-
it "generates quoted SQL" do
|
14
|
-
expect(generator.generate).
|
15
|
-
to eq("COMMENT ON TABLE \"foo\" IS 'Ohai!'")
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
context "a simple type expressed as a crazy-case string" do
|
20
|
-
let(:generator) { SqlGenerator.create("TaBlE", :foo, "Ohai!") }
|
21
|
-
|
22
|
-
it "generates quoted SQL" do
|
23
|
-
expect(generator.generate).
|
24
|
-
to eq("COMMENT ON TABLE \"foo\" IS 'Ohai!'")
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
context "a simple type expressed as a symbol" do
|
29
|
-
let(:generator) { SqlGenerator.create(:table, :foo, "Ohai!") }
|
30
|
-
|
31
|
-
it "generates quoted SQL" do
|
32
|
-
expect(generator.generate).
|
33
|
-
to eq("COMMENT ON TABLE \"foo\" IS 'Ohai!'")
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
context "a multi-word type expressed as a symbol" do
|
38
|
-
let(:generator) { SqlGenerator.create(:event_trigger, :foo, "Ohai!") }
|
39
|
-
|
40
|
-
it "generates correct SQL" do
|
41
|
-
expect(generator.generate).
|
42
|
-
to eq("COMMENT ON EVENT TRIGGER \"foo\" IS 'Ohai!'")
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
context "with a string as the object name" do
|
47
|
-
let(:generator) { SqlGenerator.create(:table, "foo", "Ohai!") }
|
48
|
-
|
49
|
-
it "generates unquoted SQL" do
|
50
|
-
expect(generator.generate).
|
51
|
-
to eq("COMMENT ON TABLE foo IS 'Ohai!'")
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
it "escapes the comment" do
|
56
|
-
expect(SqlGenerator.create(:table, :foo, "O'hai!").generate).
|
57
|
-
to eq("COMMENT ON TABLE \"foo\" IS 'O''hai!'")
|
58
|
-
end
|
59
|
-
|
60
|
-
it "explodes if an invalid object type is given" do
|
61
|
-
expect do
|
62
|
-
SqlGenerator.create(:foobooblee, :foo, "O'hai!")
|
63
|
-
end.to raise_error(ArgumentError, /unrecognised object type/i)
|
64
|
-
end
|
65
|
-
|
66
|
-
it "sets a column comment correctly" do
|
67
|
-
expect(SqlGenerator.create(:column, :foo__bar_id, "Ohai, column!").generate).
|
68
|
-
to eq("COMMENT ON COLUMN \"foo\".\"bar_id\" IS 'Ohai, column!'")
|
69
|
-
end
|
70
|
-
|
71
|
-
it "sets a constraint comment correctly" do
|
72
|
-
g = SqlGenerator.create(:constraint, :foo__not_for_you, "Ohai, constraint!")
|
73
|
-
expect(g.generate).
|
74
|
-
to eq("COMMENT ON CONSTRAINT \"not_for_you\" ON \"foo\" IS 'Ohai, constraint!'")
|
75
|
-
end
|
76
|
-
|
77
|
-
it "sets a rule comment correctly" do
|
78
|
-
g = SqlGenerator.create(:rule, :foo__not_for_you, "Ohai, rule!")
|
79
|
-
expect(g.generate).
|
80
|
-
to eq("COMMENT ON RULE \"not_for_you\" ON \"foo\" IS 'Ohai, rule!'")
|
81
|
-
end
|
82
|
-
|
83
|
-
it "sets a trigger comment correctly" do
|
84
|
-
g = SqlGenerator.create(:trigger, :foo__spoing, "Ohai, trigger!")
|
85
|
-
expect(g.generate).
|
86
|
-
to eq("COMMENT ON TRIGGER \"spoing\" ON \"foo\" IS 'Ohai, trigger!'")
|
87
|
-
end
|
88
|
-
|
89
|
-
it "sets a comment on a prefixed name correctly" do
|
90
|
-
g = PrefixSqlGenerator.new(:index, :_pkey, "Ohai, pkey!")
|
91
|
-
g.table_name = :foo
|
92
|
-
|
93
|
-
expect(g.generate).
|
94
|
-
to eq("COMMENT ON INDEX \"foo_pkey\" IS 'Ohai, pkey!'")
|
95
|
-
end
|
96
|
-
end
|