webmcp

annotate libraries/mondelefant/mondelefant.lua @ 55:594a85118cb7

Bugfix in <db_selector>:add_from(...) and <db_selector>:left_join(...)
author jbe
date Sun Dec 18 21:14:43 2011 +0100 (2011-12-18)
parents 791849c58105
children 3d43a5cf17c1
rev   line source
jbe/bsw@0 1 #!/usr/bin/env lua
jbe/bsw@0 2
jbe/bsw@0 3
jbe/bsw@0 4 ---------------------------
jbe/bsw@0 5 -- module initialization --
jbe/bsw@0 6 ---------------------------
jbe/bsw@0 7
jbe/bsw@0 8 local _G = _G
jbe/bsw@0 9 local _VERSION = _VERSION
jbe/bsw@0 10 local assert = assert
jbe/bsw@0 11 local collectgarbage = collectgarbage
jbe/bsw@0 12 local dofile = dofile
jbe/bsw@0 13 local error = error
jbe/bsw@0 14 local getfenv = getfenv
jbe/bsw@0 15 local getmetatable = getmetatable
jbe/bsw@0 16 local ipairs = ipairs
jbe/bsw@0 17 local load = load
jbe/bsw@0 18 local loadfile = loadfile
jbe/bsw@0 19 local loadstring = loadstring
jbe/bsw@0 20 local next = next
jbe/bsw@0 21 local pairs = pairs
jbe/bsw@0 22 local pcall = pcall
jbe/bsw@0 23 local print = print
jbe/bsw@0 24 local rawequal = rawequal
jbe/bsw@0 25 local rawget = rawget
jbe/bsw@0 26 local rawset = rawset
jbe/bsw@0 27 local select = select
jbe/bsw@0 28 local setfenv = setfenv
jbe/bsw@0 29 local setmetatable = setmetatable
jbe/bsw@0 30 local tonumber = tonumber
jbe/bsw@0 31 local tostring = tostring
jbe/bsw@0 32 local type = type
jbe/bsw@0 33 local unpack = unpack
jbe/bsw@0 34 local xpcall = xpcall
jbe/bsw@0 35
jbe/bsw@0 36 local coroutine = coroutine
jbe/bsw@0 37 local io = io
jbe/bsw@0 38 local math = math
jbe/bsw@0 39 local os = os
jbe/bsw@0 40 local string = string
jbe/bsw@0 41 local table = table
jbe/bsw@0 42
jbe/bsw@0 43 local add = table.insert
jbe/bsw@0 44
jbe/bsw@0 45 _G[...] = require("mondelefant_native")
jbe/bsw@0 46 module(...)
jbe/bsw@0 47
jbe/bsw@0 48
jbe/bsw@0 49
jbe/bsw@0 50 ---------------
jbe/bsw@0 51 -- selectors --
jbe/bsw@0 52 ---------------
jbe/bsw@0 53
jbe/bsw@0 54 selector_metatable = {}
jbe/bsw@0 55 selector_prototype = {}
jbe/bsw@0 56 selector_metatable.__index = selector_prototype
jbe/bsw@0 57
jbe/bsw@0 58 local function init_selector(self, db_conn)
jbe/bsw@0 59 self._db_conn = db_conn
jbe/bsw@0 60 self._mode = "list"
jbe@39 61 self._with = { sep = ", " }
jbe/bsw@0 62 self._fields = { sep = ", " }
jbe/bsw@0 63 self._distinct = false
jbe/bsw@0 64 self._distinct_on = {sep = ", ", expression}
jbe/bsw@0 65 self._from = { sep = " " }
jbe/bsw@4 66 self._where = { sep = ") AND (" }
jbe/bsw@0 67 self._group_by = { sep = ", " }
jbe/bsw@4 68 self._having = { sep = ") AND (" }
jbe/bsw@0 69 self._combine = { sep = " " }
jbe/bsw@0 70 self._order_by = { sep = ", " }
jbe/bsw@0 71 self._limit = nil
jbe/bsw@0 72 self._offset = nil
jbe/bsw@4 73 self._read_lock = { sep = ", " }
jbe/bsw@4 74 self._write_lock = { sep = ", " }
jbe/bsw@0 75 self._class = nil
jbe/bsw@0 76 self._attach = nil
jbe/bsw@0 77 return self
jbe/bsw@0 78 end
jbe/bsw@0 79
jbe@23 80 --[[--
jbe@23 81 selector = -- new selector
jbe@23 82 <db_handle>:new_selector()
jbe@23 83
jbe@23 84 Creates a new selector to operate on the given database handle.
jbe@23 85 --]]--
jbe/bsw@0 86 function connection_prototype:new_selector()
jbe/bsw@0 87 return init_selector(setmetatable({}, selector_metatable), self)
jbe/bsw@0 88 end
jbe@23 89 --//--
jbe/bsw@0 90
jbe@23 91 --[[--
jbe@23 92 db_handle = -- handle of database connection
jbe@23 93 <db_selector>:get_db_conn()
jbe@23 94
jbe@23 95 Returns the database connection handle used by a selector.
jbe@23 96
jbe@23 97 --]]--
jbe/bsw@0 98 function selector_prototype:get_db_conn()
jbe/bsw@0 99 return self._db_conn
jbe/bsw@0 100 end
jbe@23 101 --//--
jbe/bsw@0 102
jbe/bsw@0 103 -- TODO: selector clone?
jbe/bsw@0 104
jbe@23 105 --[[--
jbe@23 106 db_selector = -- same selector returned
jbe@23 107 <db_selector>:single_object_mode()
jbe@23 108
jbe@23 109 Sets selector to single object mode (mode "object" passed to "query" method of database handle). The selector is modified and returned.
jbe@23 110
jbe@23 111 --]]--
jbe/bsw@0 112 function selector_prototype:single_object_mode()
jbe/bsw@0 113 self._mode = "object"
jbe/bsw@0 114 return self
jbe/bsw@0 115 end
jbe@23 116 --//--
jbe/bsw@0 117
jbe@23 118 --[[--
jbe@23 119 db_selector = -- same selector returned
jbe@23 120 <db_selector>:optional_object_mode()
jbe@23 121
jbe@23 122 Sets selector to single object mode (mode "opt_object" passed to "query" method of database handle). The selector is modified and returned.
jbe@23 123
jbe@23 124 --]]--
jbe/bsw@0 125 function selector_prototype:optional_object_mode()
jbe/bsw@0 126 self._mode = "opt_object"
jbe/bsw@0 127 return self
jbe/bsw@0 128 end
jbe@23 129 --//--
jbe/bsw@0 130
jbe@23 131 --[[--
jbe@23 132 db_selector = -- same selector returned
jbe@23 133 <db_selector>:empty_list_mode()
jbe@23 134
jbe@23 135 Sets selector to empty list mode. The selector is modified and returned. When using the selector, no SQL query will be issued, but instead an empty database result list is returned.
jbe@23 136
jbe@23 137 --]]--
jbe/bsw@0 138 function selector_prototype:empty_list_mode()
jbe/bsw@0 139 self._mode = "empty_list"
jbe/bsw@0 140 return self
jbe/bsw@0 141 end
jbe@23 142 --//--
jbe/bsw@0 143
jbe@23 144 --[[--
jbe@39 145 db_selector =
jbe@39 146 <db_selector>:add_with(
jbe@39 147 expression = expression,
jbe@39 148 selector = selector
jbe@39 149 )
jbe@39 150
jbe@39 151 Adds an WITH RECURSIVE expression to the selector. The selector is modified and returned.
jbe@39 152 --]]--
jbe@39 153 function selector_prototype:add_with(expression, selector)
jbe@39 154 add(self._with, {"$ AS ($)", {expression}, {selector}})
jbe@39 155 return self
jbe@39 156 end
jbe@39 157 --//--
jbe@39 158
jbe@39 159 --[[--
jbe@23 160 db_selector = -- same selector returned
jbe@23 161 <db_selector>:add_distinct_on(
jbe@23 162 expression -- expression as passed to "assemble_command"
jbe@23 163 )
jbe@23 164
jbe@23 165 Adds an DISTINCT ON expression to the selector. The selector is modified and returned.
jbe@23 166
jbe@23 167 --]]--
jbe/bsw@0 168 function selector_prototype:add_distinct_on(expression)
jbe/bsw@0 169 if self._distinct then
jbe/bsw@0 170 error("Can not combine DISTINCT with DISTINCT ON.")
jbe/bsw@0 171 end
jbe/bsw@0 172 add(self._distinct_on, expression)
jbe/bsw@0 173 return self
jbe/bsw@0 174 end
jbe@23 175 --//--
jbe/bsw@0 176
jbe@23 177 --[[--
jbe@23 178 db_selector = -- same selector returned
jbe@23 179 <db_selector>:set_distinct()
jbe@23 180
jbe@23 181 Sets selector to perform a SELECT DISTINCT instead of SELECT (ALL). The selector is modified and returned. This mode can not be combined with DISTINCT ON.
jbe@23 182
jbe@23 183 --]]--
jbe/bsw@0 184 function selector_prototype:set_distinct()
jbe/bsw@0 185 if #self._distinct_on > 0 then
jbe/bsw@0 186 error("Can not combine DISTINCT with DISTINCT ON.")
jbe/bsw@0 187 end
jbe/bsw@0 188 self._distinct = true
jbe/bsw@0 189 return self
jbe/bsw@0 190 end
jbe@23 191 --//--
jbe/bsw@0 192
jbe@23 193 --[[--
jbe@23 194 db_selector = -- same selector returned
jbe@23 195 <db_selector>:add_from(
jbe@23 196 expression, -- expression as passed to "assemble_command"
jbe@23 197 alias, -- optional alias expression as passed to "assemble_command"
jbe@23 198 condition -- optional condition expression as passed to "assemble_command"
jbe@23 199 )
jbe@23 200
jbe@23 201 Adds expressions for FROM clause to the selector. The selector is modified and returned. If an additional condition is given, an INNER JOIN will be used, otherwise a CROSS JOIN.
jbe@23 202
jbe@23 203 This method is identical to "join".
jbe@23 204
jbe@23 205 --]]--
jbe/bsw@0 206 function selector_prototype:add_from(expression, alias, condition)
jbe/bsw@0 207 local first = (#self._from == 0)
jbe/bsw@0 208 if not first then
jbe/bsw@0 209 if condition then
jbe/bsw@0 210 add(self._from, "INNER JOIN")
jbe/bsw@0 211 else
jbe/bsw@0 212 add(self._from, "CROSS JOIN")
jbe/bsw@0 213 end
jbe/bsw@0 214 end
jbe/bsw@0 215 if getmetatable(expression) == selector_metatable then
jbe/bsw@0 216 if alias then
jbe/bsw@0 217 add(self._from, {'($) AS "$"', {expression}, {alias}})
jbe/bsw@0 218 else
jbe/bsw@0 219 add(self._from, {'($) AS "subquery"', {expression}})
jbe/bsw@0 220 end
jbe/bsw@0 221 else
jbe/bsw@0 222 if alias then
jbe/bsw@0 223 add(self._from, {'$ AS "$"', {expression}, {alias}})
jbe/bsw@0 224 else
jbe/bsw@0 225 add(self._from, expression)
jbe/bsw@0 226 end
jbe/bsw@0 227 end
jbe/bsw@0 228 if condition then
jbe/bsw@0 229 if first then
jbe@55 230 self:add_where(condition)
jbe/bsw@0 231 else
jbe/bsw@0 232 add(self._from, "ON")
jbe/bsw@0 233 add(self._from, condition)
jbe/bsw@0 234 end
jbe/bsw@0 235 end
jbe/bsw@0 236 return self
jbe/bsw@0 237 end
jbe@23 238 --//--
jbe/bsw@0 239
jbe@23 240 --[[--
jbe@23 241 db_selector = -- same selector returned
jbe@23 242 <db_selector>:add_where(
jbe@23 243 expression -- expression as passed to "assemble_command"
jbe@23 244 )
jbe@23 245
jbe@23 246 Adds expressions for WHERE clause to the selector. The selector is modified and returned. Multiple calls cause expressions to be AND-combined.
jbe@23 247
jbe@23 248 --]]--
jbe/bsw@0 249 function selector_prototype:add_where(expression)
jbe/bsw@0 250 add(self._where, expression)
jbe/bsw@0 251 return self
jbe/bsw@0 252 end
jbe@23 253 --//--
jbe/bsw@0 254
jbe@23 255 --[[--
jbe@23 256 db_selector = -- same selector returned
jbe@23 257 <db_selector>:add_group_by(
jbe@23 258 expression -- expression as passed to "assemble_command"
jbe@23 259 )
jbe@23 260
jbe@23 261 Adds expressions for GROUP BY clause to the selector. The selector is modified and returned.
jbe@23 262
jbe@23 263 --]]--
jbe/bsw@0 264 function selector_prototype:add_group_by(expression)
jbe/bsw@0 265 add(self._group_by, expression)
jbe/bsw@0 266 return self
jbe/bsw@0 267 end
jbe@23 268 --//--
jbe/bsw@0 269
jbe@23 270 --[[--
jbe@23 271 db_selector = -- same selector returned
jbe@23 272 <db_selector>:add_having(
jbe@23 273 expression -- expression as passed to "assemble_command"
jbe@23 274 )
jbe@23 275
jbe@23 276 Adds expressions for HAVING clause to the selector. The selector is modified and returned. Multiple calls cause expressions to be AND-combined.
jbe@23 277
jbe@23 278 --]]--
jbe/bsw@0 279 function selector_prototype:add_having(expression)
jbe/bsw@0 280 add(self._having, expression)
jbe/bsw@0 281 return self
jbe/bsw@0 282 end
jbe@23 283 --//--
jbe/bsw@0 284
jbe@23 285 --[[--
jbe@23 286 db_selector = -- same selector returned
jbe@23 287 <db_selector>:add_combine(
jbe@23 288 expression -- expression as passed to "assemble_command"
jbe@23 289 )
jbe@23 290
jbe@23 291 This function is used for UNION/INTERSECT/EXCEPT clauses. It does not need to be called directly. Use "union", "union_all", "intersect", "intersect_all", "except" and "except_all" instead.
jbe@23 292
jbe@23 293 --]]--
jbe/bsw@0 294 function selector_prototype:add_combine(expression)
jbe/bsw@0 295 add(self._combine, expression)
jbe/bsw@0 296 return self
jbe/bsw@0 297 end
jbe@23 298 --//--
jbe/bsw@0 299
jbe@23 300 --[[--
jbe@23 301 db_selector = -- same selector returned
jbe@23 302 <db_selector>:add_order_by(
jbe@23 303 expression -- expression as passed to "assemble_command"
jbe@23 304 )
jbe@23 305
jbe@23 306 Adds expressions for ORDER BY clause to the selector. The selector is modified and returned.
jbe@23 307
jbe@23 308 --]]--
jbe/bsw@0 309 function selector_prototype:add_order_by(expression)
jbe/bsw@0 310 add(self._order_by, expression)
jbe/bsw@0 311 return self
jbe/bsw@0 312 end
jbe@23 313 --//--
jbe/bsw@0 314
jbe@23 315 --[[--
jbe@23 316 db_selector = -- same selector returned
jbe@23 317 <db_selector>:limit(
jbe@23 318 count -- integer used as LIMIT
jbe@23 319 )
jbe@23 320
jbe@23 321 Limits the number of rows to a given number, by using LIMIT. The selector is modified and returned.
jbe@23 322
jbe@23 323 --]]--
jbe/bsw@0 324 function selector_prototype:limit(count)
jbe/bsw@0 325 if type(count) ~= "number" or count % 1 ~= 0 then
jbe/bsw@0 326 error("LIMIT must be an integer.")
jbe/bsw@0 327 end
jbe/bsw@0 328 self._limit = count
jbe/bsw@0 329 return self
jbe/bsw@0 330 end
jbe@23 331 --//--
jbe/bsw@0 332
jbe@23 333 --[[--
jbe@23 334 db_selector = -- same selector returned
jbe@23 335 <db_selector>:offset(
jbe@23 336 count -- integer used as OFFSET
jbe@23 337 )
jbe@23 338
jbe@23 339 Skips a given number of rows, by using OFFSET. The selector is modified and returned.
jbe@23 340
jbe@23 341 --]]--
jbe/bsw@0 342 function selector_prototype:offset(count)
jbe/bsw@0 343 if type(count) ~= "number" or count % 1 ~= 0 then
jbe/bsw@0 344 error("OFFSET must be an integer.")
jbe/bsw@0 345 end
jbe/bsw@0 346 self._offset = count
jbe/bsw@0 347 return self
jbe/bsw@0 348 end
jbe@23 349 --//--
jbe/bsw@0 350
jbe@23 351 --[[--
jbe@23 352 db_selector = -- same selector returned
jbe@23 353 <db_selector>:for_share()
jbe@23 354
jbe@23 355 Adds FOR SHARE to the statement, to share-lock all rows read. The selector is modified and returned.
jbe@23 356
jbe@23 357 --]]--
jbe/bsw@4 358 function selector_prototype:for_share()
jbe/bsw@4 359 self._read_lock.all = true
jbe/bsw@4 360 return self
jbe/bsw@4 361 end
jbe@23 362 --//--
jbe/bsw@4 363
jbe@23 364 --[[--
jbe@23 365 db_selector = -- same selector returned
jbe@23 366 <db_selector>:for_share_of(
jbe@23 367 expression -- expression as passed to "assemble_command"
jbe@23 368 )
jbe@23 369
jbe@23 370 Adds FOR SHARE OF to the statement, to share-lock all rows read by the named table(s). The selector is modified and returned.
jbe@23 371
jbe@23 372 --]]--
jbe/bsw@4 373 function selector_prototype:for_share_of(expression)
jbe/bsw@4 374 add(self._read_lock, expression)
jbe/bsw@4 375 return self
jbe/bsw@4 376 end
jbe@23 377 --//--
jbe/bsw@4 378
jbe@23 379 --[[--
jbe@23 380 db_selector = -- same selector returned
jbe@23 381 <db_selector>:for_update()
jbe@23 382
jbe@23 383 Adds FOR UPDATE to the statement, to exclusivly lock all rows read. The selector is modified and returned.
jbe@23 384
jbe@23 385 --]]--
jbe/bsw@4 386 function selector_prototype:for_update()
jbe/bsw@4 387 self._write_lock.all = true
jbe/bsw@4 388 return self
jbe/bsw@4 389 end
jbe@23 390 --//--
jbe/bsw@4 391
jbe@23 392 --[[--
jbe@23 393 db_selector = -- same selector returned
jbe@23 394 <db_selector>:for_update_of(
jbe@23 395 expression -- expression as passed to "assemble_command"
jbe@23 396 )
jbe@23 397
jbe@23 398 Adds FOR SHARE OF to the statement, to exclusivly lock all rows read by the named table(s). The selector is modified and returned.
jbe@23 399
jbe@23 400 --]]--
jbe/bsw@4 401 function selector_prototype:for_update_of(expression)
jbe/bsw@4 402 add(self._write_lock, expression)
jbe/bsw@4 403 return self
jbe/bsw@4 404 end
jbe@23 405 --//--
jbe/bsw@4 406
jbe@23 407 --[[--
jbe@23 408 db_selector = -- same selector returned
jbe@23 409 <db_selector>:reset_fields()
jbe@23 410
jbe@23 411 This method removes all fields added by method "add_field". The selector is modified and returned.
jbe@23 412
jbe@23 413 --]]--
jbe/bsw@0 414 function selector_prototype:reset_fields()
jbe/bsw@0 415 for idx in ipairs(self._fields) do
jbe/bsw@0 416 self._fields[idx] = nil
jbe/bsw@0 417 end
jbe/bsw@0 418 return self
jbe/bsw@0 419 end
jbe@23 420 --//--
jbe/bsw@0 421
jbe@23 422 --[[--
jbe@23 423 db_selector = -- same selector returned
jbe@23 424 <db_selector>:add_field(
jbe@23 425 expression, -- expression as passed to "assemble_command"
jbe@23 426 alias, -- optional alias expression as passed to "assemble_command"
jbe@23 427 option_list -- optional list of options (may contain strings "distinct" or "grouped")
jbe@23 428 )
jbe@23 429
jbe@23 430 Adds fields to the selector. The selector is modified and returned. The third argument can be a list of options. If option "distinct" is given, then "add_distinct_on" will be executed for the given field or alias. If option "grouped" is given, then "add_group_by" will be executed for the given field or alias.
jbe@23 431
jbe@23 432 --]]--
jbe/bsw@0 433 function selector_prototype:add_field(expression, alias, options)
jbe/bsw@0 434 if alias then
jbe/bsw@0 435 add(self._fields, {'$ AS "$"', {expression}, {alias}})
jbe/bsw@0 436 else
jbe/bsw@0 437 add(self._fields, expression)
jbe/bsw@0 438 end
jbe/bsw@0 439 if options then
jbe/bsw@0 440 for i, option in ipairs(options) do
jbe/bsw@0 441 if option == "distinct" then
jbe/bsw@0 442 if alias then
jbe/bsw@0 443 self:add_distinct_on('"' .. alias .. '"')
jbe/bsw@0 444 else
jbe/bsw@0 445 self:add_distinct_on(expression)
jbe/bsw@0 446 end
jbe/bsw@0 447 elseif option == "grouped" then
jbe/bsw@0 448 if alias then
jbe/bsw@0 449 self:add_group_by('"' .. alias .. '"')
jbe/bsw@0 450 else
jbe/bsw@0 451 self:add_group_by(expression)
jbe/bsw@0 452 end
jbe/bsw@0 453 else
jbe/bsw@0 454 error("Unknown option '" .. option .. "' to add_field method.")
jbe/bsw@0 455 end
jbe/bsw@0 456 end
jbe/bsw@0 457 end
jbe/bsw@0 458 return self
jbe/bsw@0 459 end
jbe@23 460 --//--
jbe/bsw@0 461
jbe@23 462 --[[--
jbe@23 463 db_selector = -- same selector returned
jbe@23 464 <db_selector>:join(
jbe@23 465 expression, -- expression as passed to "assemble_command"
jbe@23 466 alias, -- optional alias expression as passed to "assemble_command"
jbe@23 467 condition -- optional condition expression as passed to "assemble_command"
jbe@23 468 )
jbe@23 469
jbe@23 470 Adds expressions for FROM clause to the selector. The selector is modified and returned. If an additional condition is given, an INNER JOIN will be used, otherwise a CROSS JOIN.
jbe@23 471
jbe@23 472 This method is identical to "add_from".
jbe@23 473
jbe@23 474 --]]--
jbe/bsw@0 475 function selector_prototype:join(...) -- NOTE: alias for add_from
jbe/bsw@0 476 return self:add_from(...)
jbe/bsw@0 477 end
jbe@23 478 --//--
jbe/bsw@0 479
jbe@23 480 --[[--
jbe@23 481 db_selector = -- same selector returned
jbe@23 482 <db_selector>:from(
jbe@23 483 expression, -- expression as passed to "assemble_command"
jbe@23 484 alias, -- optional alias expression as passed to "assemble_command"
jbe@23 485 condition -- optional condition expression as passed to "assemble_command"
jbe@23 486 )
jbe@23 487
jbe@23 488 Adds the first expression for FROM clause to the selector. The selector is modified and returned. If an additional condition is given, an INNER JOIN will be used, otherwise a CROSS JOIN.
jbe@23 489
jbe@23 490 This method is identical to "add_from" or "join", except that an error is thrown, if there is already any FROM expression existent.
jbe@23 491
jbe@23 492 --]]--
jbe/bsw@0 493 function selector_prototype:from(expression, alias, condition)
jbe/bsw@0 494 if #self._from > 0 then
jbe/bsw@0 495 error("From-clause already existing (hint: try join).")
jbe/bsw@0 496 end
jbe/bsw@0 497 return self:join(expression, alias, condition)
jbe/bsw@0 498 end
jbe@23 499 --//--
jbe/bsw@0 500
jbe@23 501 --[[--
jbe@23 502 db_selector = -- same selector returned
jbe@23 503 <db_selector>:left_join(
jbe@23 504 expression, -- expression as passed to "assemble_command"
jbe@23 505 alias, -- optional alias expression as passed to "assemble_command"
jbe@23 506 condition -- optional condition expression as passed to "assemble_command"
jbe@23 507 )
jbe@23 508
jbe@23 509 Adds expressions for FROM clause to the selector using a LEFT OUTER JOIN. The selector is modified and returned.
jbe@23 510
jbe@23 511 --]]--
jbe/bsw@0 512 function selector_prototype:left_join(expression, alias, condition)
jbe/bsw@0 513 local first = (#self._from == 0)
jbe/bsw@0 514 if not first then
jbe/bsw@0 515 add(self._from, "LEFT OUTER JOIN")
jbe/bsw@0 516 end
jbe/bsw@0 517 if alias then
jbe/bsw@0 518 add(self._from, {'$ AS "$"', {expression}, {alias}})
jbe/bsw@0 519 else
jbe/bsw@0 520 add(self._from, expression)
jbe/bsw@0 521 end
jbe/bsw@0 522 if condition then
jbe/bsw@0 523 if first then
jbe@55 524 self:add_where(condition)
jbe/bsw@0 525 else
jbe/bsw@0 526 add(self._from, "ON")
jbe/bsw@0 527 add(self._from, condition)
jbe/bsw@0 528 end
jbe/bsw@0 529 end
jbe/bsw@0 530 return self
jbe/bsw@0 531 end
jbe@23 532 --//--
jbe/bsw@0 533
jbe@23 534 --[[--
jbe@23 535 db_selector = -- same selector returned
jbe@23 536 <db_selector>:union(
jbe@23 537 expression -- expression or selector without ORDER BY, LIMIT, FOR UPDATE or FOR SHARE
jbe@23 538 )
jbe@23 539
jbe@23 540 This method adds an UNION clause to the given selector. The selector is modified and returned. The selector (or expression) passed as argument to this function shall not contain any ORDER BY, LIMIT, FOR UPDATE or FOR SHARE clauses.
jbe@23 541
jbe@23 542 --]]--
jbe/bsw@0 543 function selector_prototype:union(expression)
jbe/bsw@0 544 self:add_combine{"UNION $", {expression}}
jbe/bsw@0 545 return self
jbe/bsw@0 546 end
jbe@23 547 --//--
jbe/bsw@0 548
jbe@23 549 --[[--
jbe@23 550 db_selector = -- same selector returned
jbe@23 551 <db_selector>:union_all(
jbe@23 552 expression -- expression or selector without ORDER BY, LIMIT, FOR UPDATE or FOR SHARE
jbe@23 553 )
jbe@23 554
jbe@23 555 This method adds an UNION ALL clause to the given selector. The selector is modified and returned. The selector (or expression) passed as argument to this function shall not contain any ORDER BY, LIMIT, FOR UPDATE or FOR SHARE clauses.
jbe@23 556
jbe@23 557 --]]--
jbe/bsw@0 558 function selector_prototype:union_all(expression)
jbe/bsw@0 559 self:add_combine{"UNION ALL $", {expression}}
jbe/bsw@0 560 return self
jbe/bsw@0 561 end
jbe@23 562 --//--
jbe/bsw@0 563
jbe@23 564 --[[--
jbe@23 565 db_selector = -- same selector returned
jbe@23 566 <db_selector>:intersect(
jbe@23 567 expression -- expression or selector without ORDER BY, LIMIT, FOR UPDATE or FOR SHARE
jbe@23 568 )
jbe@23 569
jbe@23 570 This method adds an INTERSECT clause to the given selector. The selector is modified and returned. The selector (or expression) passed as argument to this function shall not contain any ORDER BY, LIMIT, FOR UPDATE or FOR SHARE clauses.
jbe@23 571
jbe@23 572 --]]--
jbe/bsw@0 573 function selector_prototype:intersect(expression)
jbe/bsw@0 574 self:add_combine{"INTERSECT $", {expression}}
jbe/bsw@0 575 return self
jbe/bsw@0 576 end
jbe@23 577 --//--
jbe/bsw@0 578
jbe@23 579 --[[--
jbe@23 580 db_selector = -- same selector returned
jbe@23 581 <db_selector>:intersect_all(
jbe@23 582 expression -- expression or selector without ORDER BY, LIMIT, FOR UPDATE or FOR SHARE
jbe@23 583 )
jbe@23 584
jbe@23 585 This method adds an INTERSECT ALL clause to the given selector. The selector is modified and returned. The selector (or expression) passed as argument to this function shall not contain any ORDER BY, LIMIT, FOR UPDATE or FOR SHARE clauses.
jbe@23 586
jbe@23 587 --]]--
jbe/bsw@0 588 function selector_prototype:intersect_all(expression)
jbe/bsw@0 589 self:add_combine{"INTERSECT ALL $", {expression}}
jbe/bsw@0 590 return self
jbe/bsw@0 591 end
jbe@23 592 --//--
jbe/bsw@0 593
jbe@23 594 --[[--
jbe@23 595 db_selector = -- same selector returned
jbe@23 596 <db_selector>:except(
jbe@23 597 expression -- expression or selector without ORDER BY, LIMIT, FOR UPDATE or FOR SHARE
jbe@23 598 )
jbe@23 599
jbe@23 600 This method adds an EXCEPT clause to the given selector. The selector is modified and returned. The selector (or expression) passed as argument to this function shall not contain any ORDER BY, LIMIT, FOR UPDATE or FOR SHARE clauses.
jbe@23 601
jbe@23 602 --]]--
jbe/bsw@0 603 function selector_prototype:except(expression)
jbe/bsw@0 604 self:add_combine{"EXCEPT $", {expression}}
jbe/bsw@0 605 return self
jbe/bsw@0 606 end
jbe@23 607 --//--
jbe/bsw@0 608
jbe@23 609 --[[--
jbe@23 610 db_selector = -- same selector returned
jbe@23 611 <db_selector>:except_all(
jbe@23 612 expression -- expression or selector without ORDER BY, LIMIT, FOR UPDATE or FOR SHARE
jbe@23 613 )
jbe@23 614
jbe@23 615 This method adds an EXCEPT ALL clause to the given selector. The selector is modified and returned. The selector (or expression) passed as argument to this function shall not contain any ORDER BY, LIMIT, FOR UPDATE or FOR SHARE clauses.
jbe@23 616
jbe@23 617 --]]--
jbe/bsw@0 618 function selector_prototype:except_all(expression)
jbe/bsw@0 619 self:add_combine{"EXCEPT ALL $", {expression}}
jbe/bsw@0 620 return self
jbe/bsw@0 621 end
jbe@23 622 --//--
jbe/bsw@0 623
jbe@23 624 --[[--
jbe@23 625 db_selector = -- same selector returned
jbe@23 626 <db_selector>:set_class(
jbe@23 627 class -- database class (model)
jbe@23 628 )
jbe@23 629
jbe@23 630 This method makes the selector to return database result lists or objects of the given database class (model). The selector is modified and returned.
jbe@23 631
jbe@23 632 --]]--
jbe/bsw@0 633 function selector_prototype:set_class(class)
jbe/bsw@0 634 self._class = class
jbe/bsw@0 635 return self
jbe/bsw@0 636 end
jbe@23 637 --//--
jbe/bsw@0 638
jbe@23 639 --[[--
jbe@23 640 db_selector = -- same selector returned
jbe@23 641 <db_selector>:attach(
jbe@23 642 mode, -- attachment type: "11" one to one, "1m" one to many, "m1" many to one
jbe@23 643 data2, -- other database result list or object, the results of this selector shall be attached with
jbe@23 644 field1, -- field name(s) in result list or object of this selector used for attaching
jbe@23 645 field2, -- field name(s) in "data2" used for attaching
jbe@23 646 ref1, -- name of reference field in the results of this selector after attaching
jbe@23 647 ref2 -- name of reference field in "data2" after attaching
jbe@23 648 )
jbe@23 649
jbe@23 650 This method causes database result lists or objects of this selector to be attached with other database result lists after execution. This method does not need to be called directly.
jbe@23 651
jbe@23 652 --]]--
jbe/bsw@0 653 function selector_prototype:attach(mode, data2, field1, field2, ref1, ref2)
jbe/bsw@0 654 self._attach = {
jbe/bsw@0 655 mode = mode,
jbe/bsw@0 656 data2 = data2,
jbe/bsw@0 657 field1 = field1,
jbe/bsw@0 658 field2 = field2,
jbe/bsw@0 659 ref1 = ref1,
jbe/bsw@0 660 ref2 = ref2
jbe/bsw@0 661 }
jbe/bsw@0 662 return self
jbe/bsw@0 663 end
jbe@23 664 --//--
jbe/bsw@0 665
jbe/bsw@0 666 function selector_metatable:__tostring()
jbe/bsw@0 667 local parts = {sep = " "}
jbe@39 668 if #self._with > 0 then
jbe@39 669 add(parts, {"WITH RECURSIVE $", self._with})
jbe@39 670 end
jbe/bsw@0 671 add(parts, "SELECT")
jbe/bsw@0 672 if self._distinct then
jbe/bsw@0 673 add(parts, "DISTINCT")
jbe/bsw@0 674 elseif #self._distinct_on > 0 then
jbe/bsw@0 675 add(parts, {"DISTINCT ON ($)", self._distinct_on})
jbe/bsw@0 676 end
jbe/bsw@0 677 add(parts, {"$", self._fields})
jbe/bsw@0 678 if #self._from > 0 then
jbe/bsw@0 679 add(parts, {"FROM $", self._from})
jbe/bsw@0 680 end
jbe/bsw@0 681 if #self._mode == "empty_list" then
jbe/bsw@0 682 add(parts, "WHERE FALSE")
jbe/bsw@0 683 elseif #self._where > 0 then
jbe/bsw@4 684 add(parts, {"WHERE ($)", self._where})
jbe/bsw@0 685 end
jbe/bsw@0 686 if #self._group_by > 0 then
jbe/bsw@0 687 add(parts, {"GROUP BY $", self._group_by})
jbe/bsw@0 688 end
jbe/bsw@0 689 if #self._having > 0 then
jbe/bsw@4 690 add(parts, {"HAVING ($)", self._having})
jbe/bsw@0 691 end
jbe/bsw@0 692 for i, v in ipairs(self._combine) do
jbe/bsw@0 693 add(parts, v)
jbe/bsw@0 694 end
jbe/bsw@0 695 if #self._order_by > 0 then
jbe/bsw@0 696 add(parts, {"ORDER BY $", self._order_by})
jbe/bsw@0 697 end
jbe/bsw@0 698 if self._mode == "empty_list" then
jbe/bsw@0 699 add(parts, "LIMIT 0")
jbe/bsw@0 700 elseif self._mode ~= "list" then
jbe/bsw@0 701 add(parts, "LIMIT 1")
jbe/bsw@0 702 elseif self._limit then
jbe/bsw@0 703 add(parts, "LIMIT " .. self._limit)
jbe/bsw@0 704 end
jbe/bsw@0 705 if self._offset then
jbe/bsw@0 706 add(parts, "OFFSET " .. self._offset)
jbe/bsw@0 707 end
jbe/bsw@4 708 if self._write_lock.all then
jbe/bsw@4 709 add(parts, "FOR UPDATE")
jbe/bsw@4 710 else
jbe/bsw@4 711 if self._read_lock.all then
jbe/bsw@4 712 add(parts, "FOR SHARE")
jbe/bsw@4 713 elseif #self._read_lock > 0 then
jbe/bsw@4 714 add(parts, {"FOR SHARE OF $", self._read_lock})
jbe/bsw@4 715 end
jbe/bsw@4 716 if #self._write_lock > 0 then
jbe/bsw@4 717 add(parts, {"FOR UPDATE OF $", self._write_lock})
jbe/bsw@4 718 end
jbe/bsw@4 719 end
jbe/bsw@0 720 return self._db_conn:assemble_command{"$", parts}
jbe/bsw@0 721 end
jbe/bsw@0 722
jbe@23 723 --[[--
jbe@23 724 db_error, -- database error object, or nil in case of success
jbe@23 725 result = -- database result list or object
jbe@23 726 <db_selector>:try_exec()
jbe@23 727
jbe@23 728 This method executes the selector on its database. First return value is an error object or nil in case of success. Second return value is the result list or object.
jbe@23 729
jbe@23 730 --]]--
jbe/bsw@0 731 function selector_prototype:try_exec()
jbe/bsw@0 732 if self._mode == "empty_list" then
jbe/bsw@0 733 if self._class then
jbe/bsw@0 734 return nil, self._class:create_list()
jbe/bsw@0 735 else
jbe/bsw@0 736 return nil, self._db_conn:create_list()
jbe/bsw@0 737 end
jbe/bsw@0 738 end
jbe/bsw@0 739 local db_error, db_result = self._db_conn:try_query(self, self._mode)
jbe/bsw@0 740 if db_error then
jbe/bsw@0 741 return db_error
jbe/bsw@0 742 elseif db_result then
jbe/bsw@0 743 if self._class then set_class(db_result, self._class) end
jbe/bsw@0 744 if self._attach then
jbe/bsw@0 745 attach(
jbe/bsw@0 746 self._attach.mode,
jbe/bsw@0 747 db_result,
jbe/bsw@0 748 self._attach.data2,
jbe/bsw@0 749 self._attach.field1,
jbe/bsw@0 750 self._attach.field2,
jbe/bsw@0 751 self._attach.ref1,
jbe/bsw@0 752 self._attach.ref2
jbe/bsw@0 753 )
jbe/bsw@0 754 end
jbe/bsw@0 755 return nil, db_result
jbe/bsw@0 756 else
jbe/bsw@0 757 return nil
jbe/bsw@0 758 end
jbe/bsw@0 759 end
jbe@23 760 --//--
jbe/bsw@0 761
jbe@23 762 --[[--
jbe@23 763 result = -- database result list or object
jbe@23 764 <db_selector>:exec()
jbe@23 765
jbe@23 766 This method executes the selector on its database. The result list or object is returned on success, otherwise an error is thrown.
jbe@23 767
jbe@23 768 --]]--
jbe/bsw@0 769 function selector_prototype:exec()
jbe/bsw@0 770 local db_error, result = self:try_exec()
jbe/bsw@0 771 if db_error then
jbe/bsw@0 772 db_error:escalate()
jbe/bsw@0 773 else
jbe/bsw@0 774 return result
jbe/bsw@0 775 end
jbe/bsw@0 776 end
jbe@23 777 --//--
jbe/bsw@0 778
jbe@23 779 --[[--
jbe@23 780 count = -- number of rows returned
jbe@23 781 <db_selector>:count()
jbe@23 782
jbe@23 783 This function wraps the given selector inside a subquery to count the number of rows returned by the database. NOTE: The result is cached inside the selector, thus the selector should NOT be modified afterwards.
jbe@23 784
jbe@23 785 --]]--
jbe/bsw@4 786 function selector_prototype:count()
jbe/bsw@4 787 if not self._count then
jbe/bsw@4 788 local count_selector = self:get_db_conn():new_selector()
jbe/bsw@4 789 count_selector:add_field('count(1)')
jbe/bsw@4 790 count_selector:add_from(self)
jbe/bsw@4 791 count_selector:single_object_mode()
jbe/bsw@4 792 self._count = count_selector:exec().count
jbe/bsw@4 793 end
jbe/bsw@4 794 return self._count
jbe/bsw@4 795 end
jbe@23 796 --//--
jbe/bsw@4 797
jbe/bsw@0 798
jbe/bsw@0 799
jbe/bsw@0 800 -----------------
jbe/bsw@0 801 -- attachments --
jbe/bsw@0 802 -----------------
jbe/bsw@0 803
jbe/bsw@0 804 local function attach_key(row, fields)
jbe/bsw@0 805 local t = type(fields)
jbe/bsw@0 806 if t == "string" then
jbe/bsw@0 807 return tostring(row[fields])
jbe/bsw@0 808 elseif t == "table" then
jbe/bsw@0 809 local r = {}
jbe/bsw@0 810 for idx, field in ipairs(fields) do
jbe/bsw@0 811 r[idx] = string.format("%q", row[field])
jbe/bsw@0 812 end
jbe/bsw@0 813 return table.concat(r)
jbe/bsw@0 814 else
jbe/bsw@0 815 error("Field information for 'mondelefant.attach' is neither a string nor a table.")
jbe/bsw@0 816 end
jbe/bsw@0 817 end
jbe/bsw@0 818
jbe@23 819 --[[--
jbe@23 820 mondelefant.attach(
jbe@23 821 mode, -- attachment type: "11" one to one, "1m" one to many, "m1" many to one
jbe@23 822 data1, -- first database result list or object
jbe@23 823 data2, -- second database result list or object
jbe@23 824 key1, -- field name(s) in first result list or object used for attaching
jbe@23 825 key2, -- field name(s) in second result list or object used for attaching
jbe@23 826 ref1, -- name of reference field to be set in first database result list or object
jbe@23 827 ref2 -- name of reference field to be set in second database result list or object
jbe@23 828 )
jbe@23 829
jbe@23 830 This function attaches database result lists/objects with each other. It does not need to be called directly.
jbe@23 831
jbe@23 832 --]]--
jbe/bsw@0 833 function attach(mode, data1, data2, key1, key2, ref1, ref2)
jbe/bsw@0 834 local many1, many2
jbe/bsw@0 835 if mode == "11" then
jbe/bsw@0 836 many1 = false
jbe/bsw@0 837 many2 = false
jbe/bsw@0 838 elseif mode == "1m" then
jbe/bsw@0 839 many1 = false
jbe/bsw@0 840 many2 = true
jbe/bsw@0 841 elseif mode == "m1" then
jbe/bsw@0 842 many1 = true
jbe/bsw@0 843 many2 = false
jbe/bsw@0 844 elseif mode == "mm" then
jbe/bsw@0 845 many1 = true
jbe/bsw@0 846 many2 = true
jbe/bsw@0 847 else
jbe/bsw@0 848 error("Unknown mode specified for 'mondelefant.attach'.")
jbe/bsw@0 849 end
jbe/bsw@0 850 local list1, list2
jbe/bsw@0 851 if data1._type == "object" then
jbe/bsw@0 852 list1 = { data1 }
jbe/bsw@0 853 elseif data1._type == "list" then
jbe/bsw@0 854 list1 = data1
jbe/bsw@0 855 else
jbe/bsw@0 856 error("First result data given to 'mondelefant.attach' is invalid.")
jbe/bsw@0 857 end
jbe/bsw@0 858 if data2._type == "object" then
jbe/bsw@0 859 list2 = { data2 }
jbe/bsw@0 860 elseif data2._type == "list" then
jbe/bsw@0 861 list2 = data2
jbe/bsw@0 862 else
jbe/bsw@0 863 error("Second result data given to 'mondelefant.attach' is invalid.")
jbe/bsw@0 864 end
jbe/bsw@0 865 local hash1 = {}
jbe/bsw@0 866 local hash2 = {}
jbe/bsw@0 867 if ref2 then
jbe/bsw@0 868 for i, row in ipairs(list1) do
jbe/bsw@0 869 local key = attach_key(row, key1)
jbe/bsw@0 870 local list = hash1[key]
jbe/bsw@0 871 if not list then list = {}; hash1[key] = list end
jbe/bsw@0 872 list[#list + 1] = row
jbe/bsw@0 873 end
jbe/bsw@0 874 end
jbe/bsw@0 875 if ref1 then
jbe/bsw@0 876 for i, row in ipairs(list2) do
jbe/bsw@0 877 local key = attach_key(row, key2)
jbe/bsw@0 878 local list = hash2[key]
jbe/bsw@0 879 if not list then list = {}; hash2[key] = list end
jbe/bsw@0 880 list[#list + 1] = row
jbe/bsw@0 881 end
jbe/bsw@0 882 for i, row in ipairs(list1) do
jbe/bsw@0 883 local key = attach_key(row, key1)
jbe/bsw@0 884 local matching_rows = hash2[key]
jbe/bsw@0 885 if many2 then
jbe/bsw@0 886 local list = data2._connection:create_list(matching_rows)
jbe/bsw@0 887 list._class = data2._class
jbe/bsw@0 888 row._ref[ref1] = list
jbe/bsw@0 889 elseif matching_rows and #matching_rows == 1 then
jbe/bsw@0 890 row._ref[ref1] = matching_rows[1]
jbe/bsw@0 891 else
jbe/bsw@0 892 row._ref[ref1] = false
jbe/bsw@0 893 end
jbe/bsw@0 894 end
jbe/bsw@0 895 end
jbe/bsw@0 896 if ref2 then
jbe/bsw@0 897 for i, row in ipairs(list2) do
jbe/bsw@0 898 local key = attach_key(row, key2)
jbe/bsw@0 899 local matching_rows = hash1[key]
jbe/bsw@0 900 if many1 then
jbe/bsw@0 901 local list = data1._connection:create_list(matching_rows)
jbe/bsw@0 902 list._class = data1._class
jbe/bsw@0 903 row._ref[ref2] = list
jbe/bsw@0 904 elseif matching_rows and #matching_rows == 1 then
jbe/bsw@0 905 row._ref[ref2] = matching_rows[1]
jbe/bsw@0 906 else
jbe/bsw@0 907 row._ref[ref2] = false
jbe/bsw@0 908 end
jbe/bsw@0 909 end
jbe/bsw@0 910 end
jbe/bsw@0 911 end
jbe@23 912 --//--
jbe/bsw@0 913
jbe/bsw@0 914
jbe/bsw@0 915
jbe/bsw@0 916 ------------------
jbe/bsw@0 917 -- model system --
jbe/bsw@0 918 ------------------
jbe/bsw@0 919
jbe@23 920 --[[--
jbe@23 921 <db_class>.primary_key
jbe@23 922
jbe@23 923 Primary key of a database class (model). Defaults to "id".
jbe@23 924
jbe@23 925 --]]--
jbe/bsw@0 926 class_prototype.primary_key = "id"
jbe@23 927 --//--
jbe/bsw@0 928
jbe@23 929 --[[--
jbe@23 930 db_handle = -- database connection handle used by this class
jbe@23 931 <db_class>:get_db_conn()
jbe@23 932
jbe@23 933 By implementing this method for a particular model or overwriting it in the default prototype "mondelefant.class_prototype", classes are connected with a particular database. This method needs to return a database connection handle. If it is not overwritten, an error is thrown, when invoking this method.
jbe@23 934
jbe@23 935 --]]--
jbe/bsw@0 936 function class_prototype:get_db_conn()
jbe/bsw@0 937 error(
jbe/bsw@0 938 "Method mondelefant class(_prototype):get_db_conn() " ..
jbe/bsw@0 939 "has to be implemented."
jbe/bsw@0 940 )
jbe/bsw@0 941 end
jbe@23 942 --//--
jbe/bsw@0 943
jbe@23 944 --[[--
jbe@23 945 string = -- string of form '"schemaname"."tablename"' or '"tablename"'
jbe@23 946 <db_class>:get_qualified_table()
jbe@23 947
jbe@23 948 This method returns a string with the (double quoted) qualified table name used to store objects of this class.
jbe@23 949
jbe@23 950 --]]--
jbe/bsw@0 951 function class_prototype:get_qualified_table()
jbe/bsw@0 952 if not self.table then error "Table unknown." end
jbe/bsw@0 953 if self.schema then
jbe/bsw@0 954 return '"' .. self.schema .. '"."' .. self.table .. '"'
jbe/bsw@0 955 else
jbe/bsw@0 956 return '"' .. self.table .. '"'
jbe/bsw@0 957 end
jbe/bsw@0 958 end
jbe@23 959 --]]--
jbe/bsw@0 960
jbe@23 961 --[[--
jbe@23 962 string = -- single quoted string of form "'schemaname.tablename'" or "'tablename'"
jbe@23 963 <db_class>:get_qualified_table_literal()
jbe@23 964
jbe@23 965 This method returns a string with an SQL literal representing the given table. It causes ambiguities when the table name contains a dot (".") character.
jbe@23 966
jbe@23 967 --]]--
jbe/bsw@0 968 function class_prototype:get_qualified_table_literal()
jbe/bsw@0 969 if not self.table then error "Table unknown." end
jbe/bsw@0 970 if self.schema then
jbe/bsw@0 971 return self.schema .. '.' .. self.table
jbe/bsw@0 972 else
jbe/bsw@0 973 return self.table
jbe/bsw@0 974 end
jbe/bsw@0 975 end
jbe@23 976 --//--
jbe/bsw@0 977
jbe@23 978 --[[--
jbe@23 979 list = -- list of column names of primary key
jbe@23 980 <db_class>:get_primary_key_list()
jbe@23 981
jbe@23 982 This method returns a list of column names of the primary key.
jbe@23 983
jbe@23 984 --]]--
jbe/bsw@0 985 function class_prototype:get_primary_key_list()
jbe/bsw@0 986 local primary_key = self.primary_key
jbe/bsw@0 987 if type(primary_key) == "string" then
jbe/bsw@0 988 return {primary_key}
jbe/bsw@0 989 else
jbe/bsw@0 990 return primary_key
jbe/bsw@0 991 end
jbe/bsw@0 992 end
jbe@23 993 --//--
jbe/bsw@0 994
jbe@23 995 --[[--
jbe@23 996 columns = -- list of columns
jbe@23 997 <db_class>:get_columns()
jbe@23 998
jbe@23 999 This method returns a list of column names of the table used for the class.
jbe@23 1000
jbe@23 1001 --]]--
jbe/bsw@0 1002 function class_prototype:get_columns()
jbe/bsw@0 1003 if self._columns then
jbe/bsw@0 1004 return self._columns
jbe/bsw@0 1005 end
jbe/bsw@0 1006 local selector = self:get_db_conn():new_selector()
jbe/bsw@0 1007 selector:set_class(self)
jbe/bsw@0 1008 selector:from(self:get_qualified_table())
jbe/bsw@0 1009 selector:add_field("*")
jbe/bsw@0 1010 selector:add_where("FALSE")
jbe/bsw@0 1011 local db_result = selector:exec()
jbe/bsw@0 1012 local connection = db_result._connection
jbe/bsw@0 1013 local columns = {}
jbe/bsw@0 1014 for idx, info in ipairs(db_result._column_info) do
jbe/bsw@0 1015 local key = info.field_name
jbe/bsw@0 1016 local value = {
jbe/bsw@0 1017 name = key,
jbe/bsw@0 1018 type = connection.type_mappings[info.type]
jbe/bsw@0 1019 }
jbe/bsw@0 1020 columns[key] = value
jbe/bsw@0 1021 table.insert(columns, value)
jbe/bsw@0 1022 end
jbe/bsw@0 1023 self._columns = columns
jbe/bsw@0 1024 return columns
jbe/bsw@0 1025 end
jbe@25 1026 --//--
jbe/bsw@0 1027
jbe@23 1028 --[[--
jbe@23 1029 selector = -- new selector for selecting objects of this class
jbe@23 1030 <db_class>:new_selector(
jbe@23 1031 db_conn -- optional(!) database connection handle, defaults to result of :get_db_conn()
jbe@23 1032 )
jbe@23 1033
jbe@23 1034 This method creates a new selector for selecting objects of the class.
jbe@23 1035
jbe@23 1036 --]]--
jbe/bsw@0 1037 function class_prototype:new_selector(db_conn)
jbe/bsw@0 1038 local selector = (db_conn or self:get_db_conn()):new_selector()
jbe/bsw@0 1039 selector:set_class(self)
jbe/bsw@0 1040 selector:from(self:get_qualified_table())
jbe/bsw@0 1041 selector:add_field(self:get_qualified_table() .. ".*")
jbe/bsw@0 1042 return selector
jbe/bsw@0 1043 end
jbe@23 1044 --//--
jbe/bsw@0 1045
jbe@23 1046 --[[--
jbe@23 1047 db_list = -- database result being an empty list
jbe@23 1048 <db_class>:create_list()
jbe@23 1049
jbe@23 1050 Creates an empty database result representing a list of objects of the given class.
jbe@23 1051
jbe@23 1052 --]]--
jbe/bsw@0 1053 function class_prototype:create_list()
jbe/bsw@0 1054 local list = self:get_db_conn():create_list()
jbe/bsw@0 1055 list._class = self
jbe/bsw@0 1056 return list
jbe/bsw@0 1057 end
jbe@23 1058 --//--
jbe/bsw@0 1059
jbe@23 1060 --[[--
jbe@23 1061 db_object = -- database object (instance of model)
jbe@23 1062 <db_class>:new()
jbe@23 1063
jbe@23 1064 Creates a new object of the given class.
jbe@23 1065
jbe@23 1066 --]]--
jbe/bsw@0 1067 function class_prototype:new()
jbe/bsw@0 1068 local object = self:get_db_conn():create_object()
jbe/bsw@0 1069 object._class = self
jbe/bsw@0 1070 object._new = true
jbe/bsw@0 1071 return object
jbe/bsw@0 1072 end
jbe@23 1073 --//--
jbe/bsw@0 1074
jbe@23 1075 --[[--
jbe@23 1076 db_error = -- database error object, or nil in case of success
jbe@23 1077 <db_object>:try_save()
jbe@23 1078
jbe@23 1079 This method saves changes to an object in the database. Returns nil on success, otherwise an error object is returned.
jbe@23 1080
jbe@23 1081 --]]--
jbe/bsw@0 1082 function class_prototype.object:try_save()
jbe/bsw@0 1083 if not self._class then
jbe/bsw@0 1084 error("Cannot save object: No class information available.")
jbe/bsw@0 1085 end
jbe/bsw@0 1086 local primary_key = self._class:get_primary_key_list()
jbe/bsw@0 1087 local primary_key_sql = { sep = ", " }
jbe/bsw@0 1088 for idx, value in ipairs(primary_key) do
jbe/bsw@0 1089 primary_key_sql[idx] = '"' .. value .. '"'
jbe/bsw@0 1090 end
jbe/bsw@0 1091 if self._new then
jbe/bsw@0 1092 local fields = {sep = ", "}
jbe/bsw@0 1093 local values = {sep = ", "}
jbe/bsw@0 1094 for key, dummy in pairs(self._dirty or {}) do
jbe/bsw@0 1095 add(fields, {'"$"', {key}})
jbe/bsw@0 1096 add(values, {'?', self[key]})
jbe/bsw@0 1097 end
jbe/bsw@0 1098 if compat_returning then -- compatibility for PostgreSQL 8.1
jbe/bsw@0 1099 local db_error, db_result1, db_result2 = self._connection:try_query(
jbe/bsw@0 1100 {
jbe/bsw@0 1101 'INSERT INTO $ ($) VALUES ($)',
jbe/bsw@0 1102 {self._class:get_qualified_table()},
jbe/bsw@0 1103 fields,
jbe/bsw@0 1104 values,
jbe/bsw@0 1105 primary_key_sql
jbe/bsw@0 1106 },
jbe/bsw@0 1107 "list",
jbe/bsw@0 1108 {
jbe/bsw@0 1109 'SELECT currval(?)',
jbe/bsw@0 1110 self._class.table .. '_id_seq'
jbe/bsw@0 1111 },
jbe/bsw@0 1112 "object"
jbe/bsw@0 1113 )
jbe/bsw@0 1114 if db_error then
jbe/bsw@0 1115 return db_error
jbe/bsw@0 1116 end
jbe/bsw@0 1117 self.id = db_result2.id
jbe/bsw@0 1118 else
jbe@51 1119 local db_error, db_result
jbe@51 1120 if #fields == 0 then
jbe@51 1121 db_error, db_result = self._connection:try_query(
jbe@51 1122 {
jbe@51 1123 'INSERT INTO $ DEFAULT VALUES RETURNING ($)',
jbe@51 1124 {self._class:get_qualified_table()},
jbe@51 1125 primary_key_sql
jbe@51 1126 },
jbe@51 1127 "object"
jbe@51 1128 )
jbe@51 1129 else
jbe@51 1130 db_error, db_result = self._connection:try_query(
jbe@51 1131 {
jbe@51 1132 'INSERT INTO $ ($) VALUES ($) RETURNING ($)',
jbe@51 1133 {self._class:get_qualified_table()},
jbe@51 1134 fields,
jbe@51 1135 values,
jbe@51 1136 primary_key_sql
jbe@51 1137 },
jbe@51 1138 "object"
jbe@51 1139 )
jbe@51 1140 end
jbe/bsw@0 1141 if db_error then
jbe/bsw@0 1142 return db_error
jbe/bsw@0 1143 end
jbe/bsw@0 1144 for idx, value in ipairs(primary_key) do
jbe/bsw@0 1145 self[value] = db_result[value]
jbe/bsw@0 1146 end
jbe/bsw@0 1147 end
jbe/bsw@0 1148 self._new = false
jbe/bsw@0 1149 else
jbe/bsw@0 1150 local command_sets = {sep = ", "}
jbe/bsw@0 1151 for key, dummy in pairs(self._dirty or {}) do
jbe/bsw@0 1152 add(command_sets, {'"$" = ?', {key}, self[key]})
jbe/bsw@0 1153 end
jbe/bsw@0 1154 if #command_sets >= 1 then
jbe/bsw@0 1155 local primary_key_compare = {sep = " AND "}
jbe/bsw@0 1156 for idx, value in ipairs(primary_key) do
jbe/bsw@0 1157 primary_key_compare[idx] = {
jbe/bsw@0 1158 "$ = ?",
jbe/bsw@0 1159 {'"' .. value .. '"'},
jbe/bsw@0 1160 self[value]
jbe/bsw@0 1161 }
jbe/bsw@0 1162 end
jbe/bsw@0 1163 local db_error = self._connection:try_query{
jbe/bsw@0 1164 'UPDATE $ SET $ WHERE $',
jbe/bsw@0 1165 {self._class:get_qualified_table()},
jbe/bsw@0 1166 command_sets,
jbe/bsw@0 1167 primary_key_compare
jbe/bsw@0 1168 }
jbe/bsw@0 1169 if db_error then
jbe/bsw@0 1170 return db_error
jbe/bsw@0 1171 end
jbe/bsw@0 1172 end
jbe/bsw@0 1173 end
jbe/bsw@0 1174 return nil
jbe/bsw@0 1175 end
jbe@23 1176 --//--
jbe/bsw@0 1177
jbe@23 1178 --[[--
jbe@23 1179 <db_object>:save()
jbe@23 1180
jbe@23 1181 This method saves changes to an object in the database. Throws error, unless successful.
jbe@23 1182
jbe@23 1183 --]]--
jbe/bsw@0 1184 function class_prototype.object:save()
jbe/bsw@0 1185 local db_error = self:try_save()
jbe/bsw@0 1186 if db_error then
jbe/bsw@0 1187 db_error:escalate()
jbe/bsw@0 1188 end
jbe/bsw@0 1189 return self
jbe/bsw@0 1190 end
jbe@23 1191 --//--
jbe/bsw@0 1192
jbe@23 1193 --[[--
jbe@23 1194 db_error = -- database error object, or nil in case of success
jbe@23 1195 <db_object>:try_destroy()
jbe@23 1196
jbe@23 1197 This method deletes an object in the database. Returns nil on success, otherwise an error object is returned.
jbe@23 1198
jbe@23 1199 --]]--
jbe/bsw@0 1200 function class_prototype.object:try_destroy()
jbe/bsw@0 1201 if not self._class then
jbe/bsw@0 1202 error("Cannot destroy object: No class information available.")
jbe/bsw@0 1203 end
jbe/bsw@0 1204 local primary_key = self._class:get_primary_key_list()
jbe/bsw@0 1205 local primary_key_compare = {sep = " AND "}
jbe/bsw@0 1206 for idx, value in ipairs(primary_key) do
jbe/bsw@0 1207 primary_key_compare[idx] = {
jbe/bsw@0 1208 "$ = ?",
jbe/bsw@0 1209 {'"' .. value .. '"'},
jbe/bsw@0 1210 self[value]
jbe/bsw@0 1211 }
jbe/bsw@0 1212 end
jbe/bsw@0 1213 return self._connection:try_query{
jbe/bsw@0 1214 'DELETE FROM $ WHERE $',
jbe/bsw@0 1215 {self._class:get_qualified_table()},
jbe/bsw@0 1216 primary_key_compare
jbe/bsw@0 1217 }
jbe/bsw@0 1218 end
jbe@23 1219 --//--
jbe/bsw@0 1220
jbe@23 1221 --[[--
jbe@23 1222 <db_object>:destroy()
jbe@23 1223
jbe@23 1224 This method deletes an object in the database. Throws error, unless successful.
jbe@23 1225
jbe@23 1226 --]]--
jbe/bsw@0 1227 function class_prototype.object:destroy()
jbe/bsw@0 1228 local db_error = self:try_destroy()
jbe/bsw@0 1229 if db_error then
jbe/bsw@0 1230 db_error:escalate()
jbe/bsw@0 1231 end
jbe/bsw@0 1232 return self
jbe/bsw@0 1233 end
jbe@23 1234 --//--
jbe/bsw@0 1235
jbe@23 1236 --[[--
jbe@23 1237 db_selector =
jbe@23 1238 <db_list>:get_reference_selector(
jbe@23 1239 ref_name, -- name of reference (e.g. "children")
jbe@23 1240 options, -- table options passed to the reference loader (e.g. { order = ... })
jbe@23 1241 ref_alias, -- optional alias for the reference (e.g. "ordered_children")
jbe@23 1242 back_ref_alias -- back reference name (e.g. "parent")
jbe@23 1243 )
jbe@23 1244
jbe@23 1245 This method returns a special selector for selecting referenced objects. It is prepared in a way, that on execution of the selector, all returned objects are attached with the objects of the existent list. The "ref" and "back_ref" arguments passed to "add_reference" are used for the attachment, unless aliases are given with "ref_alias" and "back_ref_alias". If "options" are set, these options are passed to the reference loader. The default reference loader supports only one option named "order". If "order" is set to nil, the default order is used, if "order" is set to false, no ORDER BY statment is included in the selector, otherwise the given expression is used for ordering.
jbe@23 1246
jbe@23 1247 This method is not only available for database result lists but also for database result objects.
jbe@23 1248
jbe@23 1249 --]]--
jbe/bsw@0 1250 function class_prototype.list:get_reference_selector(
jbe/bsw@0 1251 ref_name, options, ref_alias, back_ref_alias
jbe/bsw@0 1252 )
jbe/bsw@0 1253 local ref_info = self._class.references[ref_name]
jbe/bsw@0 1254 if not ref_info then
jbe/bsw@0 1255 error('Reference with name "' .. ref_name .. '" not found.')
jbe/bsw@0 1256 end
jbe/bsw@0 1257 local selector = ref_info.selector_generator(self, options or {})
jbe/bsw@0 1258 local mode = ref_info.mode
jbe/bsw@0 1259 if mode == "mm" or mode == "1m" then
jbe/bsw@0 1260 mode = "m1"
jbe/bsw@0 1261 elseif mode == "m1" then
jbe/bsw@0 1262 mode = "1m"
jbe/bsw@0 1263 end
jbe/bsw@0 1264 local ref_alias = ref_alias
jbe/bsw@0 1265 if ref_alias == false then
jbe/bsw@0 1266 ref_alias = nil
jbe/bsw@0 1267 elseif ref_alias == nil then
jbe/bsw@0 1268 ref_alias = ref_name
jbe/bsw@0 1269 end
jbe/bsw@0 1270 local back_ref_alias
jbe/bsw@0 1271 if back_ref_alias == false then
jbe/bsw@0 1272 back_ref_alias = nil
jbe/bsw@0 1273 elseif back_ref_alias == nil then
jbe/bsw@0 1274 back_ref_alias = ref_info.back_ref
jbe/bsw@0 1275 end
jbe/bsw@0 1276 selector:attach(
jbe/bsw@0 1277 mode,
jbe/bsw@0 1278 self,
jbe/bsw@0 1279 ref_info.that_key, ref_info.this_key,
jbe/bsw@0 1280 back_ref_alias or ref_info.back_ref, ref_alias or ref_name
jbe/bsw@0 1281 )
jbe/bsw@0 1282 return selector
jbe/bsw@0 1283 end
jbe@23 1284 --//--
jbe/bsw@0 1285
jbe@23 1286 --[[--
jbe@23 1287 db_list_or_object =
jbe@23 1288 <db_list>:load(
jbe@23 1289 ref_name, -- name of reference (e.g. "children")
jbe@23 1290 options, -- table options passed to the reference loader (e.g. { order = ... })
jbe@23 1291 ref_alias, -- optional alias for the reference (e.g. "ordered_children")
jbe@23 1292 back_ref_alias -- back reference name (e.g. "parent")
jbe@23 1293 )
jbe@23 1294
jbe@23 1295 This method loads referenced objects and attaches them with the objects of the existent list. The "ref" and "back_ref" arguments passed to "add_reference" are used for the attachment, unless aliases are given with "ref_alias" and "back_ref_alias". If "options" are set, these options are passed to the reference loader. The default reference loader supports only one option named "order". If "order" is set to nil, the default order is used, if "order" is set to false, no ORDER BY statment is included in the selector, otherwise the given expression is used for ordering.
jbe@23 1296
jbe@23 1297 This method is not only available for database result lists but also for database result objects.
jbe@23 1298
jbe@23 1299 --]]--
jbe/bsw@0 1300 function class_prototype.list.load(...)
jbe/bsw@0 1301 return class_prototype.list.get_reference_selector(...):exec()
jbe/bsw@0 1302 end
jbe@23 1303 --//--
jbe/bsw@0 1304
jbe@23 1305 --[[--
jbe@23 1306 db_object =
jbe@23 1307 <db_object>:get_reference_selector(
jbe@23 1308 ref_name, -- name of reference (e.g. "children")
jbe@23 1309 options, -- table options passed to the reference loader (e.g. { order = ... })
jbe@23 1310 ref_alias, -- optional alias for the reference (e.g. "ordered_children")
jbe@23 1311 back_ref_alias -- back reference name (e.g. "parent")
jbe@23 1312 )
jbe@23 1313
jbe@23 1314 This method returns a special selector for selecting referenced objects. It is prepared in a way, that on execution of the selector, all returned objects are attached with the objects of the existent list. The "ref" and "back_ref" arguments passed to "add_reference" are used for the attachment, unless aliases are given with "ref_alias" and "back_ref_alias". If "options" are set, these options are passed to the reference loader. The default reference loader supports only one option named "order". If "order" is set to nil, the default order is used, if "order" is set to false, no ORDER BY statment is included in the selector, otherwise the given expression is used for ordering.
jbe@23 1315
jbe@23 1316 This method is not only available for database result objects but also for database result lists.
jbe@23 1317
jbe@23 1318 --]]--
jbe/bsw@0 1319 function class_prototype.object:get_reference_selector(...)
jbe/bsw@0 1320 local list = self._class:create_list()
jbe/bsw@0 1321 list[1] = self
jbe/bsw@0 1322 return list:get_reference_selector(...)
jbe/bsw@0 1323 end
jbe@23 1324 --//--
jbe/bsw@0 1325
jbe@23 1326 --[[--
jbe@23 1327 db_list_or_object =
jbe@23 1328 <db_object>:load(
jbe@23 1329 ref_name, -- name of reference (e.g. "children")
jbe@23 1330 options, -- table options passed to the reference loader (e.g. { order = ... })
jbe@23 1331 ref_alias, -- optional alias for the reference (e.g. "ordered_children")
jbe@23 1332 back_ref_alias -- back reference name (e.g. "parent")
jbe@23 1333 )
jbe@23 1334
jbe@23 1335 This method loads referenced objects and attaches them with the objects of the existent list. The "ref" and "back_ref" arguments passed to "add_reference" are used for the attachment, unless aliases are given with "ref_alias" and "back_ref_alias". If "options" are set, these options are passed to the reference loader. The default reference loader supports only one option named "order". If "order" is set to nil, the default order is used, if "order" is set to false, no ORDER BY statment is included in the selector, otherwise the given expression is used for ordering.
jbe@23 1336
jbe@23 1337 This method is not only available for database result objects but also for database result lists. Calling this method for objects is unneccessary, unless additional options and/or an alias is used.
jbe@23 1338
jbe@23 1339 --]]--
jbe/bsw@0 1340 function class_prototype.object.load(...)
jbe/bsw@0 1341 return class_prototype.object.get_reference_selector(...):exec()
jbe/bsw@0 1342 end
jbe@23 1343 --//--
jbe/bsw@0 1344
jbe@23 1345 --[[--
jbe@23 1346 db_class = -- same class returned
jbe@23 1347 <db_class>:add_reference{
jbe@23 1348 mode = mode, -- "11", "1m", "m1", or "mm" (one/many to one/many)
jbe@23 1349 to = to, -- referenced class (model), optionally as string or function returning the value (avoids autoload)
jbe@23 1350 this_key = this_key, -- name of key in this class (model)
jbe@23 1351 that_key = that_key, -- name of key in the other class (model) ("to" argument)
jbe@23 1352 ref = ref, -- name of reference in this class, referring to the other class
jbe@23 1353 back_ref = back_ref, -- name of reference in other class, referring to this class
jbe@23 1354 default_order = default_order, -- expression as passed to "assemble_command" used for sorting
jbe@23 1355 selector_generator = selector_generator, -- alternative function used as selector generator (use only, when you know what you are doing)
jbe@23 1356 connected_by_table = connected_by_table, -- connecting table used for many to many relations
jbe@23 1357 connected_by_this_key = connected_by_this_key, -- key in connecting table referring to "this_key" of this class (model)
jbe@23 1358 connected_by_that_key = connected_by_that_key -- key in connecting table referring to "that_key" in other class (model) ("to" argument)
jbe@23 1359 }
jbe/bsw@0 1360
jbe@23 1361 Denotes a reference from one database class to another database class (model to model relation). There are 4 possible types of references: one-to-one (mode = "11"), one-to-many (mode = "1m"), many-to-one ("m1"), and many-to-many ("mm"). References usually should be defined in both models, which are related to each other, with mirrored mode (i.e. "1m" in one model, and "m1" in the other). One-to-one and one-to-many references may have a "back_ref" setting, which causes that loaded objects of the referenced class, refer back to the originating object. One-to-many and many-to-many references may have a "default_order" setting, which selects the default order for selected objects. When adding a many-to-many reference, the argument "connected_by_table", "connected_by_this_key" and "connected_by_that_key" must be set additionally.
jbe@23 1362
jbe@23 1363 --]]--
jbe/bsw@0 1364 function class_prototype:add_reference(args)
jbe/bsw@0 1365 local selector_generator = args.selector_generator
jbe/bsw@0 1366 local mode = args.mode
jbe/bsw@0 1367 local to = args.to
jbe/bsw@0 1368 local this_key = args.this_key
jbe/bsw@0 1369 local that_key = args.that_key
jbe/bsw@0 1370 local connected_by_table = args.connected_by_table -- TODO: split to table and schema
jbe/bsw@0 1371 local connected_by_this_key = args.connected_by_this_key
jbe/bsw@0 1372 local connected_by_that_key = args.connected_by_that_key
jbe/bsw@0 1373 local ref = args.ref
jbe/bsw@0 1374 local back_ref = args.back_ref
jbe/bsw@0 1375 local default_order = args.default_order
jbe/bsw@0 1376 local model
jbe/bsw@0 1377 local function get_model()
jbe/bsw@0 1378 if not model then
jbe/bsw@0 1379 if type(to) == "string" then
jbe/bsw@0 1380 model = _G
jbe/bsw@0 1381 for path_element in string.gmatch(to, "[^.]+") do
jbe/bsw@0 1382 model = model[path_element]
jbe/bsw@0 1383 end
jbe/bsw@0 1384 elseif type(to) == "function" then
jbe/bsw@0 1385 model = to()
jbe/bsw@0 1386 else
jbe/bsw@0 1387 model = to
jbe/bsw@0 1388 end
jbe/bsw@0 1389 end
jbe/bsw@0 1390 if not model or model == _G then
jbe/bsw@0 1391 error("Could not get model for reference.")
jbe/bsw@0 1392 end
jbe/bsw@0 1393 return model
jbe/bsw@0 1394 end
jbe/bsw@0 1395 self.references[ref] = {
jbe/bsw@0 1396 mode = mode,
jbe/bsw@0 1397 this_key = this_key,
jbe/bsw@0 1398 that_key = connected_by_table and "mm_ref_" or that_key,
jbe/bsw@0 1399 ref = ref,
jbe/bsw@0 1400 back_ref = back_ref,
jbe/bsw@0 1401 selector_generator = selector_generator or function(list, options)
jbe/bsw@0 1402 -- TODO: support tuple keys
jbe/bsw@0 1403 local options = options or {}
jbe/bsw@0 1404 local model = get_model()
jbe/bsw@0 1405 -- TODO: too many records cause PostgreSQL command stack overflow
jbe/bsw@0 1406 local ids = { sep = ", " }
jbe/bsw@0 1407 for i, object in ipairs(list) do
jbe/bsw@0 1408 local id = object[this_key]
jbe/bsw@0 1409 if id ~= nil then
jbe/bsw@0 1410 ids[#ids+1] = {"?", id}
jbe/bsw@0 1411 end
jbe/bsw@0 1412 end
jbe/bsw@0 1413 if #ids == 0 then
jbe/bsw@0 1414 return model:new_selector():empty_list_mode()
jbe/bsw@0 1415 end
jbe/bsw@0 1416 local selector = model:new_selector()
jbe/bsw@0 1417 if connected_by_table then
jbe/bsw@0 1418 selector:join(
jbe/bsw@0 1419 connected_by_table,
jbe/bsw@0 1420 nil,
jbe/bsw@0 1421 {
jbe/bsw@0 1422 '$."$" = $."$"',
jbe/bsw@0 1423 {connected_by_table},
jbe/bsw@0 1424 {connected_by_that_key},
jbe/bsw@0 1425 {model:get_qualified_table()},
jbe/bsw@0 1426 {that_key}
jbe/bsw@0 1427 }
jbe/bsw@0 1428 )
jbe/bsw@0 1429 selector:add_field(
jbe/bsw@0 1430 {
jbe/bsw@0 1431 '$."$"',
jbe/bsw@0 1432 {connected_by_table},
jbe/bsw@0 1433 {connected_by_this_key}
jbe/bsw@0 1434 },
jbe/bsw@0 1435 'mm_ref_'
jbe/bsw@0 1436 )
jbe/bsw@0 1437 selector:add_where{
jbe/bsw@0 1438 '$."$" IN ($)',
jbe/bsw@0 1439 {connected_by_table},
jbe/bsw@0 1440 {connected_by_this_key},
jbe/bsw@0 1441 ids
jbe/bsw@0 1442 }
jbe/bsw@0 1443 else
jbe/bsw@6 1444 selector:add_where{'$."$" IN ($)', {model:get_qualified_table()}, {that_key}, ids}
jbe/bsw@0 1445 end
jbe/bsw@0 1446 if options.order == nil and default_order then
jbe/bsw@0 1447 selector:add_order_by(default_order)
jbe/bsw@0 1448 elseif options.order then
jbe/bsw@0 1449 selector:add_order_by(options.order)
jbe/bsw@0 1450 end
jbe/bsw@0 1451 return selector
jbe/bsw@0 1452 end
jbe/bsw@0 1453 }
jbe/bsw@0 1454 if mode == "m1" or mode == "11" then
jbe/bsw@0 1455 self.foreign_keys[this_key] = ref
jbe/bsw@0 1456 end
jbe/bsw@0 1457 return self
jbe/bsw@0 1458 end
jbe@23 1459 --//--
jbe@23 1460

Impressum / About Us