· 8 years ago · Mar 07, 2018, 04:20 PM
1class Sequel::Dataset
2
3 # This makes sure the original Sequel methods are aliased only once.
4 # Since the framework this was built for will reload these pages if they change,
5 # it was necessary. The conditional part of code not required for most other uses
6 # but is not harmful either.
7 if !defined?( DATASET_ALIASED )
8 alias_method :orig_insert_sql, :insert_sql
9 alias_method :orig_update_sql, :update_sql
10 alias_method :orig_delete_sql, :delete_sql
11 DATASET_ALIASED = true
12 end
13
14 # Allows insert_sql method to accept a HyperModel or any object that exposes
15 # a #sequel_values method
16
17 def insert_sql( *args )
18 if ( args.size == 1 ) && args[0].respond_to?( :sequel_values )
19 orig_insert_sql( args[0].sequel_values )
20 else
21 orig_insert_sql( *args )
22 end
23 end
24
25 # UPDATE AND DELETE SQL MONKEY-PATCH
26
27 # This code protects us from doing something stupid. Since it is so easy to call the
28 # update or delete method on a dataset, this patch will throw an error if there is no
29 # filter placed on the dataset. In other words, it won't let you easily update all
30 # the records in a table.
31 #
32 # The workaround is to do this (assumes a dataset named 'scribbles'):
33 #
34 # scribbles.unrestrict.update( :rating => 5 )
35 #
36 # The Dataset#full method is a filter that doesn't restrict anything.
37
38 def update_sql( *args )
39 validate_where_exists
40 orig_update_sql( *args )
41 end
42
43 def delete_sql( *args )
44 validate_where_exists
45 orig_delete_sql( *args )
46 end
47
48 def validate_where_exists
49 if !opts[ :where ]
50 raise 'The Dataset#update and Dataset#delete methods require a filter to be in place. ' +
51 'This protects you from accidentally updating or deleting all records in a database by accident. ' +
52 'The workaround is to apply a filter like dataset.unrestrict.delete that includes all records.'
53 end
54 end
55
56 # This filter doesn't do anything except make it possible for #update_sql and
57 # #delete_sql to execute without error because a where clause is in place.
58 def unrestrict
59 filter( '1 = 1' )
60 end
61
62 # CUSTOM ATTRIBUTE READERS
63 # These are mostly convenience methods that lets us pull data out of the
64 # dataset without having to delve into #opts
65
66 # Returns table name as symbol
67 def table
68 opts[:from].first
69 end
70
71 # Returns hash of models
72 def models
73 opts[:models]
74 end
75
76 # If there is only a single model, returns it.
77 def model
78 models[nil]
79 end
80
81 # Returns true if the table for the given dataset exists
82 def table_exists?
83 db.table_exists?( table )
84 end
85
86 # CREATE AND DROP TABLE
87
88 def create_table
89 model.create_table( db, table )
90 end
91
92 def drop_table
93 db.drop_table( table ) if table_exists?
94 end
95
96 def recreate_table
97 drop_table
98 create_table
99 end
100
101 # METHOD MISSING
102
103 def method_missing( method, *args )
104
105 # Creates #find_by_name_and_email like methods
106 if method.to_s.starts_with?( 'find_by_' )
107 columns = method.to_s[8..-1].split('_and_')
108 hash = {}
109 columns.each_with_index do |col,i|
110 hash[col.to_sym] = args[i]
111 end
112 self.filter( hash )
113
114 # Missing methods are delegated to the model. The model must implement
115 # methods like:
116 #
117 # def self.dataset_method
118 # end
119 #
120 # where 'method' is the name of the dataset method to implement
121 else
122 dataset_method = ( 'dataset_' + method.to_s ).to_sym
123 if model.respond_to?( dataset_method )
124 model.send( dataset_method, self, *args )
125 else
126 raise "Couldn't find a Sequel::Dataset##{method} method "+
127 "nor a Hyper::Model##{dataset_method} method"
128 end
129 end
130 end
131
132end