activerecord-postgresql-extensions 0.0.10 → 0.0.11
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.
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/activerecord-postgresql-extensions.gemspec +20 -17
- data/lib/activerecord-postgresql-extensions.rb +2 -0
- data/lib/postgresql_extensions/postgresql_adapter_extensions.rb +50 -53
- data/lib/postgresql_extensions/postgresql_constraints.rb +142 -153
- data/lib/postgresql_extensions/postgresql_extensions.rb +246 -0
- data/lib/postgresql_extensions/postgresql_functions.rb +31 -33
- data/lib/postgresql_extensions/postgresql_geometry.rb +2 -2
- data/lib/postgresql_extensions/postgresql_indexes.rb +13 -14
- data/lib/postgresql_extensions/postgresql_languages.rb +4 -4
- data/lib/postgresql_extensions/postgresql_permissions.rb +12 -14
- data/lib/postgresql_extensions/postgresql_roles.rb +2 -2
- data/lib/postgresql_extensions/postgresql_rules.rb +11 -10
- data/lib/postgresql_extensions/postgresql_schemas.rb +4 -4
- data/lib/postgresql_extensions/postgresql_sequences.rb +15 -16
- data/lib/postgresql_extensions/postgresql_tables.rb +20 -21
- data/lib/postgresql_extensions/postgresql_text_search.rb +313 -0
- data/lib/postgresql_extensions/postgresql_triggers.rb +13 -14
- data/lib/postgresql_extensions/postgresql_types.rb +1 -1
- data/lib/postgresql_extensions/postgresql_views.rb +13 -14
- data/test/{adapter_test.rb → adapter_tests.rb} +6 -6
- data/test/{constraints_test.rb → constraints_tests.rb} +13 -13
- data/test/extensions_tests.rb +275 -0
- data/test/{functions_test.rb → functions_tests.rb} +10 -10
- data/test/{geometry_test.rb → geometry_tests.rb} +16 -16
- data/test/{index_test.rb → index_tests.rb} +11 -11
- data/test/{languages_test.rb → languages_tests.rb} +6 -6
- data/test/{permissions_test.rb → permissions_tests.rb} +36 -36
- data/test/{roles_test.rb → roles_tests.rb} +6 -6
- data/test/{rules_test.rb → rules_tests.rb} +3 -3
- data/test/{schemas_test.rb → schemas_tests.rb} +6 -6
- data/test/{sequences_test.rb → sequences_tests.rb} +10 -10
- data/test/{tables_test.rb → tables_tests.rb} +2 -2
- data/test/text_search_tests.rb +263 -0
- metadata +19 -16
- data/postgresql-extensions.gemspec +0 -50
@@ -80,7 +80,7 @@ module ActiveRecord
|
|
80
80
|
sql << ' TO '
|
81
81
|
sql << Array(role_names).collect { |r| quote_role(r) }.join(', ')
|
82
82
|
sql << ' WITH ADMIN OPTION' if options[:with_admin_option]
|
83
|
-
execute
|
83
|
+
execute("#{sql};")
|
84
84
|
end
|
85
85
|
|
86
86
|
# Revokes table privileges. You can specify multiple tables,
|
@@ -155,7 +155,7 @@ module ActiveRecord
|
|
155
155
|
sql << ' FROM '
|
156
156
|
sql << Array(role_names).collect { |r| quote_role(r) }.join(', ')
|
157
157
|
sql << ' CASCADE' if options[:cascade]
|
158
|
-
execute
|
158
|
+
execute("#{sql};")
|
159
159
|
end
|
160
160
|
end
|
161
161
|
|
@@ -204,12 +204,11 @@ module ActiveRecord
|
|
204
204
|
#
|
205
205
|
# ==== Examples
|
206
206
|
#
|
207
|
-
#
|
208
|
-
#
|
209
|
-
# # => GRANT SELECT ON TABLE "table1", "table2" TO "joe"
|
207
|
+
# grant_table_privileges([ :table1, :table2 ], :select, :joe)
|
208
|
+
# # => GRANT SELECT ON TABLE "table1", "table2" TO "joe"
|
210
209
|
#
|
211
|
-
#
|
212
|
-
#
|
210
|
+
# grant_sequence_privileges(:my_seq, [ :select, :update ], :public)
|
211
|
+
# # => GRANT SELECT, UPDATE ON SEQUENCE "my_seq" TO PUBLIC
|
213
212
|
#
|
214
213
|
# You can specify the <tt>:with_grant_option</tt> in any of the
|
215
214
|
# grant_*_privilege methods to add a WITH GRANT OPTION clause to
|
@@ -244,7 +243,7 @@ module ActiveRecord
|
|
244
243
|
end.join(', ')
|
245
244
|
|
246
245
|
sql << ' WITH GRANT OPTION' if options[:with_grant_option]
|
247
|
-
sql
|
246
|
+
"#{sql};"
|
248
247
|
end
|
249
248
|
alias :to_s :to_sql
|
250
249
|
end
|
@@ -264,12 +263,11 @@ module ActiveRecord
|
|
264
263
|
#
|
265
264
|
# ==== Examples
|
266
265
|
#
|
267
|
-
#
|
268
|
-
#
|
269
|
-
# # => REVOKE SELECT ON TABLE "table1", "table2" FROM "joe"
|
266
|
+
# revoke_table_privileges([ :table1, :table2 ], :select, :joe)
|
267
|
+
# # => REVOKE SELECT ON TABLE "table1", "table2" FROM "joe"
|
270
268
|
#
|
271
|
-
#
|
272
|
-
#
|
269
|
+
# revoke_sequence_privileges(:my_seq, [ :select, :update ], :public)
|
270
|
+
# # => REVOKE SELECT, UPDATE ON SEQUENCE "my_seq" FROM PUBLIC
|
273
271
|
#
|
274
272
|
# You can specify the <tt>:grant_option_for</tt> in any of the
|
275
273
|
# revoke_*_privilege methods to add a GRANT OPTION FOR clause to
|
@@ -314,7 +312,7 @@ module ActiveRecord
|
|
314
312
|
end.join(', ')
|
315
313
|
|
316
314
|
sql << ' CASCADE' if options[:cascade]
|
317
|
-
sql
|
315
|
+
"#{sql};"
|
318
316
|
end
|
319
317
|
alias :to_s :to_sql
|
320
318
|
end
|
@@ -24,7 +24,7 @@ module ActiveRecord
|
|
24
24
|
sql = 'DROP ROLE '
|
25
25
|
sql << 'IF EXISTS ' if options[:if_exists]
|
26
26
|
sql << Array(name).collect { |r| quote_role(r) }.join(', ')
|
27
|
-
execute
|
27
|
+
execute("#{sql};")
|
28
28
|
end
|
29
29
|
alias :drop_user :drop_role
|
30
30
|
end
|
@@ -112,7 +112,7 @@ module ActiveRecord
|
|
112
112
|
sql << Array(options[:admin]).collect { |r| base.quote_role(r) }.join(', ')
|
113
113
|
end
|
114
114
|
|
115
|
-
sql.join(' ')
|
115
|
+
"#{sql.join(' ')};"
|
116
116
|
end
|
117
117
|
alias :to_s :to_sql
|
118
118
|
|
@@ -37,22 +37,21 @@ module ActiveRecord
|
|
37
37
|
#
|
38
38
|
# ==== Examples
|
39
39
|
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
# # => CREATE RULE "check_it_out_rule" AS ON SELECT TO "child" WHERE id = 1 DO INSTEAD select * from public.another;
|
40
|
+
# create_rule(
|
41
|
+
# 'check_it_out_rule',
|
42
|
+
# :select,
|
43
|
+
# :child,
|
44
|
+
# :instead,
|
45
|
+
# 'select * from public.another', :conditions => 'id = 1'
|
46
|
+
# )
|
47
|
+
# # => CREATE RULE "check_it_out_rule" AS ON SELECT TO "child" WHERE id = 1 DO INSTEAD select * from public.another;
|
49
48
|
def create_rule(name, event, table, action, commands, options = {})
|
50
49
|
execute PostgreSQLRuleDefinition.new(self, name, event, table, action, commands, options).to_s
|
51
50
|
end
|
52
51
|
|
53
52
|
# Drops a PostgreSQL rule.
|
54
53
|
def drop_rule(name, table)
|
55
|
-
execute "DROP RULE #{quote_rule(name)} ON #{quote_table_name(table)}"
|
54
|
+
execute "DROP RULE #{quote_rule(name)} ON #{quote_table_name(table)};"
|
56
55
|
end
|
57
56
|
end
|
58
57
|
|
@@ -89,6 +88,8 @@ module ActiveRecord
|
|
89
88
|
else
|
90
89
|
commands.to_s
|
91
90
|
end
|
91
|
+
|
92
|
+
"#{sql};"
|
92
93
|
end
|
93
94
|
alias :to_s :to_sql
|
94
95
|
|
@@ -18,7 +18,7 @@ module ActiveRecord
|
|
18
18
|
def create_schema schema, options = {}
|
19
19
|
sql = "CREATE SCHEMA #{quote_schema(schema)}"
|
20
20
|
sql << " AUTHORIZATION #{quote_role(options[:authorization])}" if options[:authorization]
|
21
|
-
execute
|
21
|
+
execute("#{sql};")
|
22
22
|
end
|
23
23
|
|
24
24
|
# Drops a schema.
|
@@ -32,17 +32,17 @@ module ActiveRecord
|
|
32
32
|
sql << 'IF EXISTS ' if options[:if_exists]
|
33
33
|
sql << Array(schemas).collect { |s| quote_schema(s) }.join(', ')
|
34
34
|
sql << ' CASCADE' if options[:cascade]
|
35
|
-
execute
|
35
|
+
execute("#{sql};")
|
36
36
|
end
|
37
37
|
|
38
38
|
# Alter's a schema's name.
|
39
39
|
def alter_schema_name old_schema, new_schema
|
40
|
-
execute "ALTER SCHEMA #{quote_schema(old_schema)} RENAME TO #{quote_schema(new_schema)}"
|
40
|
+
execute "ALTER SCHEMA #{quote_schema(old_schema)} RENAME TO #{quote_schema(new_schema)};"
|
41
41
|
end
|
42
42
|
|
43
43
|
# Changes a schema's owner.
|
44
44
|
def alter_schema_owner schema, role
|
45
|
-
execute "ALTER SCHEMA #{quote_schema(schema)} OWNER TO #{
|
45
|
+
execute "ALTER SCHEMA #{quote_schema(schema)} OWNER TO #{quote_role(role)};"
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -42,17 +42,16 @@ module ActiveRecord
|
|
42
42
|
#
|
43
43
|
# ==== Example
|
44
44
|
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
# # NO MINVALUE MAXVALUE 10 CACHE 2 OWNED BY "foo"."id";
|
45
|
+
# create_sequence(
|
46
|
+
# 'what_a_sequence_of_events',
|
47
|
+
# :increment => 2,
|
48
|
+
# :cache => 2,
|
49
|
+
# :min_value => nil,
|
50
|
+
# :max_value => 10,
|
51
|
+
# :owned_by => [ :foo, :id ]
|
52
|
+
# )
|
53
|
+
# # => CREATE SEQUENCE "what_a_sequence_of_events" INCREMENT BY 2
|
54
|
+
# # NO MINVALUE MAXVALUE 10 CACHE 2 OWNED BY "foo"."id";
|
56
55
|
def create_sequence(name, options = {})
|
57
56
|
execute PostgreSQLSequenceDefinition.new(self, :create, name, options).to_s
|
58
57
|
end
|
@@ -69,17 +68,17 @@ module ActiveRecord
|
|
69
68
|
sql << 'IF EXISTS ' if options[:if_exists]
|
70
69
|
sql << Array(name).collect { |s| quote_sequence(s) }.join(', ')
|
71
70
|
sql << ' CASCADE' if options[:cascade]
|
72
|
-
execute
|
71
|
+
execute("#{sql};")
|
73
72
|
end
|
74
73
|
|
75
74
|
# Renames the sequence.
|
76
75
|
def rename_sequence(name, rename, options = {})
|
77
|
-
execute "ALTER SEQUENCE #{quote_sequence(name)} RENAME TO #{quote_generic_ignore_schema(rename)}"
|
76
|
+
execute "ALTER SEQUENCE #{quote_sequence(name)} RENAME TO #{quote_generic_ignore_schema(rename)};"
|
78
77
|
end
|
79
78
|
|
80
79
|
# Alters the sequence's schema.
|
81
80
|
def alter_sequence_schema(name, schema, options = {})
|
82
|
-
execute "ALTER SEQUENCE #{quote_sequence(name)} SET SCHEMA #{quote_schema(schema)}"
|
81
|
+
execute "ALTER SEQUENCE #{quote_sequence(name)} SET SCHEMA #{quote_schema(schema)};"
|
83
82
|
end
|
84
83
|
|
85
84
|
# Alters any of the various options for a sequence. See
|
@@ -112,7 +111,7 @@ module ActiveRecord
|
|
112
111
|
else
|
113
112
|
'false'
|
114
113
|
end <<
|
115
|
-
')'
|
114
|
+
');'
|
116
115
|
end
|
117
116
|
|
118
117
|
# Returns an Array of available sequences.
|
@@ -193,7 +192,7 @@ module ActiveRecord
|
|
193
192
|
if action != :create && options.has_key?(:restart_with)
|
194
193
|
sql << "RESTART WITH #{options[:restart_with].to_i}"
|
195
194
|
end
|
196
|
-
sql.join(' ')
|
195
|
+
"#{sql.join(' ')};"
|
197
196
|
end
|
198
197
|
alias :to_s :to_sql
|
199
198
|
|
@@ -13,7 +13,7 @@ module ActiveRecord
|
|
13
13
|
class PostgreSQLAdapter < AbstractAdapter
|
14
14
|
# Set the schema of a table.
|
15
15
|
def alter_table_schema table_name, schema, options = {}
|
16
|
-
execute "ALTER TABLE #{quote_schema(table_name)} SET SCHEMA #{quote_schema(schema)}"
|
16
|
+
execute "ALTER TABLE #{quote_schema(table_name)} SET SCHEMA #{quote_schema(schema)};"
|
17
17
|
end
|
18
18
|
|
19
19
|
alias :original_create_table :create_table
|
@@ -69,24 +69,23 @@ module ActiveRecord
|
|
69
69
|
#
|
70
70
|
# ==== Examples
|
71
71
|
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
# end
|
72
|
+
# create_table(:foo, :inherits => :parent) do |t|
|
73
|
+
# t.integer :bar_id, :references => :bar
|
74
|
+
# t.like :base, :including => [ :defaults, :indexes ], :excluding => :constraints
|
75
|
+
# t.check_constraint "bar_id < 100"
|
76
|
+
# t.unique_constraint :bar_id
|
77
|
+
# end
|
79
78
|
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
79
|
+
# # Produces:
|
80
|
+
# #
|
81
|
+
# # CREATE TABLE "foo" (
|
82
|
+
# # "id" serial primary key,
|
83
|
+
# # "bar_id" integer DEFAULT NULL NULL,
|
84
|
+
# # LIKE "base" INCLUDING DEFAULTS INCLUDING INDEXES EXCLUDING CONSTRAINTS,
|
85
|
+
# # FOREIGN KEY ("bar_id") REFERENCES "bar",
|
86
|
+
# # CHECK (bar_id < 100),
|
87
|
+
# # UNIQUE ("bar_id")
|
88
|
+
# # ) INHERITS ("parent");
|
90
89
|
#
|
91
90
|
# This is a fairly convoluted example, but there you have it.
|
92
91
|
#
|
@@ -131,7 +130,7 @@ module ActiveRecord
|
|
131
130
|
sql << 'IF EXISTS ' if options[:if_exists]
|
132
131
|
sql << Array(tables).collect { |t| quote_table_name(t) }.join(', ')
|
133
132
|
sql << ' CASCADE' if options[:cascade]
|
134
|
-
execute
|
133
|
+
execute("#{sql};")
|
135
134
|
end
|
136
135
|
|
137
136
|
alias :original_rename_table :rename_table
|
@@ -140,7 +139,7 @@ module ActiveRecord
|
|
140
139
|
# capabilities. You can still access the original method via
|
141
140
|
# original_rename_table.
|
142
141
|
def rename_table(name, new_name, options = {})
|
143
|
-
execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_generic_ignore_schema(new_name)}"
|
142
|
+
execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_generic_ignore_schema(new_name)};"
|
144
143
|
end
|
145
144
|
|
146
145
|
private
|
@@ -195,7 +194,7 @@ module ActiveRecord
|
|
195
194
|
sql << "ON COMMIT #{options[:on_commit].to_s.upcase}" if options[:on_commit]
|
196
195
|
sql << "#{options[:options]}" if options[:options]
|
197
196
|
sql << "TABLESPACE #{base.quote_tablespace(options[:tablespace])}" if options[:tablespace]
|
198
|
-
sql
|
197
|
+
"#{sql};"
|
199
198
|
end
|
200
199
|
alias :to_s :to_sql
|
201
200
|
|
@@ -0,0 +1,313 @@
|
|
1
|
+
|
2
|
+
require 'active_record/connection_adapters/postgresql_adapter'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
module ConnectionAdapters
|
6
|
+
class PostgreSQLAdapter < AbstractAdapter
|
7
|
+
# Creates a new PostgreSQL text search configuration. You must provide
|
8
|
+
# either a :parser_name or a :source_config option as per the PostgreSQL
|
9
|
+
# text search docs.
|
10
|
+
def create_text_search_configuration(name, options = {})
|
11
|
+
if options[:parser_name] && options[:source_config]
|
12
|
+
raise ArgumentError.new("You can't define both :parser_name and :source_config options.")
|
13
|
+
elsif options[:parser_name].blank? && options[:source_config].blank?
|
14
|
+
raise ArgumentError.new("You must provide either a :parser_name or a :source_config.")
|
15
|
+
end
|
16
|
+
|
17
|
+
sql = "CREATE TEXT SEARCH CONFIGURATION #{quote_generic_with_schema(name)} ("
|
18
|
+
|
19
|
+
ignore_schema do
|
20
|
+
sql << if options[:parser_name]
|
21
|
+
"PARSER = #{quote_generic_with_schema(options[:parser_name])}"
|
22
|
+
else
|
23
|
+
"COPY = #{quote_generic_with_schema(options[:source_config])}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
sql << ")"
|
28
|
+
execute("#{sql};")
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_text_search_configuration_mapping(name, tokens, dictionaries)
|
32
|
+
add_or_alter_text_search_configuration_mapping(name, tokens, dictionaries, :action => :add)
|
33
|
+
end
|
34
|
+
|
35
|
+
def alter_text_search_configuration_mapping(name, tokens, dictionaries)
|
36
|
+
add_or_alter_text_search_configuration_mapping(name, tokens, dictionaries, :action => :alter)
|
37
|
+
end
|
38
|
+
|
39
|
+
# This method is semi-private and should only really be used via
|
40
|
+
# add_text_search_configuration_mapping and alter_text_search_configuration_mapping.
|
41
|
+
#
|
42
|
+
# ==== Options
|
43
|
+
#
|
44
|
+
# * <tt>:action</tt> - either :add or :alter.
|
45
|
+
def add_or_alter_text_search_configuration_mapping(name, tokens, dictionaries, options = {})
|
46
|
+
options = {
|
47
|
+
:action => :add
|
48
|
+
}.merge(options)
|
49
|
+
|
50
|
+
if ![ :add, :alter ].include?(options[:action])
|
51
|
+
raise ArgumentError.new(":action option must be eithe :add or :alter.")
|
52
|
+
end
|
53
|
+
|
54
|
+
add_or_alter = options[:action].to_s.upcase
|
55
|
+
|
56
|
+
sql = "ALTER TEXT SEARCH CONFIGURATION #{quote_generic_with_schema(name)} #{add_or_alter} MAPPING FOR "
|
57
|
+
sql << Array(tokens).collect { |token|
|
58
|
+
quote_generic(token)
|
59
|
+
}.join(', ')
|
60
|
+
|
61
|
+
sql << ' WITH '
|
62
|
+
|
63
|
+
sql << Array(dictionaries).collect { |dictionary|
|
64
|
+
quote_generic(dictionary)
|
65
|
+
}.join(', ')
|
66
|
+
|
67
|
+
execute("#{sql};")
|
68
|
+
end
|
69
|
+
|
70
|
+
def replace_text_search_configuration_dictionary(name, old_dictionary, new_dictionary)
|
71
|
+
sql = "ALTER TEXT SEARCH CONFIGURATION #{quote_generic_with_schema(name)} ALTER MAPPING REPLACE "
|
72
|
+
sql << "#{quote_generic(old_dictionary)} WITH #{quote_generic(new_dictionary)}"
|
73
|
+
|
74
|
+
execute("#{sql};")
|
75
|
+
end
|
76
|
+
|
77
|
+
def alter_text_search_configuration_mapping_replace_dictionary(name, mappings, old_dictionary, new_dictionary)
|
78
|
+
if mappings.blank?
|
79
|
+
raise ArgumentError.new("Expected one or more mappings to alter.")
|
80
|
+
end
|
81
|
+
|
82
|
+
sql = "ALTER TEXT SEARCH CONFIGURATION #{quote_generic_with_schema(name)} ALTER MAPPING FOR "
|
83
|
+
sql << Array(mappings).collect { |token_type|
|
84
|
+
quote_generic(token_type)
|
85
|
+
}.join(', ')
|
86
|
+
sql << " REPLACE #{quote_generic(old_dictionary)} WITH #{quote_generic(new_dictionary)}"
|
87
|
+
|
88
|
+
execute("#{sql};")
|
89
|
+
end
|
90
|
+
|
91
|
+
def drop_text_search_configuration_mapping(name, *args)
|
92
|
+
options = args.extract_options!
|
93
|
+
mappings = args
|
94
|
+
|
95
|
+
if mappings.blank?
|
96
|
+
raise ArgumentError.new("Expected one or more mappings to drop.")
|
97
|
+
end
|
98
|
+
|
99
|
+
sql = "ALTER TEXT SEARCH CONFIGURATION #{quote_generic_with_schema(name)} DROP MAPPING "
|
100
|
+
|
101
|
+
if options[:if_exists]
|
102
|
+
sql << 'IF EXISTS '
|
103
|
+
end
|
104
|
+
|
105
|
+
sql << 'FOR '
|
106
|
+
sql << mappings.collect { |token_type|
|
107
|
+
quote_generic(token_type)
|
108
|
+
}.join(', ')
|
109
|
+
|
110
|
+
execute("#{sql};")
|
111
|
+
end
|
112
|
+
|
113
|
+
def rename_text_search_configuration(old_name, new_name)
|
114
|
+
execute("ALTER TEXT SEARCH CONFIGURATION %s RENAME TO %s;" % [
|
115
|
+
quote_generic_with_schema(old_name),
|
116
|
+
quote_generic_with_schema(new_name)
|
117
|
+
])
|
118
|
+
end
|
119
|
+
|
120
|
+
def alter_text_search_configuration_owner(name, role)
|
121
|
+
execute "ALTER TEXT SEARCH CONFIGURATION #{quote_generic_with_schema(name)} OWNER TO #{quote_role(role)};"
|
122
|
+
end
|
123
|
+
|
124
|
+
def alter_text_search_configuration_schema(name, schema)
|
125
|
+
execute "ALTER TEXT SEARCH CONFIGURATION #{quote_generic_with_schema(name)} SET SCHEMA #{quote_schema(schema)};"
|
126
|
+
end
|
127
|
+
|
128
|
+
# Drops a text search configuration.
|
129
|
+
#
|
130
|
+
# ==== Options
|
131
|
+
#
|
132
|
+
# * <tt>:if_exists</tt> - adds IF EXISTS.
|
133
|
+
# * <tt>:cascade</tt> - adds CASCADE.
|
134
|
+
def drop_text_search_configuration(name, options = {})
|
135
|
+
sql = 'DROP TEXT SEARCH CONFIGURATION '
|
136
|
+
sql << 'IF EXISTS ' if options[:if_exists]
|
137
|
+
sql << quote_generic_with_schema(name)
|
138
|
+
sql << ' CASCADE' if options[:cascade]
|
139
|
+
|
140
|
+
execute("#{sql};")
|
141
|
+
end
|
142
|
+
|
143
|
+
def create_text_search_dictionary(name, template, options = {})
|
144
|
+
sql = "CREATE TEXT SEARCH DICTIONARY #{quote_generic_with_schema(name)} ("
|
145
|
+
sql << "TEMPLATE = #{quote_generic_with_schema(template)}"
|
146
|
+
|
147
|
+
if !options.blank?
|
148
|
+
sql << ', '
|
149
|
+
sql << options.collect { |k, v|
|
150
|
+
"#{quote_generic(k)} = #{quote(v)}"
|
151
|
+
}.join(', ')
|
152
|
+
end
|
153
|
+
|
154
|
+
sql << ')'
|
155
|
+
|
156
|
+
execute("#{sql};")
|
157
|
+
end
|
158
|
+
|
159
|
+
# ==== Options
|
160
|
+
#
|
161
|
+
# * <tt>:if_exists</tt> - adds IF EXISTS.
|
162
|
+
# * <tt>:cascade</tt> - adds CASCADE.
|
163
|
+
def drop_text_search_dictionary(name, options = {})
|
164
|
+
sql = 'DROP TEXT SEARCH DICTIONARY '
|
165
|
+
sql << 'IF EXISTS ' if options[:if_exists]
|
166
|
+
sql << quote_generic_with_schema(name)
|
167
|
+
sql << ' CASCADE' if options[:cascade]
|
168
|
+
|
169
|
+
execute("#{sql};")
|
170
|
+
end
|
171
|
+
|
172
|
+
def alter_text_search_dictionary(name, options)
|
173
|
+
if options.blank?
|
174
|
+
raise ArgumentError.new("Expected some options to alter.")
|
175
|
+
end
|
176
|
+
|
177
|
+
sql = "ALTER TEXT SEARCH DICTIONARY #{quote_generic_with_schema} ("
|
178
|
+
sql << options.collect { |k, v|
|
179
|
+
"#{quote_generic(k)} = #{quote(v)}"
|
180
|
+
}.join(', ')
|
181
|
+
sql << ')'
|
182
|
+
|
183
|
+
execute("#{sql};")
|
184
|
+
end
|
185
|
+
|
186
|
+
def rename_text_search_dictionary(old_name, new_name)
|
187
|
+
execute("ALTER TEXT SEARCH DICTIONARY %s RENAME TO %s;" % [
|
188
|
+
quote_generic_with_schema(old_name),
|
189
|
+
quote_generic_with_schema(new_name)
|
190
|
+
])
|
191
|
+
end
|
192
|
+
|
193
|
+
def alter_text_search_dictionary_owner(name, role)
|
194
|
+
execute "ALTER TEXT SEARCH DICTIONARY #{quote_generic_with_schema(name)} OWNER TO #{quote_role(role)};"
|
195
|
+
end
|
196
|
+
|
197
|
+
def alter_text_search_dictionary_schema(name, schema)
|
198
|
+
execute "ALTER TEXT SEARCH DICTIONARY #{quote_generic_with_schema(name)} SET SCHEMA #{quote_schema(schema)};"
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
# ==== Options
|
203
|
+
#
|
204
|
+
# :lexize - the function used by the template lexer. Required.
|
205
|
+
# :init - the initialization function for the template. Optional.
|
206
|
+
def create_text_search_template(name, options = {})
|
207
|
+
if options[:lexize].blank?
|
208
|
+
raise ArgumentError.new("Expected to see a :lexize option.")
|
209
|
+
end
|
210
|
+
|
211
|
+
sql = "CREATE TEXT SEARCH TEMPLATE #{quote_generic_with_schema(name)} ("
|
212
|
+
|
213
|
+
if options[:init]
|
214
|
+
sql << "INIT = #{quote_function(options[:init])}, "
|
215
|
+
end
|
216
|
+
|
217
|
+
sql << "LEXIZE = #{quote_function(options[:lexize])}"
|
218
|
+
sql << ')'
|
219
|
+
|
220
|
+
execute("#{sql};")
|
221
|
+
end
|
222
|
+
|
223
|
+
# ==== Options
|
224
|
+
#
|
225
|
+
# * <tt>:if_exists</tt> - adds IF EXISTS.
|
226
|
+
# * <tt>:cascade</tt> - adds CASCADE.
|
227
|
+
def drop_text_search_template(name, options = {})
|
228
|
+
sql = 'DROP TEXT SEARCH TEMPLATE '
|
229
|
+
sql << 'IF EXISTS ' if options[:if_exists]
|
230
|
+
sql << quote_generic_with_schema(name)
|
231
|
+
sql << ' CASCADE' if options[:cascade]
|
232
|
+
|
233
|
+
execute("#{sql};")
|
234
|
+
end
|
235
|
+
|
236
|
+
def rename_text_search_template(old_name, new_name)
|
237
|
+
execute("ALTER TEXT SEARCH TEMPLATE %s RENAME TO %s;" % [
|
238
|
+
quote_generic_with_schema(old_name),
|
239
|
+
quote_generic_with_schema(new_name)
|
240
|
+
])
|
241
|
+
end
|
242
|
+
|
243
|
+
def alter_text_search_template_schema(name, schema)
|
244
|
+
execute "ALTER TEXT SEARCH TEMPLATE #{quote_generic_with_schema(name)} SET SCHEMA #{quote_schema(schema)};"
|
245
|
+
end
|
246
|
+
|
247
|
+
|
248
|
+
|
249
|
+
# The :start, :gettoken, :end and :lextypes options are required as per
|
250
|
+
# the PostgreSQL docs, while the :headline option is optional.
|
251
|
+
def create_text_search_parser(name, options = {})
|
252
|
+
if (missing_options = [ :start, :gettoken, :end, :lextypes ] - options.keys).present?
|
253
|
+
raise ArgumentError.new("Missing options: #{missing_options}.")
|
254
|
+
end
|
255
|
+
|
256
|
+
sql = "CREATE TEXT SEARCH PARSER #{quote_generic_with_schema(name)} ("
|
257
|
+
sql << "START = #{quote_function(options[:start])}, "
|
258
|
+
sql << "GETTOKEN = #{quote_function(options[:gettoken])}, "
|
259
|
+
sql << "END = #{quote_function(options[:end])}, "
|
260
|
+
sql << "LEXTYPES = #{quote_function(options[:lextypes])}"
|
261
|
+
|
262
|
+
if options[:headline]
|
263
|
+
sql << ", HEADLINE = #{quote_function(options[:headline])}"
|
264
|
+
end
|
265
|
+
|
266
|
+
sql << ')'
|
267
|
+
|
268
|
+
execute("#{sql};")
|
269
|
+
end
|
270
|
+
|
271
|
+
# ==== Options
|
272
|
+
#
|
273
|
+
# * <tt>:if_exists</tt> - adds IF EXISTS.
|
274
|
+
# * <tt>:cascade</tt> - adds CASCADE.
|
275
|
+
def drop_text_search_parser(name, options = {})
|
276
|
+
sql = 'DROP TEXT SEARCH PARSER '
|
277
|
+
sql << 'IF EXISTS ' if options[:if_exists]
|
278
|
+
sql << quote_generic_with_schema(name)
|
279
|
+
sql << ' CASCADE' if options[:cascade]
|
280
|
+
|
281
|
+
execute("#{sql};")
|
282
|
+
end
|
283
|
+
|
284
|
+
def rename_text_search_parser(old_name, new_name)
|
285
|
+
execute("ALTER TEXT SEARCH PARSER %s RENAME TO %s;" % [
|
286
|
+
quote_generic_with_schema(old_name),
|
287
|
+
quote_generic_with_schema(new_name)
|
288
|
+
])
|
289
|
+
end
|
290
|
+
|
291
|
+
def alter_text_search_parser_schema(name, schema)
|
292
|
+
execute "ALTER TEXT SEARCH PARSER #{quote_generic_with_schema(name)} SET SCHEMA #{quote_schema(schema)};"
|
293
|
+
end
|
294
|
+
|
295
|
+
private
|
296
|
+
def extract_hash_or_array_options(hash_or_array, *keys)
|
297
|
+
case v = hash_or_array[0]
|
298
|
+
when Hash
|
299
|
+
if (keys - (sliced = v.slice(*keys)).keys).length == 0
|
300
|
+
keys.collect do |k|
|
301
|
+
sliced[k]
|
302
|
+
end
|
303
|
+
else
|
304
|
+
[ v.keys.first, v.values.first ]
|
305
|
+
end
|
306
|
+
else
|
307
|
+
v = hash_or_array.flatten
|
308
|
+
[ v.shift, *v ]
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|