activerecord-postgresql-extensions 0.0.10 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- 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
|