Class: Og::Backend
Overview
Abstract backend. A backend communicates with the RDBMS. This is the base class for the various backend implementations.
Instance Attribute Summary collapse
-
#conn ⇒ Object
The actual connection to the database.
Class Method Summary collapse
-
.create_db(database, user = nil, password = nil) ⇒ Object
Create the database.
-
.drop_db(database, user = nil, password = nil) ⇒ Object
Drop the database.
-
.encode(klass) ⇒ Object
Encode the name of the klass as an sql safe string.
-
.eval_og_deserialize(klass, og) ⇒ Object
Precompile the code to read objects of the given class from the backend.
-
.eval_og_insert(klass) ⇒ Object
Precompile the insert code for the given class.
-
.eval_og_update(klass) ⇒ Object
Precompile the update code for the given class.
-
.join_table(klass1, klass2) ⇒ Object
The name of the join table for the two given classes.
-
.props_for_insert(klass) ⇒ Object
Returns the props that will be included in the insert query.
-
.table(klass) ⇒ Object
The name of the SQL table where objects of this class are stored.
Instance Method Summary collapse
-
#close ⇒ Object
Close the connection to the RDBMS.
-
#commit ⇒ Object
Commit a transaction.
-
#create_fields(klass, typemap) ⇒ Object
Create the fields that correpsond to the klass properties.
-
#create_table(klass) ⇒ Object
Create the managed object table.
-
#deserialize_all(res, klass) ⇒ Object
Deserialize all rows of the resultset.
-
#deserialize_one(res, klass) ⇒ Object
Deserialize one row of the resultset.
-
#drop_table(klass) ⇒ Object
Drop the managed object table.
-
#exec(sql) ⇒ Object
Execute an SQL query, no result returned.
-
#get_int(res, idx = 0) ⇒ Object
Return a single integer value from the resultset.
-
#initialize(config) ⇒ Backend
constructor
Intitialize the connection to the RDBMS.
-
#query(sql) ⇒ Object
Execute an SQL query and return the result.
-
#rollback ⇒ Object
Rollback transaction.
-
#safe_exec(sql) ⇒ Object
Execute an SQL query, no result returned.
-
#safe_query(sql) ⇒ Object
Execute an SQL query and return the result.
-
#start ⇒ Object
Start a new transaction.
-
#valid?(res) ⇒ Boolean
Check if it is a valid resultset.
Constructor Details
#initialize(config) ⇒ Backend
Intitialize the connection to the RDBMS.
21 22 23 |
# File 'lib/og/backend.rb', line 21 def initialize(config) raise "Not implemented" end |
Instance Attribute Details
#conn ⇒ Object
The actual connection to the database
17 18 19 |
# File 'lib/og/backend.rb', line 17 def conn @conn end |
Class Method Details
.create_db(database, user = nil, password = nil) ⇒ Object
Create the database.
173 174 175 |
# File 'lib/og/backend.rb', line 173 def self.create_db(database, user = nil, password = nil) Logger.info "Creating database '#{database}'." end |
.drop_db(database, user = nil, password = nil) ⇒ Object
Drop the database.
179 180 181 |
# File 'lib/og/backend.rb', line 179 def self.drop_db(database, user = nil, password = nil) Logger.info "Dropping database '#{database}'." end |
.encode(klass) ⇒ Object
Encode the name of the klass as an sql safe string. The Module separators are replaced with _ and NOT stripped out so that we can convert back to the original notation if needed. The leading module if available is removed.
40 41 42 |
# File 'lib/og/backend.rb', line 40 def self.encode(klass) "#{klass.name.gsub(/^.*::/, "")}".gsub(/::/, "_").downcase end |
.eval_og_deserialize(klass, og) ⇒ Object
Precompile the code to read objects of the given class from the backend. In order to allow for changing field/attribute orders we have to use a field mapping hash.
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/og/backend.rb', line 146 def self.eval_og_deserialize(klass, og) calc_field_index(klass, og) props = klass.__props code = [] props.each do |p| if idx = og.managed_classes[klass].field_index[p.name] # more fault tolerant if a new field is added and it # doesnt exist in the database. code << "@#{p.name} = #{read_prop(p, idx)}" end end klass.class_eval %{ def og_deserialize(res, tuple = nil) #{code.join('; ')} end } end |
.eval_og_insert(klass) ⇒ Object
Precompile the insert code for the given class. The generated code sets the oid when inserting!
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/og/backend.rb', line 67 def self.eval_og_insert(klass) props = props_for_insert(klass) values = props.collect { |p| write_prop(p) } sql = "INSERT INTO #{table(klass)} (#{props.collect {|p| p.name}.join(',')}) VALUES (#{values.join(',')})" if klass.instance_methods.include?("og_pre_insert") pre_cb = "og_pre_insert(conn);" else pre_cb = "" end if klass.instance_methods.include?("og_post_insert") post_cb = "og_post_insert(conn);" else post_cb = "" end if klass.instance_methods.include?("og_pre_insert_update") pre_cb << "og_pre_insert_update(conn);" end if klass.instance_methods.include?("og_post_insert_update") post_cb << "og_post_insert_update(conn);" end klass.class_eval %{ def og_insert(conn) #{insert_code(klass, sql, pre_cb, post_cb)} end } end |
.eval_og_update(klass) ⇒ Object
Precompile the update code for the given class. Ignore the oid when updating!
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/og/backend.rb', line 104 def self.eval_og_update(klass) props = klass.__props.reject { |p| :oid == p.symbol } updates = props.collect { |p| "#{p.name}=#{write_prop(p)}" } sql = "UPDATE #{klass::DBTABLE} SET #{updates.join(', ')} WHERE oid=#\{@oid\}" if klass.instance_methods.include?("og_pre_update") pre_cb = "og_pre_update(conn);" else pre_cb = "" end if klass.instance_methods.include?("og_post_update") post_cb = "og_post_update(conn);" else post_cb = "" end if klass.instance_methods.include?("og_pre_insert_update") pre_cb << "og_pre_insert_update(conn);" end if klass.instance_methods.include?("og_post_insert_update") post_cb << "og_post_insert_update(conn);" end klass.class_eval %{ def og_update(conn) #{pre_cb} conn.exec "#{sql}" #{post_cb} end } end |
.join_table(klass1, klass2) ⇒ Object
The name of the join table for the two given classes.
53 54 55 |
# File 'lib/og/backend.rb', line 53 def self.join_table(klass1, klass2) "_#{Og.table_prefix}j_#{encode(klass1)}_#{encode(klass2)}" end |
.props_for_insert(klass) ⇒ Object
Returns the props that will be included in the insert query. For some backends the oid should be stripped.
60 61 62 |
# File 'lib/og/backend.rb', line 60 def self.props_for_insert(klass) klass.__props end |
Instance Method Details
#close ⇒ Object
Close the connection to the RDBMS.
27 28 29 |
# File 'lib/og/backend.rb', line 27 def close() @conn.close() end |
#commit ⇒ Object
Commit a transaction.
223 224 225 |
# File 'lib/og/backend.rb', line 223 def commit exec "COMMIT" end |
#create_fields(klass, typemap) ⇒ Object
Create the fields that correpsond to the klass properties. The generated fields array is used in create_table. If the property has an :sql metadata this overrides the default mapping. If the property has an :extra_sql metadata the extra sql is appended after the default mapping.
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'lib/og/backend.rb', line 239 def create_fields(klass, typemap) fields = [] klass.__props.each do |p| klass.sql_index(p.symbol) if p.[:sql_index] field = "#{p.symbol}" if p. and p.[:sql] field << " #{p.[:sql]}" else field << " #{typemap[p.klass]}" # attach extra sql if p. and extra_sql = p.[:extra_sql] field << " #{extra_sql}" end end fields << field end return fields end |
#create_table(klass) ⇒ Object
Create the managed object table. The properties of the object are mapped to the table columns. Additional sql relations and constrains are created (indicices, sequences, etc).
267 268 269 |
# File 'lib/og/backend.rb', line 267 def create_table(klass) return if query("SELECT * FROM #{klass::DBTABLE} LIMIT 1") end |
#deserialize_all(res, klass) ⇒ Object
Deserialize all rows of the resultset.
285 286 287 |
# File 'lib/og/backend.rb', line 285 def deserialize_all(res, klass) raise 'Not implemented' end |
#deserialize_one(res, klass) ⇒ Object
Deserialize one row of the resultset.
279 280 281 |
# File 'lib/og/backend.rb', line 279 def deserialize_one(res, klass) raise 'Not implemented' end |
#drop_table(klass) ⇒ Object
Drop the managed object table
273 274 275 |
# File 'lib/og/backend.rb', line 273 def drop_table(klass) exec "DROP TABLE #{klass::DBTABLE}" end |
#exec(sql) ⇒ Object
Execute an SQL query, no result returned.
191 192 193 |
# File 'lib/og/backend.rb', line 191 def exec(sql) raise "Not implemented" end |
#get_int(res, idx = 0) ⇒ Object
Return a single integer value from the resultset.
291 292 293 |
# File 'lib/og/backend.rb', line 291 def get_int(res, idx = 0) raise 'Not implemented' end |
#query(sql) ⇒ Object
Execute an SQL query and return the result.
185 186 187 |
# File 'lib/og/backend.rb', line 185 def query(sql) raise "Not implemented" end |
#rollback ⇒ Object
Rollback transaction.
229 230 231 |
# File 'lib/og/backend.rb', line 229 def rollback exec "ROLLBACK" end |
#safe_exec(sql) ⇒ Object
Execute an SQL query, no result returned. Wrapped in a rescue block.
205 206 207 |
# File 'lib/og/backend.rb', line 205 def safe_exec(sql) raise "Not implemented" end |
#safe_query(sql) ⇒ Object
Execute an SQL query and return the result. Wrapped in a rescue block.
198 199 200 |
# File 'lib/og/backend.rb', line 198 def safe_query(sql) raise "Not implemented" end |
#start ⇒ Object
Start a new transaction.
217 218 219 |
# File 'lib/og/backend.rb', line 217 def start exec "START TRANSACTION" end |
#valid?(res) ⇒ Boolean
Check if it is a valid resultset.
211 212 213 |
# File 'lib/og/backend.rb', line 211 def valid?(res) raise "Not implemented" end |