jeremyevans-sequel_postgresql_triggers 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/LICENSE +1 -1
  2. data/lib/sequel_postgresql_triggers.rb +140 -140
  3. metadata +2 -2
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2008 Jeremy Evans
1
+ Copyright (c) 2008-2009 Jeremy Evans
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to
@@ -1,140 +1,140 @@
1
- module Sequel
2
- module Postgres
3
- # Add the pgt_* methods so that any Sequel database connecting to PostgreSQL
4
- # can use them. All of these methods require the plpgsql procedural language
5
- # added to the PostgreSQL database before they can be used. You can do so
6
- # with:
7
- #
8
- # DB.create_language(:plpgsql)
9
- #
10
- # All of the public methods take the following options in their opts hash:
11
- #
12
- # * :function_name: The name of the function to use. This is important
13
- # to specify if you want an easy way to drop the function.
14
- # * :trigger_name: The name of the trigger to use. This is important
15
- # to specify if you want an easy way to drop the trigger.
16
- module DatabaseMethods
17
- # Turns a column in the main table into a counter cache. A counter cache is a
18
- # column in the main table with the number of rows in the counted table
19
- # for the matching id. Arguments:
20
- # * main_table : name of table holding counter cache column
21
- # * main_table_id_column : column in main table matching counted_table_id_column in counted_table
22
- # * counter_column : column in main table containing the counter cache
23
- # * counted_table : name of table being counted
24
- # * counted_table_id_column : column in counted_table matching main_table_id_column in main_table
25
- # * opts : option hash, see module documentation
26
- def pgt_counter_cache(main_table, main_table_id_column, counter_column, counted_table, counted_table_id_column, opts={})
27
- trigger_name = opts[:trigger_name] || "pgt_cc_#{main_table}__#{main_table_id_column}__#{counter_column}__#{counted_table_id_column}"
28
- function_name = opts[:function_name] || "pgt_cc_#{main_table}__#{main_table_id_column}__#{counter_column}__#{counted_table}__#{counted_table_id_column}"
29
- pgt_trigger(counted_table, trigger_name, function_name, [:insert, :delete], <<-SQL)
30
- BEGIN
31
- IF (TG_OP = 'DELETE') THEN
32
- UPDATE #{quote_schema_table(main_table)} SET #{quote_identifier(counter_column)} = #{quote_identifier(counter_column)} - 1 WHERE #{quote_identifier(main_table_id_column)} = OLD.#{counted_table_id_column};
33
- RETURN OLD;
34
- ELSIF (TG_OP = 'INSERT') THEN
35
- UPDATE #{quote_schema_table(main_table)} SET #{quote_identifier(counter_column)} = #{quote_identifier(counter_column)} + 1 WHERE #{quote_identifier(main_table_id_column)} = NEW.#{quote_identifier(counted_table_id_column)};
36
- RETURN NEW;
37
- END IF;
38
- END;
39
- SQL
40
- end
41
-
42
- # Turns a column in the table into a created at timestamp column, which
43
- # always contains the timestamp the record was inserted into the database.
44
- # Arguments:
45
- # * table : name of table
46
- # * column : column in table that should be a created at timestamp column
47
- # * opts : option hash, see module documentation
48
- def pgt_created_at(table, column, opts={})
49
- trigger_name = opts[:trigger_name] || "pgt_ca_#{column}"
50
- function_name = opts[:function_name] || "pgt_ca_#{table}__#{column}"
51
- pgt_trigger(table, trigger_name, function_name, [:insert, :update], <<-SQL)
52
- BEGIN
53
- IF (TG_OP = 'UPDATE') THEN
54
- NEW.#{quote_identifier(column)} := OLD.#{quote_identifier(column)};
55
- ELSIF (TG_OP = 'INSERT') THEN
56
- NEW.#{quote_identifier(column)} := CURRENT_TIMESTAMP;
57
- END IF;
58
- RETURN NEW;
59
- END;
60
- SQL
61
- end
62
-
63
- # Makes all given columns in the given table immutable, so an exception
64
- # is raised if there is an attempt to modify the value when updating the
65
- # record. Arguments:
66
- # * table : name of table
67
- # * columns : All columns in the table that should be immutable. Can end with a hash of options, see module documentation.
68
- def pgt_immutable(table, *columns)
69
- opts = columns.extract_options!
70
- trigger_name = opts[:trigger_name] || "pgt_im_#{columns.join('__')}"
71
- function_name = opts[:function_name] || "pgt_im_#{columns.join('__')}"
72
- ifs = columns.map do |c|
73
- old = "OLD.#{quote_identifier(c)}"
74
- new = "NEW.#{quote_identifier(c)}"
75
- <<-END
76
- IF #{new} != #{old} THEN
77
- RAISE EXCEPTION 'Attempted event_id update: Old: %, New: %', #{old}, #{new};
78
- END IF;
79
- END
80
- end.join("\n")
81
- pgt_trigger(table, trigger_name, function_name, :update, "BEGIN #{ifs} RETURN NEW; END;")
82
- end
83
-
84
- # Turns a column in the main table into a sum cache. A sum cache is a
85
- # column in the main table with the sum of a column in the summed table
86
- # for the matching id. Arguments:
87
- # * main_table : name of table holding counter cache column
88
- # * main_table_id_column : column in main table matching counted_table_id_column in counted_table
89
- # * sum_column : column in main table containing the sum cache
90
- # * summed_table : name of table being summed
91
- # * summed_table_id_column : column in summed_table matching main_table_id_column in main_table
92
- # * summed_column : column in summed_table being summed
93
- # * opts : option hash, see module documentation
94
- def pgt_sum_cache(main_table, main_table_id_column, sum_column, summed_table, summed_table_id_column, summed_column, opts={})
95
- trigger_name = opts[:trigger_name] || "pgt_sc_#{main_table}__#{main_table_id_column}__#{sum_column}__#{summed_table_id_column}"
96
- function_name = opts[:function_name] || "pgt_sc_#{main_table}__#{main_table_id_column}__#{sum_column}__#{summed_table}__#{summed_table_id_column}__#{summed_column}"
97
- pgt_trigger(summed_table, trigger_name, function_name, [:insert, :delete, :update], <<-SQL)
98
- BEGIN
99
- IF (TG_OP = 'DELETE') THEN
100
- UPDATE #{quote_schema_table(main_table)} SET #{quote_identifier(sum_column)} = #{quote_identifier(sum_column)} - OLD.#{quote_identifier(summed_column)} WHERE #{quote_identifier(main_table_id_column)} = OLD.#{summed_table_id_column};
101
- RETURN OLD;
102
- ELSIF (TG_OP = 'UPDATE') THEN
103
- UPDATE #{quote_schema_table(main_table)} SET #{quote_identifier(sum_column)} = #{quote_identifier(sum_column)} + NEW.#{quote_identifier(summed_column)} - OLD.#{quote_identifier(summed_column)} WHERE #{quote_identifier(main_table_id_column)} = NEW.#{quote_identifier(summed_table_id_column)};
104
- RETURN NEW;
105
- ELSIF (TG_OP = 'INSERT') THEN
106
- UPDATE #{quote_schema_table(main_table)} SET #{quote_identifier(sum_column)} = #{quote_identifier(sum_column)} + NEW.#{quote_identifier(summed_column)} WHERE #{quote_identifier(main_table_id_column)} = NEW.#{quote_identifier(summed_table_id_column)};
107
- RETURN NEW;
108
- END IF;
109
- END;
110
- SQL
111
- end
112
-
113
- # Turns a column in the table into a updated at timestamp column, which
114
- # always contains the timestamp the record was inserted or last updated.
115
- # Arguments:
116
- # * table : name of table
117
- # * column : column in table that should be a updated at timestamp column
118
- # * opts : option hash, see module documentation
119
- def pgt_updated_at(table, column, opts={})
120
- trigger_name = opts[:trigger_name] || "pgt_ua_#{column}"
121
- function_name = opts[:function_name] || "pgt_ua_#{table}__#{column}"
122
- pgt_trigger(table, trigger_name, function_name, [:insert, :update], <<-SQL)
123
- BEGIN
124
- NEW.#{quote_identifier(column)} := CURRENT_TIMESTAMP;
125
- RETURN NEW;
126
- END;
127
- SQL
128
- end
129
-
130
- private
131
-
132
- # Add or replace a function that returns trigger to handle the action,
133
- # and add a trigger that calls the function.
134
- def pgt_trigger(table, trigger_name, function_name, events, definition)
135
- create_function(function_name, definition, :language=>:plpgsql, :returns=>:trigger, :replace=>true)
136
- create_trigger(table, trigger_name, function_name, :events=>events, :each_row=>true)
137
- end
138
- end
139
- end
140
- end
1
+ module Sequel
2
+ module Postgres
3
+ # Add the pgt_* methods so that any Sequel database connecting to PostgreSQL
4
+ # can use them. All of these methods require the plpgsql procedural language
5
+ # added to the PostgreSQL database before they can be used. You can do so
6
+ # with:
7
+ #
8
+ # DB.create_language(:plpgsql)
9
+ #
10
+ # All of the public methods take the following options in their opts hash:
11
+ #
12
+ # * :function_name: The name of the function to use. This is important
13
+ # to specify if you want an easy way to drop the function.
14
+ # * :trigger_name: The name of the trigger to use. This is important
15
+ # to specify if you want an easy way to drop the trigger.
16
+ module DatabaseMethods
17
+ # Turns a column in the main table into a counter cache. A counter cache is a
18
+ # column in the main table with the number of rows in the counted table
19
+ # for the matching id. Arguments:
20
+ # * main_table : name of table holding counter cache column
21
+ # * main_table_id_column : column in main table matching counted_table_id_column in counted_table
22
+ # * counter_column : column in main table containing the counter cache
23
+ # * counted_table : name of table being counted
24
+ # * counted_table_id_column : column in counted_table matching main_table_id_column in main_table
25
+ # * opts : option hash, see module documentation
26
+ def pgt_counter_cache(main_table, main_table_id_column, counter_column, counted_table, counted_table_id_column, opts={})
27
+ trigger_name = opts[:trigger_name] || "pgt_cc_#{main_table}__#{main_table_id_column}__#{counter_column}__#{counted_table_id_column}"
28
+ function_name = opts[:function_name] || "pgt_cc_#{main_table}__#{main_table_id_column}__#{counter_column}__#{counted_table}__#{counted_table_id_column}"
29
+ pgt_trigger(counted_table, trigger_name, function_name, [:insert, :delete], <<-SQL)
30
+ BEGIN
31
+ IF (TG_OP = 'DELETE') THEN
32
+ UPDATE #{quote_schema_table(main_table)} SET #{quote_identifier(counter_column)} = #{quote_identifier(counter_column)} - 1 WHERE #{quote_identifier(main_table_id_column)} = OLD.#{counted_table_id_column};
33
+ RETURN OLD;
34
+ ELSIF (TG_OP = 'INSERT') THEN
35
+ UPDATE #{quote_schema_table(main_table)} SET #{quote_identifier(counter_column)} = #{quote_identifier(counter_column)} + 1 WHERE #{quote_identifier(main_table_id_column)} = NEW.#{quote_identifier(counted_table_id_column)};
36
+ RETURN NEW;
37
+ END IF;
38
+ END;
39
+ SQL
40
+ end
41
+
42
+ # Turns a column in the table into a created at timestamp column, which
43
+ # always contains the timestamp the record was inserted into the database.
44
+ # Arguments:
45
+ # * table : name of table
46
+ # * column : column in table that should be a created at timestamp column
47
+ # * opts : option hash, see module documentation
48
+ def pgt_created_at(table, column, opts={})
49
+ trigger_name = opts[:trigger_name] || "pgt_ca_#{column}"
50
+ function_name = opts[:function_name] || "pgt_ca_#{table}__#{column}"
51
+ pgt_trigger(table, trigger_name, function_name, [:insert, :update], <<-SQL)
52
+ BEGIN
53
+ IF (TG_OP = 'UPDATE') THEN
54
+ NEW.#{quote_identifier(column)} := OLD.#{quote_identifier(column)};
55
+ ELSIF (TG_OP = 'INSERT') THEN
56
+ NEW.#{quote_identifier(column)} := CURRENT_TIMESTAMP;
57
+ END IF;
58
+ RETURN NEW;
59
+ END;
60
+ SQL
61
+ end
62
+
63
+ # Makes all given columns in the given table immutable, so an exception
64
+ # is raised if there is an attempt to modify the value when updating the
65
+ # record. Arguments:
66
+ # * table : name of table
67
+ # * columns : All columns in the table that should be immutable. Can end with a hash of options, see module documentation.
68
+ def pgt_immutable(table, *columns)
69
+ opts = columns.last.is_a?(Hash) ? columns.pop : {}
70
+ trigger_name = opts[:trigger_name] || "pgt_im_#{columns.join('__')}"
71
+ function_name = opts[:function_name] || "pgt_im_#{columns.join('__')}"
72
+ ifs = columns.map do |c|
73
+ old = "OLD.#{quote_identifier(c)}"
74
+ new = "NEW.#{quote_identifier(c)}"
75
+ <<-END
76
+ IF #{new} != #{old} THEN
77
+ RAISE EXCEPTION 'Attempted event_id update: Old: %, New: %', #{old}, #{new};
78
+ END IF;
79
+ END
80
+ end.join("\n")
81
+ pgt_trigger(table, trigger_name, function_name, :update, "BEGIN #{ifs} RETURN NEW; END;")
82
+ end
83
+
84
+ # Turns a column in the main table into a sum cache. A sum cache is a
85
+ # column in the main table with the sum of a column in the summed table
86
+ # for the matching id. Arguments:
87
+ # * main_table : name of table holding counter cache column
88
+ # * main_table_id_column : column in main table matching counted_table_id_column in counted_table
89
+ # * sum_column : column in main table containing the sum cache
90
+ # * summed_table : name of table being summed
91
+ # * summed_table_id_column : column in summed_table matching main_table_id_column in main_table
92
+ # * summed_column : column in summed_table being summed
93
+ # * opts : option hash, see module documentation
94
+ def pgt_sum_cache(main_table, main_table_id_column, sum_column, summed_table, summed_table_id_column, summed_column, opts={})
95
+ trigger_name = opts[:trigger_name] || "pgt_sc_#{main_table}__#{main_table_id_column}__#{sum_column}__#{summed_table_id_column}"
96
+ function_name = opts[:function_name] || "pgt_sc_#{main_table}__#{main_table_id_column}__#{sum_column}__#{summed_table}__#{summed_table_id_column}__#{summed_column}"
97
+ pgt_trigger(summed_table, trigger_name, function_name, [:insert, :delete, :update], <<-SQL)
98
+ BEGIN
99
+ IF (TG_OP = 'DELETE') THEN
100
+ UPDATE #{quote_schema_table(main_table)} SET #{quote_identifier(sum_column)} = #{quote_identifier(sum_column)} - OLD.#{quote_identifier(summed_column)} WHERE #{quote_identifier(main_table_id_column)} = OLD.#{summed_table_id_column};
101
+ RETURN OLD;
102
+ ELSIF (TG_OP = 'UPDATE') THEN
103
+ UPDATE #{quote_schema_table(main_table)} SET #{quote_identifier(sum_column)} = #{quote_identifier(sum_column)} + NEW.#{quote_identifier(summed_column)} - OLD.#{quote_identifier(summed_column)} WHERE #{quote_identifier(main_table_id_column)} = NEW.#{quote_identifier(summed_table_id_column)};
104
+ RETURN NEW;
105
+ ELSIF (TG_OP = 'INSERT') THEN
106
+ UPDATE #{quote_schema_table(main_table)} SET #{quote_identifier(sum_column)} = #{quote_identifier(sum_column)} + NEW.#{quote_identifier(summed_column)} WHERE #{quote_identifier(main_table_id_column)} = NEW.#{quote_identifier(summed_table_id_column)};
107
+ RETURN NEW;
108
+ END IF;
109
+ END;
110
+ SQL
111
+ end
112
+
113
+ # Turns a column in the table into a updated at timestamp column, which
114
+ # always contains the timestamp the record was inserted or last updated.
115
+ # Arguments:
116
+ # * table : name of table
117
+ # * column : column in table that should be a updated at timestamp column
118
+ # * opts : option hash, see module documentation
119
+ def pgt_updated_at(table, column, opts={})
120
+ trigger_name = opts[:trigger_name] || "pgt_ua_#{column}"
121
+ function_name = opts[:function_name] || "pgt_ua_#{table}__#{column}"
122
+ pgt_trigger(table, trigger_name, function_name, [:insert, :update], <<-SQL)
123
+ BEGIN
124
+ NEW.#{quote_identifier(column)} := CURRENT_TIMESTAMP;
125
+ RETURN NEW;
126
+ END;
127
+ SQL
128
+ end
129
+
130
+ private
131
+
132
+ # Add or replace a function that returns trigger to handle the action,
133
+ # and add a trigger that calls the function.
134
+ def pgt_trigger(table, trigger_name, function_name, events, definition)
135
+ create_function(function_name, definition, :language=>:plpgsql, :returns=>:trigger, :replace=>true)
136
+ create_trigger(table, trigger_name, function_name, :events=>events, :each_row=>true)
137
+ end
138
+ end
139
+ end
140
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jeremyevans-sequel_postgresql_triggers
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-10-27 00:00:00 -07:00
12
+ date: 2009-05-16 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15