<% /* $Revision$ $Id$ File: api2.inc Description: Functies voor manipuleren van de modellen Notes: Hier wordt weinig met de 'buitenwereld' gecommuniceerd, dat gebeurt voornamelijk in api2_rest.inc Status: Nog TODO's wegwerken */ %> <% api2 = { form2JSONdata: function _form2JSONdata(model, params, formfields) // Maak een jsondata-object voor gebruik vanuit model_xxx.inc { var jsondata = {id: params.filter.id}; // Form parameters van gewone velden. for (i=0; i SYSDATE)"); if (inc.joinfunction) { var where = inc.joinfunction(params); if (typeof where == "string") wheres.push (where); else { tables = tables.concat (where.tables); wheres.push (where.where); } } else { if (params.orderby) { for (var i = 0; i < params.orderby.length; i++) { var field = inc.model.fields[params.orderby[i]]; if (field) orderbys.push(inc.model.table + "." + field.dbs); } } // In orderbys worden de include primary keys verzameld om te sorteren // We bieden daar geen garantie op maar tijdens testen is deterministisch // gedrag wel fijn. orderbys.push(inc.model.aliasprefix + inc.model.primary); // simpel op joinfield var outer = "(+)"; if ("outertoggle" in inc) { if (params.filter.has_scf_outer && params.filter.scf_outer == "on") outer = ""; else outer = inc.outertoggle.def?"":"(+)"; } wheres.push ( model.table + "." + model.primary + "=" + inc.model.table + "." + inc.model.fields[inc.joinfield].dbs + outer); } } } else __Log("Unknown include '{0}' requested".format(params.include[i])); } } return { withs: withs, selects: selects, tables: tables, wheres: wheres, orderbys: orderbys }; }, // TODO the_key *moet* bestaan. Andere filtervelden negeren we // Bouw een fields object zoals save2db dat verwacht/ kent update_fields: function _update_fields(params, model, jsondata) { var fields = {}; for (var fld in model.fields) { var field = model.fields[fld]; // De key halen we uit de url, die in de JSON negeren we if (fld == "id") continue; if ("sql" in field) continue; if (!(fld in jsondata) && !field.fnval) continue; if (field.readonly) continue; if (field.insertonly && !params.isNew) continue; if (field.fnval) var newval = field.fnval(jsondata); else // simpel var newval = jsondata[fld]; if (field.LOV && newval && typeof newval == "object" && "id" in newval) { // dereference newval = newval.id; } switch (field.typ) { case "key": // De foreign keys action { "id": "5", "name": "afhalen" } if (newval && typeof newval == "object") { if ("id" in newval) { // dereference newval = newval.id; jsondata[fld] = newval; } else if ("name" in newval && field.foreign && typeof field.foreign != 'function') { if (typeof field.foreign == 'string') { field.foreign = foreignKeyTable(field.foreign); } if (field.foreign.desc_is_unique) // Dan mag je die bij saven ook opgeven { field.typ = "sql"; var where = "{0} = {1}".format(field.foreign.desc, safe.quoted_sql(newval.name)); if (typeof field.foreign.desc_is_unique == "string") where += " AND " + field.foreign.desc_is_unique; newval = "(SELECT {0} FROM {1} WHERE {2})".format(field.foreign.key, field.foreign.tbl, where); } } } break; case "date": case "datetime": if (newval === "") newval = null; // LET OP: Een (new Date) gemaakt binnen een plugin is vreemd genoeg geen (instanceof Date) // Waarschijnlijk gebruikt een wsc een ander Date object als (ASP)JScript? if (newval !== null && typeof newval == "object" && !(newval instanceof Date)) newval = new Date(newval); if (newval !== null && !(newval instanceof Date)) { abort_with_warning("Invalid " + field.typ + " (" + model.record_name + "." + fld + "): " + newval); } break; case "float": case "currency": case "number": if (isNaN(newval)) abort_with_warning("Invalid number (" + model.record_name + "." + fld + "): " + newval); break; } if (field.dbs.indexOf(".") >= 0) // complexe foreign key continue; // LET OP: newfield en fields zijn in het formaat wat save2db verwacht/kent // dat lijkt wel op een standaard model.fields object maar is soms een fractie anders // Zo heeft een save2db field geen "label" en is "track" geen boolean maar de label-tekst // LET OP2: save2db werkt eigenlijk met een Array voor fields maar wij hebben een // object met "name": { field.. } wat daar wel omgezet wordt. var newfield = { dbs: field.dbs, typ: field.typ, track: field.track && field.label?field.label:field.track, foreign: field.foreign, val: newval, len: field.len }; fields[fld] = newfield; } return fields; }, // Verwerk de POST en PUT (== insert en update) // Merk op dat het resultaat van deze functie redelijk ongedefinieerd is process_includes: function(params, model, jsondata, the_key) { if (!model.includes) return []; for (var incname in model.includes) { if (incname in jsondata) // i=="visitors" { var inc = model.includes[incname]; if (inc.model && inc.enable_update) // andere includes zijn nog niet bij te werken { // Als je bij een PUT/POST een include in de BODY zet geven we hem automagisch terug params.include = params.include || []; params.include.push(incname); var incmodel = inc.model; var existing_includes = {}; if (!params.isNew) { // Vul existing_includes met bestaande records in de database if ("fntablesql" in incmodel) incmodel.tablesql = incmodel.fntablesql(); var sql = "SELECT " + incmodel.primary + " FROM " + (incmodel.tablesql || incmodel.table) + " WHERE " + incmodel.table + "." + incmodel.fields[inc.joinfield].dbs + "=" + the_key; var oRs = Oracle.Execute(sql); while (!oRs.Eof) { existing_includes[oRs(incmodel.primary).Value] = { found: false }; // vooralsnog niet in json-data gevonden oRs.MoveNext(); } oRs.Close(); } var incdata = jsondata[incname]; // Array zoals via API aangeleverd for (var j=0; j 0) || params.isNew) { delete incdata[j]["id"]; // voor als je bij isNew toch keys had meegegeven incdata[j][inc.joinfield] = the_key; // de parent_key altijd zetten __Log("Nu ga ik een '{0}' toevoegen".format(incname)); incmodel.REST_POST(params, incdata[j], the_key); } else if (inckey in existing_includes) { __Log("Nu ga ik '{0}' {1} updaten".format(incname, inckey)); incmodel.REST_PUT(params, incdata[j], inckey, the_key); existing_includes[inckey].found = true; } } for (oldi in existing_includes) { if (!existing_includes[oldi].found) { incmodel.REST_DELETE(params, oldi); } } } else { //if (inc.func) } } } }, // Geeft de GET terug van een enkel veld sql2jsonval: function _sql2jsonval(oRs, fld, model) { var field = model.fields[fld]; var sqlfieldname = (model.aliasprefix ? api2.sqlfield_alias(model, fld) : field.dbs); if (field.val instanceof Function) var val = field.val(oRs, field, model, sqlfieldname); else if (field.dbs.indexOf(".") < 0) { var val = oRs(sqlfieldname).Value; } else var val = oRs(field.dbs.split(".")[1]).Value; if (field.typ == "check" || field.typ == "check0") { if (field.invert) val = (val==1?0:1); } if (val === null) return val; if (field.typ == "date") val = new Date(val); if (field.typ == "datetime") val = new Date(val); if (field.typ == "time") // In de database ondersteunen we dit niet maar komt voor bij fac_report val = new Date(val); // Wat te doen met lege waarde // action: null // action: {key: null, name: null} // action: {} // of helemaal weglaten? We hebben nu de 1e optie. Dat is zelfdocumenterend // En wat bij een leeg (include) array? Dan kun je ook nog occupations:[] krijgen if (field.foreign || field.foreignsql) { if (field.foreignsql) { var name = oRs(model.aliasprefix + field._foreignname).Value; if (name != null && typeof name == "date" ) name = new Date(name); } else { var name = field.foreign(val); } val = { id: val }; val.name = name; } // if (field.typ == 'check' && !field.LOV) // field.LOV = "0;" + L("lcl_No") + ";1;" + L("lcl_Yes"); if (field.LOV) { var spl = api2.splitLOV(field.LOV); val = { id: val, name: spl[val] }; } if (field.flexmodule) { var flexparam = flexProps(field.flexmodule, -1, null, null, { getFile: val, api2name: null }); if (flexparam.files.length) { var file = flexparam.files[0]; val = { name: file.name, date: file.date, size: file.size, content_url: file.deepurl, digest: file.digest }; } } return val; }, filterLOV: function _splitLOV(LOV, filter) { filter = filter.split(","); var spl = api2.splitLOV(LOV); var result = []; for (var f in filter) result.push(filter[f] + ";" + spl[filter[f]]); return result.join(";"); }, splitLOV: function _splitLOV(LOV, nameprefix) { var splits = LOV.split(";"); if (splits % 2) abort_with_warning("LOV '{0}' mismatch".format(LOV)); var result = {}; for (var i=0; i < splits.length / 2; i++) { var name = splits[i*2]; if (nameprefix) name = nameprefix + name; result[name] = splits[i*2 + 1]; } return result; }, splitLOV2sql: function _splitLOV(LOV) { var spl = api2.splitLOV(LOV); var dual = []; var cnt = 0; for (var l in spl) { cnt ++; dual.push("SELECT " + safe.quoted_sql(l) + ", " + safe.quoted_sql(spl[l]) + ", " + cnt + " FROM DUAL"); } return dual.join(" UNION ALL ") + " ORDER BY 3"; }, splitLOV2select: function _splitLOV(LOV, current, params) { params = params || {}; var spl = api2.splitLOV(LOV); var options = []; for (var l in spl) options.push(""); return "" + options.join("") + ""; }, // ['xxx','yyy','zzz'] ==> "0;xxx;1;yyy;2;zzz" makeLOV: function _makeLOV(arr) { var LOVarr = []; for (var i = 0; i < arr.length; i++) { LOVarr.push(String(i)); LOVarr.push(arr[i]); } return LOVarr.join(";"); }, getTimetable: function() { var timetable = []; for (var t = 0; t < 24*4-1; t++) { // "0;0:00;0.25;0:15;0.5;0:30;0.75;0:45;" enzovoorts timetable.push(t / 4); timetable.push(String(Math.floor(t / 4)) + ":" + padout(15*(t % 4))); } return timetable.join(";"); }, // Geef alle velden van een record terug // ?? Alleen bij includes in gebruik ?? sql2jsonfields: function _sql2jsonfields(params, oRs, model) { var record = {}; for (var fld in model.fields) { if (fld.substring(0,1) == "_") continue; var field = model.fields[fld]; if (field.hidden) continue; var val = api2.sql2jsonval(oRs, fld, model); //waarom was dit aanwezig? //if (field.readonly && !val.id) // continue; record[fld] = val; } if ("post_get" in model) model.post_get(params, record); return record; }, sql2json: function _sql2json(params, sql, model) { var prefuncdata; var prefuncdatainitialized = false; var prefilterfuncdata; if (model.filter && model.filter.prefunc) prefilterfuncdata = model.filter.prefunc(params); var data = []; var oRs = Oracle.Execute(sql, params.errmsg); if (params.errmsg && oRs.friendlyMsg) { var record = {}; record[model.list.columns[0]] = oRs.friendlyMsg; data.push(record); return data; } var lastkey = 0; var record = {}; // Merk op dat onze recordset meer regels kan bevatten dan je zou verwachten // omdat de includes er bij zijn gejoind var total_count = 0; var limit = S("qp_maxrows"); // TODO: maximaliseren op qp_maxrows2? if ("limit" in params.filter) limit = params.filter.limit; if (params.filter.nolimit || limit == -1) limit = 99999999; // Excel/CSV alles tonen while (!oRs.Eof) { if (data.length >= limit) // Alleen nog maar tellen { if (model.primary) { var key = oRs(model.primary).Value; // Oppassen met de includes if (key != lastkey) total_count ++; lastkey = key; } else { total_count ++; } oRs.MoveNext(); continue; } if (model.primary) { var key = oRs(model.primary).Value; if (key != lastkey) { if (key < lastkey && params.include && params.include.length && !params.include[0] == 'disc_params') // disc_params is toch one-on-one { abort_with_warning("Include '{0}' only allowed when main record is ordered by '{1}'".format(params.include[0], model.primary)); } if (lastkey && !isEmptyObject(record)) // Record was er mogelijk uit gefilterd { data.push(record); total_count ++; if (data.length == limit) continue; // alleen nog tellen, 'volgende' record niet meer opbouwen } var record = {}; } } // Complexe filtering die we niet voor elkaar kregen met een WHERE-clause if (model.filter && model.filter.func) { if (!model.filter.func(oRs, params, prefilterfuncdata)) { lastkey = key; oRs.MoveNext(); continue; } } var fld; for (fld in model.fields) { if (fld.substring(0,1) == "_") continue; var field = model.fields[fld]; if (field.hidden) continue; if ("fields" in params.filter && !inArray(fld, params.filter.fields.split(","))) continue; var val = api2.sql2jsonval(oRs, fld, model) //waarom was dit aanwezig? //if (field.readonly && !val.id) // continue; record[fld] = val; } if (params.include && model.includes) { for (var i in params.include) // welke includes worden opgevraagd? { var incname = params.include[i]; if (incname == "lastchange") // special case continue; if (incname in model.includes) // Ondersteunen we deze include? { if (!(incname in record)) record[incname] = []; var incmodel = model.includes[incname].model; if (incmodel) { // Standaard include via model. Ons 'hoofd' record zal meerdere keren // uit de query komen met telkens een ander 'include' record incmodel.aliasprefix = incmodel.aliasprefix || ""; var inc_key = oRs(incmodel.aliasprefix + incmodel.primary).value; if (inc_key == null) // Geen record door outer join continue; // Nu kan het zo zijn dat ons include record al eerder is toegevoegd // Kan gebeuren bij res_ruimte als je een include van res_alg_ruimte *en* opstelling doet var incfound = false; for (var i = 0; i < record[incname].length && !incfound; i++) { if (record[incname][i].id == inc_key) incfound = true; } if (!incfound) record[incname].push(api2.sql2jsonfields(params, oRs, incmodel)); } else if (model.includes[incname].func) // include via callback functie zoals reservablerooms/occupation { if (model.includes[incname].prefunc && !prefuncdatainitialized) { prefuncdata = model.includes[incname].prefunc(params); prefuncdatainitialized = true; } var incdata = model.includes[incname].func(key, params, oRs, record, prefuncdata); if (incdata !== null) record[incname] = incdata; // de callback geeft de gehele include in een keer } } else __Log("Unknown include '{0}' requested".format(incname)); } } lastkey = key; if (!model.primary) { data.push(record); record = {}; total_count ++; } oRs.MoveNext(); } if (lastkey && data.length < limit) { total_count ++; data.push(record); } if ("merged_model" in model) // de disc_params truc { model.merged_model.limit = limit; //model.offset = offset; model.merged_model.total_count = total_count; } model.limit = limit; //model.offset = offset; model.total_count = total_count; return data; }, error: function (code, msg) { abort_with_warning(msg, code); }, find_fieldindex_by_dbsname: function(array, value) { for(var i = 0; i < array.length; i++) { if(array[i].hasOwnProperty("dbs") && array[i]["dbs"] === value) { return i; } } return -1; }, // Pas op: fields is hier alleen de fields die bijgewerkt moeten worden field_alter: function(fields, fld, newval, model) { if (fld in fields) { fields[fld].val = newval; } else { // Als veld niet aanwezig is, dan toevoegen. // Het typ halen we uit het api-model. var newfield = {}; newfield.dbs = model[fld].dbs; newfield.typ = model[fld].typ; if (model[fld].track) newfield.fld = model[fld].label||model[fld].track; newfield.val = newval; __Log(newfield); fields[fld] = newfield; } }, // Maak van inkomende data een standaard formaat cleanup_data: function(model, jsondata) { // foreigns's leveren we op als issuetype: { id: 123, name: "de standaardmelding") } // Zo mag je het met een PUT en POST ook opgeven maar we ondersteunen/prefereren ook rechtstreeks issuetype: 123 // Onderstaande functie converteert inkomende data naar het simpele formaat for (var fld in model.fields) { if (model.fields[fld].foreign) { if (fld in jsondata && typeof jsondata[fld] == "object" && jsondata[fld] && "id" in jsondata[fld]) jsondata[fld] = jsondata[fld].id; } } }, get_jdata_refkey: function(jsondataobject) { var value = null; if (jsondataobject) { if (jsondataobject.id && typeof jsondataobject.id != "object") value = jsondataobject.id; else value = jsondataobject; } return value; }, hasTime: function (dt) { return dt.getHours() > 0 || dt.getMinutes() > 0 || dt.getSeconds() > 0 }, toDate: function (dt) { if (dt instanceof Array) MULTI_DATE_NOT_SUPPORTED; if (dt instanceof Date) return dt; // LET OP: Een (new Date) gemaakt binnen een plugin is vreemd genoeg geen (instanceof Date) // Waarschijnlijk gebruikt een wsc een ander Date object als (ASP)JScript? if (dt !== null && typeof dt == "object") { dt = new Date(dt); if (dt instanceof Date) return dt; } if (typeof dt == 'string') { if (dt.match(/^[0-9]+$/)) return new Date(parseInt(dt, 10)); var dt = myJSON.internal_parsedate(null, dt); if (dt && dt instanceof Date) return dt; } NOT_A_DATE; }, generic_REST: function(model, gparams) { __Log("Creating generic_REST for model " + model.records_name); gparams = gparams || {}; if (typeof model == "function") // Nieuwe stijl is het een function. Even compatible. DIT_KLOPT_NIET; // autfunction === false kun je het expliciet uitschakelen if (model.autfunction !== false && !model.autfunction) GENERIC_ONLY_WITH_AUTFUNCTION; model.REST_GET = generic_REST_GET(model, gparams); if (model.primary) { model.REST_POST = generic_REST_POST(model, gparams); model.REST_PUT = generic_REST_PUT(model, gparams); model.REST_DELETE = generic_REST_DELETE(model, gparams); } }, GET: function _GET(model, key, params) // Haal één enkel record op of null als niet gevonden { // Key is optioneel, dan meot je zelf in params maar goed filteren if (typeof key == "object") { params = key; key = null; } else { params = params || {}; params.filter = params.filter || {}; params.filter.id = key; } var xxx_array = model.REST_GET(params); if (!xxx_array.length) return null; return xxx_array[0]; }, POST: function _POST(model, jsondata, parent_key) // Maak één enkel record aan { // Key is optioneel, dan meot je zelf in params maar goed filteren var params = {}; return model.REST_POST(params, jsondata, parent_key); }, merge_disc_params_model: function(deze, template_model) { template_model.merged_model = deze; // hebben we nodig om total_count te kunnen zetten for (var x in template_model) deze[x] = template_model[x]; deze.fields = {}; // Die krijgt een deepclone for (var fld in template_model.fields) deze.fields[fld] = template_model.fields[fld]; for (var fld in deze.disc_params.model.fields) { if (fld != "id") deze.fields[fld] = deze.disc_params.model.fields[fld]; } } } function generic_REST_GET(model, gparams) { gparams = gparams || {}; gparams.GET = gparams.GET || {}; model.gparams = gparams; return function _generic_REST_GET(params, jsondata) { if (model.autfunction !== false) user.checkAutorisation(model.autfunction); // Als je zelfs geen readrechten hebt ben je heel fout bezig if ("disc_params" in model) { // We zouden net als bij de PUT etc. een rechtstreekse call op de eigen REST_GET kunnen doen // maar dat werkt niet (zo soepeltjes) voor meerdere records model.includes = model.includes || {}; model.includes["disc_params"] = model.disc_params; params.include = params.include || []; params.include.push("disc_params"); // Altijd } var query = api2.sqlfields(params, model); var wheres = api2.sqlfilter(params, model); query.wheres = query.wheres.concat(wheres); if ("disc_params" in model) // Daar mag je ook op filteren { if (params.filter && "id" in params.filter) delete params.filter.id; // anders wordt de disc_params_key onterecht gefilterd. var wheres = api2.sqlfilter(params, model.disc_params.model); query.wheres = query.wheres.concat(wheres); } if (gparams.GET.tables) query.tables = query.tables.concat(gparams.GET.tables); if (gparams.GET.wheres) query.wheres = query.wheres.concat(gparams.GET.wheres); if (model.soft_delete && params.filter.show_deleted != "on") query.wheres.push(model.soft_delete + " IS NULL"); if (model.soft_expire && params.filter.show_expired != "on" && !params.filter.id) query.wheres.push("(" + model.soft_expire + " IS NULL OR " + model.soft_expire + " > SYSDATE)"); var sql = "SELECT " + query.selects.join(", ") + " FROM " + query.tables.join(", ") + (query.wheres.length ? " WHERE " + query.wheres.join(" AND " ) : ""); if (query.withs) { for (var w in query.withs) sql = " WITH " + w + " AS " + query.withs[w] + sql; } var orderbys = ((params.orderby && params.orderby.length > 0) ? [] : gparams.GET.orderbys || []); if (params.orderby) { for (var i = 0; i < params.orderby.length; i++) { var field = model.fields[params.orderby[i]]; if (field.sql) orderbys.push(field.sql); else orderbys.push(field._foreignname || field.dbs); } } if (!params.include && params.columns && params.columns.length > 1) // Sorteren volgens 'columns' { for (var i = 0; i < params.columns.length; i++) { if (params.columns[i] != "id")// Sla id-veld over bij sorteren { var field = model.fields[params.columns[i]]; orderbys.push(model.fields[params.columns[i]]._foreignname || model.fields[params.columns[i]].dbs); } } } if (!orderbys.length) { if (model.fields && "name" in model.fields) orderbys.push(model.fields.name.dbs); else if (model.fields && "id" in model.fields) orderbys.push(model.fields.id.dbs); else orderbys.push(1); // FAC_VERSION heeft niets van dit alles } sql += " ORDER BY " + orderbys.join(", "); // TODO: Altijd goed met includes? // Probeer ook nog de 1e include te sorteren. Fraaier met subframes in scaffolding if (params.include && params.include.length && model.includes && params.include[0] in model.includes) { var inc0 = model.includes[params.include[0]].model; if (inc0.fields["sequence"]) sql += ", " + inc0.table + "." + inc0.fields["sequence"].dbs; if (inc0.fields["name"]) sql += ", " + inc0.table + "." + inc0.fields["name"].dbs; if (inc0.fields["id"]) sql += ", " + inc0.table + "." + inc0.fields["id"].dbs; } var maxcnt = params.filter.showall==1?S("qp_maxrows2"):S("qp_maxrows"); if (params.include && params.include.length) { // geen beperking // We proberen te voorkomen dat we onnodig veel rijen ophalen. // Als er echter includes zijn krijgen we veel meer records dan je direct zou verwachten en // klopt de beperking op basis van ROWNUM geheel niet. Met gepaste tegenzin bij includes // dan maar (veel) te veel records ophalen. } else { if (!params.filter.nolimit) // Dan niet (Excel, CSV) var sql = "SELECT * FROM (" + sql + ") WHERE ROWNUM <= " + (maxcnt + 1); // Eentje extra om overflow-melding te triggeren in resultsettable } if (model.fields) var json = api2.sql2json (params, sql, model); else json = {}; if ("disc_params" in model) { // include van disc_params data niveau 'hoger' zetten for (var i = 0; i < json.length; i ++) { for (var fld in json[i].disc_params[0]) { if (fld != "id") json[i][fld] = json[i].disc_params[0][fld]; } delete json[i].disc_params; } } return json; } } function generic_REST_POST(model, gparams) { gparams = gparams || {}; if (!model.fields["id"].seq) // We willen per se een sequence return false; return function _generic_REST_POST(params, jsondata, parent_key) { params.isNew = true; // negeer eventuele bestaande keys if (model.autfunction !== false) { var autparams = user.checkAutorisation(model.autfunction); user.auth_required_or_abort(autparams.PRSwritelevel < 9 && autparams.ALGwritelevel < 9); } if ("disc_params" in model) { // disc_params velden er uit trekken naar eigen json object var module = model.fields.ins_discipline_module || ""; var jsondata_dp = { }; for (var fld in jsondata) { if (fld in model.disc_params.model.fields && !(fld in model.fields)) { jsondata_dp[fld] = jsondata[fld]; delete jsondata[fld]; } } } for (var fld in model.fields) { if (!(fld in jsondata) && model.fields[fld].required) jsondata[fld] = model.fields[fld].defaultvalue; // hopen dat die is gezet } var dbfields = api2.update_fields(params, model, jsondata); dbfields["id"] = model.fields["id"]; // Die zal een seq hebben var xxxIns = buildInsert(model.table, dbfields, { noValidateToken: true }); var the_key = xxxIns.sequences[model.fields.id.dbs]; // TODO: Generieke tracking? var err = Oracle.Execute(xxxIns.sql, true); if (err.friendlyMsg) abort_with_warning(err.friendlyMsg); var inctrack = api2.process_includes(params, model, jsondata, the_key); if ("disc_params" in model) { // Nu de one-on-one tabel. De eigen sequence daarvan interesseert ons niet jsondata_dp[model.disc_params.joinfield] = the_key; var dbfields = api2.update_fields(params, model.disc_params.model, jsondata_dp); var xxxIns = buildInsert(model.disc_params.model.table, dbfields, { noValidateToken: true }); var err = Oracle.Execute(xxxIns.sql, true); if (err.friendlyMsg) { var sql = "DELETE FROM " + model.table + " WHERE " + model.fields.id.dbs + " = " + the_key; Oracle.Execute(sql); abort_with_warning(err.friendlyMsg); } } return { key: the_key, warning: "" }; } } function generic_REST_PUT(model, gparams) { gparams = gparams || {}; return function _generic_REST_PUT(params, jsondata, the_key) { if (model.autfunction !== false) { var autparams = user.checkAutorisation(model.autfunction); user.auth_required_or_abort(autparams.PRSwritelevel < 9 && autparams.ALGwritelevel < 9); } if ("disc_params" in model) { // disc_params velden er uit trekken naar eigen json object var jsondata_dp = { }; for (var fld in jsondata) { if (fld in model.disc_params.model.fields && !(fld in model.fields)) { jsondata_dp[fld] = jsondata[fld]; // delete jsondata[fld]; neen, dan gaat multi-save fout } } model.disc_params.model.fields[model.disc_params.joinfield].readonly = true; // Voor de zekerheid jsondata_dp[model.disc_params.joinfield] = the_key; } var dbfields = api2.update_fields(params, model, jsondata); var wheres = [model.fields["id"].dbs + " = " + the_key]; var xxxUpd = buildTrackingUpdate(model.table, wheres.join(" AND " ), dbfields, { noValidateToken: true }); // TODO: Generieke tracking? if (xxxUpd) // Misschien geen velden opgegeven. { var err = Oracle.Execute(xxxUpd.sql, true); if (err.friendlyMsg) abort_with_warning(err.friendlyMsg); if (model.trackcode && xxxUpd.trackarray.length > 0) shared.trackaction(model.trackcode, the_key, L("lcl_updated") + "\n" + xxxUpd.trackarray.join("\n")); } var inctrack = api2.process_includes(params, model, jsondata, the_key); if ("disc_params" in model) { // Nu de one-on-one tabel var dbfields = api2.update_fields(params, model.disc_params.model, jsondata_dp); var wheres = [model.disc_params.model.fields[model.disc_params.joinfield].dbs + " = " + the_key]; var xxxUpd = buildTrackingUpdate(model.disc_params.model.table, wheres.join(" AND " ), dbfields, { noValidateToken: true }); if (xxxUpd) // Misschien geen velden opgegeven. { var err = Oracle.Execute(xxxUpd.sql, true); if (err.friendlyMsg) abort_with_warning(err.friendlyMsg); } } return { key: the_key, warning: "" }; } } function generic_REST_DELETE(model, gparams) { gparams = gparams || {}; return function _generic_REST_DELETE(params, the_key) { if (model.autfunction !== false) { var autparams = user.checkAutorisation(model.autfunction); user.auth_required_or_abort(autparams.PRSwritelevel < 9 && autparams.ALGwritelevel < 9); } if (model.soft_delete) { var sql = "UPDATE " + model.table + " SET " + model.soft_delete + " = SYSDATE" + " WHERE " + model.fields.id.dbs + " = " + the_key + " AND " + model.soft_delete + " IS NULL"; } else { var sql = "DELETE " + model.table + " WHERE " + model.fields.id.dbs + " = " + the_key; } var err = Oracle.Execute(sql, true); if (err.friendlyMsg) abort_with_warning(err.friendlyMsg); return { key: the_key, warning: "" }; } } // Algemene normalizing function def(hash, fld, val) { if (!(fld in hash)) hash[fld] = val; } function isEmptyObject ( obj ) { var name; for ( name in obj ) { return false; } return true; } %>