Differences
This shows you the differences between two versions of the page.
| — |
pub:prepstat [2026/02/05 18:42] (current) f.strappini created |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Accesso a DB tramite prepared statement ====== | ||
| + | ===== Generalità ===== | ||
| + | * I prepared statement sono gestiti attraverso l' | ||
| + | * I prepared statement riconosciuti dall' | ||
| + | * Ogni file json può contenere più di un prepared statement | ||
| + | * L' | ||
| + | * tpevodb: agente di database | ||
| + | * path: path ove risiedono i file di configurazione | ||
| + | * Es: | ||
| + | <code xml> | ||
| + | <agent lib="/ | ||
| + | <param name=" | ||
| + | <param name=" | ||
| + | </ | ||
| + | </ | ||
| + | ==== Key ==== | ||
| + | * Ogni prepared statement è identificata attraverso la seguente codifica: | ||
| + | * {Main Key}.{Sub Key} | ||
| + | * {Main Key}: identifica il nome del file senza estensione | ||
| + | * {Sub Key}: identifica lo specifico prepared statement all' | ||
| + | * L' | ||
| + | * L' | ||
| + | * Es: | ||
| + | * nel file **topology.json** è presente un prepared statement codificato con **nodi** | ||
| + | * la chiave di tale prepared statement è: **topology.nodi** | ||
| + | ===== JSON ===== | ||
| + | * Il file .json permette di configurare più di un prepared statement | ||
| + | * Si possono aggregare, nello stesso file, prepared statement che hanno fini comuni ad esempio | ||
| + | * insieme di tabelle di database associate a certe entità logicamente correlate | ||
| + | * insieme di operazioni comuni (select, update, insert, delete) | ||
| + | * etc... | ||
| + | * Il file contiene un array di oggetti, ognuno dei quali ha i seguenti attributi: | ||
| + | * **subkey**: chiave associata allo specifico prepared statement all' | ||
| + | * **sql**: query sql che definisce il prepared statement | ||
| + | * Es: file operalang.json, | ||
| + | * operalang.insert | ||
| + | * operalang.update | ||
| + | * operalang.select | ||
| + | <code javascript> | ||
| + | [ | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | </ | ||
| + | |||
| + | ===== Parametri e Query ===== | ||
| + | * I parametri di un prepared statement sono definiti in **forma espressiva** (attraverso nomi descrittivi) e non in **forma numerata** | ||
| + | * Questo modello permette di poter gestire i parametri in modo più intuitivo e semplificato, | ||
| + | * L' | ||
| + | * La sintassi utilizzata per definire un parametro in un prepared statement è la seguente: | ||
| + | * **$[.]** => il nome del parametro è inserito tra parentesi quadre, precedute dal simbolo **$** | ||
| + | * Es: **$[codice]** | ||
| + | * //il nome del parametro, tra parentesi quadre, non deve essere necessariamente il nome di un campo di database, ma può essere un qualsiasi nome riconosciuto dall' | ||
| + | * **Risulta però conveniente dal punto di vista progettuale e di uniformità nelle conoscenze dei sistemi, utilizzare i nomi dei campi di database** | ||
| + | * Di seguito un esempio di query in forma espressiva (da configurare nel sistema) e la corrispondente in forma numerata: | ||
| + | <code sql> | ||
| + | --Forma espressiva | ||
| + | select * from nodi where id=$[idnodo] and codprg=$[codice progetto]; | ||
| + | |||
| + | --Forma numerata | ||
| + | select * from nodi where id=$1 and codprg=$2; | ||
| + | </ | ||
| + | * Se un parametro è ripetuto più volte con lo stesso nome, verrà connesso con lo stesso numero | ||
| + | * Le query di insert, update, delete devono essere sempre seguite dall' | ||
| + | <code sql> | ||
| + | insert into operalang (codice, | ||
| + | </ | ||
| + | |||
| + | ====== AgentData e funzionalità ====== | ||
| + | * L' | ||
| + | * L' | ||
| + | * Le query preconfezionate sono definite in appositi file json. Ogni file json e' un array di oggetti del tipo: | ||
| + | * {" | ||
| + | ===== Esecuzione dei prepared statement ===== | ||
| + | * Al fine di eseguire un prepared statement si effettua una **ask** come segue: | ||
| + | * **request** = **KEY** (chiave del prepared statement che si vuole eseguire, oppure Main Key) | ||
| + | * **p1** = rec(//lista parametri// | ||
| + | * **nume** = 0 valore di default => operazione semplice (per nume > 0 vedi paragrafo Funzioni integrative) | ||
| + | * **retval** = risultato della query (nel caso di query insert, update, delete si inserisce in fondo alla query " | ||
| + | * Es | ||
| + | * file **operacom.json** | ||
| + | <code javascript> | ||
| + | [ | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | </ | ||
| + | * **Chiamata** | ||
| + | * agente: **AgentData** | ||
| + | * tipo di chiamata: **ask** | ||
| + | * request: **operacom.selectkey** | ||
| + | * p1: **{" | ||
| + | {{: | ||
| + | |||
| + | |||
| + | * **Risposta** | ||
| + | <code javascript> | ||
| + | [ | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | </ | ||
| + | * Se **KEY (request) viene posta ad un valore di {Main Key}** (solo parte relativa al nome del file), **il sistema può restituire il risultato dell' | ||
| + | * **L' | ||
| + | * infatti i permessi utente potrebbero essere associati all' | ||
| + | |||
| + | ==== Esecuzione multi-query implicita ==== | ||
| + | * request = **{Main Key}** | ||
| + | * p1 = (**_subkey**, | ||
| + | * **_subkey** = la lista delle Sub Key a cui siamo interessati, | ||
| + | * se _subkey non viene specificato (vuoto, oppure assente) => l' | ||
| + | * **lista parametri**: | ||
| + | * se due Sub Key hanno un parametro in comune (stesso nome espressivo), | ||
| + | * retval: rec(lista key) ove | ||
| + | * lista key: | ||
| + | * un attributo per ogni KEY richiesta, con il nome **{Main Key}.{Sub Key}** | ||
| + | * il valore di ogni attributo è il JSON corrispondente all' | ||
| + | * **Questo modello è particolarmente indicato per estrarre (select), con una unica chiamata, i dati da più tabelle in relazione tra loro** | ||
| + | * Es: | ||
| + | * file **topology.json** | ||
| + | <code javascript> | ||
| + | [ | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | </ | ||
| + | * **Chiamata** | ||
| + | * agente: **AgentData** | ||
| + | * tipo chiamata: **ask** | ||
| + | * request: **topology** | ||
| + | * p1: **{" | ||
| + | |||
| + | {{: | ||
| + | * **Risposta** | ||
| + | <code javascript> | ||
| + | [ | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | } | ||
| + | ] | ||
| + | </ | ||
| + | |||
| + | ==== Esecuzione multi-query esplicita ==== | ||
| + | * request = **{Main Key}** | ||
| + | * p1 = (**_subkey**, | ||
| + | * **_subkey** = codice di una specifica Sub Key nel file della Main Key | ||
| + | * **_params**: | ||
| + | * ogni Sub Key è analizzata indipendentemente dalle altre | ||
| + | * retval: rec(lista key) ove | ||
| + | * lista key: | ||
| + | * un attributo per ogni KEY richiesta, con il nome **{Main Key}.{Sub Key}** | ||
| + | * il valore di ogni attributo è il JSON corrispondente all' | ||
| + | |||
| + | === Esempio === | ||
| + | * Consideriamo il seguente file operacomins.json | ||
| + | <code javascript> | ||
| + | [ | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | </ | ||
| + | * Vogliamo inserire un nuovo **operacom** ed i relativi messaggi in **operamsg** per i vari linguaggi **operalang**, | ||
| + | * operacom: una riga per il nuovo tipo di messaggio | ||
| + | * operamsg: una riga per ogni traduzione prevista nella specifica lingua | ||
| + | * Possiamo eseguire | ||
| + | * **ask** | ||
| + | * **request** = operacomins | ||
| + | * **nume** = 2 | ||
| + | * transazione: | ||
| + | * pre-processing: | ||
| + | * {" | ||
| + | * {" | ||
| + | * **p1** è il seguente json | ||
| + | <code javascript> | ||
| + | [ | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | } | ||
| + | ] | ||
| + | </ | ||
| + | |||
| + | ==== Applicazione Funzioni Avanzate ==== | ||
| + | Indipendentemente dal tipo di query (monoquery, multiquery implicete o esplicite) è possibile richiedere al sistema una combinazione delle seguenti funzionalità: | ||
| + | * Transazione | ||
| + | * Preprocessing | ||
| + | * Merge dei risultati | ||
| + | |||
| + | Per attivare una o tutte le funzioni indicate bisogna utilizzare il **nume** secondo la tabella seguente: | ||
| + | ^ Nume ^ Bit ^ Descrizione | ||
| + | | **0** | 000 | Nessuna Funzione | ||
| + | | **1** | 001 | Transazione | ||
| + | | **2** | 010 | Preprocessing | ||
| + | | **3** | 011 | Transazione + Preprocessing | ||
| + | | **4** | 100 | Merge | | | **X** | | ||
| + | | **5** | 101 | Transazione + Merge | **X** | | **X** | | ||
| + | | **6** | 110 | Preprocessing + Merge | | **X** | **X** | | ||
| + | | **7** | 111 | Transazione + Preprocessing + Merge | **X** | **X** | **X** | | ||
| + | |||
| + | Come si osserva dalla tabella le transazioni sono attivate con nume=1, il preprocessing con nume = 2, il merge con nume = 4; gli altri valori del nume combinano le tre funzioni in modo opportuno (vedi tabella delle funzioni avanzate sopra). | ||
| + | |||
| + | === Transazioni === | ||
| + | * **Questo modello è particolarmente indicato nel caso di applicazione di modifiche ai dati attraverso operazioni di insert, update, delete attuate su più tabelle in relazione tra loro** | ||
| + | * I dati vengono preparati inserendo, per ogni Sub Key, i valori rilevati, nei rispettivi parametri attesi dal prepared statement | ||
| + | * Si costruisce un JSon per ogni Sub Key, contenente i parametri | ||
| + | * **Per assicurare l' | ||
| + | * è possibile eseguire le operazioni all' | ||
| + | * a tale scopo => **nume = 1** esegue i prepared statement all' | ||
| + | * se anche una sola query non va a buon fine, il sistema esegue una rollback della transazione altrimenti esegue commit | ||
| + | |||
| + | === Pre-Processing dei parametri === | ||
| + | * Impostando nume = 2 si richiede all' | ||
| + | * L' | ||
| + | * **_getnume** => se un parametro ha il valore **_getnume**, | ||
| + | * il numeratore richiesto sarà: **getnume({MainKey}.{SubKey}, | ||
| + | * l' | ||
| + | * **_getnume(tabnume, | ||
| + | * **_uuidv4** => se un parametro ha il valore **_uuid** (v4), l' | ||
| + | * la uuid viene generata con la classe iaf stringutil:: | ||
| + | * viene generata una uuid per l' | ||
| + | * la uuid generata ha una dimensione fissa di 37 caratteri | ||
| + | * **_uuidv7** => se un parametro ha il valore **_uuidv7**, | ||
| + | * la uuid viene generata con la classe iaf stringutil:: | ||
| + | * viene generata una uuid per l' | ||
| + | * la uuid generata ha una dimensione fissa di 37 caratteri | ||
| + | * **_uuidshort** => se un parametro ha il valore **_uuidshort**, | ||
| + | * **_uuidveryshort** => se un parametro ha il valore **_uuidveryshort**, | ||
| + | * **$[X.Y]** => sostituisce il valore del parametro relativo, con il valore del parametro riferito dalla coppia | ||
| + | * X=Sub Key della Main Key in elaborazione | ||
| + | * Y=nome parametro della Sub Key | ||
| + | * es: nodi.codice: | ||
| + | * Utile nei casi in cui si assegni una chiave esterna a RUN-TIME tramite la _getnume | ||
| + | * **_datanow**, | ||
| + | * la data corrente (YYYYMMDD) | ||
| + | * l'ora corrente (HH:MI:SE) | ||
| + | * il time epoch corrente (secondi da 1 Gennaio 1970) | ||
| + | === Merge dei risultati === | ||
| + | * Funzionalità applicata dall' | ||
| + | * Esegue il merge di tutti i dataset di una multiquery in un unico dataset dove vengono accodati nella sequenza di esecuzione i dataset ottenuti | ||
| + | * Il **retval** prende in questo caso una struttura tabella che rappresenta il merge di tutti i risultati | ||
| + | * Particolarmente utile per fare il merge di dati provenienti da più database in una unica struttura tabellare | ||
| + | ===== Altre funzioni di AgentData ===== | ||
| + | ==== Lista parametri ==== | ||
| + | * Tramite **ask** è possibile richiedere la lista dei parametri di una {Main Key}.{Sub Key}: | ||
| + | * **request = keyparams** | ||
| + | * p1 = rec(key, | ||
| + | - key = chiave completa {Main Key}.{Sub Key} => il campo _subkey è trascurato | ||
| + | - key = Main Key e _subkey = vuoto => restituisce i parametri di tutti i _subkey della Main Key | ||
| + | - key = Main Key e _subkey = lista di subkey divisi da virgola => restituisce i parametri dei subkey specificati | ||
| + | * nume = numero di righe nei parametri | ||
| + | * retv = rec(parametri), | ||
| + | - un json con una colonna per ogni parametro il cui nome e' proprio il nome del parametro, il valore e' vuoto | ||
| + | - un json con una colonna per ogni subkey della Main Key identificata con {Main Key}.{Sub Key} contenente il json dei parametri della specifica key | ||
| + | - un json con una colonna per ogni subkey della Main Key indicata in _subkey, identificata con {Main Key}.{Sub Key} contenente il json dei parametri della specifica key | ||
| + | * **request = keyparamsmqi (keyparams per multiquery implicite)** | ||
| + | * p1 = rec(key, | ||
| + | * retv = rec(parametri) restituisce in una unica riga tutti i parametri del sottoinsieme di key richieste senza replicazioni; | ||
| + | ==== Reload del repository ==== | ||
| + | * Tramite **tell** è possibile fare ricaricare dal repository di file json tutte le configurazioni, | ||
| + | * request = reload | ||
| + | * p1 = rec(ciao=ciao) | ||
| + | * retv = true se l' | ||
| + | ==== Costruzione automatica file JSon Insert / Update ==== | ||
| + | Attraverso una chiamata **tell** all' | ||
| + | * insert, update, delete | ||
| + | di apposite liste di tabelle. Di seguito vediamo i 3 casi. | ||
| + | === Insert === | ||
| + | * E' possibile costruire file json contenenti operazioni di insert per gruppi tabelle correlate, attraverso l' | ||
| + | * request = tabinsert | ||
| + | * p1 = rec(key, | ||
| + | * key = Main Key (nome del file senza estensione da creare) | ||
| + | * tabs = lista delle tabelle interessate separate da virgola senza spazi | ||
| + | * nume = 1 => i nuovi dati vengono inseriti in append nel file (se esiste), altrimenti il file viene sovrascritto | ||
| + | * retv = true se il file e' stato creato nel path di destinazione definito | ||
| + | === Update === | ||
| + | * E' possibile costruire file json contenenti operazioni di update per gruppi tabelle correlate, attraverso l' | ||
| + | * request = tabupdate | ||
| + | * p1 = rec(key, | ||
| + | * key = Main Key (nome del file senza estensione da creare) | ||
| + | * tabs = lista delle tabelle interessate separate da virgola senza spazi | ||
| + | * nume = 1 => i nuovi dati vengono inseriti in append nel file (se esiste), altrimenti il file viene sovrascritto | ||
| + | * retv = true se il file e' stato creato nel path di destinazione definito | ||
| + | * La condizione di update (where codice=...) viene applicata come segue: | ||
| + | * se esiste un campo codice, viene utilizzato nella codizione di update come segue | ||
| + | * nome espressivo: _codice (codice preceduto da underscore) | ||
| + | * condizione aggiunta: **where codice = $[_codice]** | ||
| + | * se non esiste un campo codice, l' | ||
| + | * nome espressivo: _codXXX (codice di chiave esterna preceduto da underscore) | ||
| + | * condizione aggiunta: **where codXXX = $[_codXXX] and codYYY = $[_codYYY] and ...** | ||
| + | === Delete === | ||
| + | * E' possibile costruire file json contenenti operazioni di delete per gruppi tabelle correlate, attraverso l' | ||
| + | * request = tabdelete | ||
| + | * p1 = rec(key, | ||
| + | * key = Main Key (nome del file senza estensione da creare) | ||
| + | * tabs = lista delle tabelle interessate separate da virgola senza spazi | ||
| + | * nume = 1 => i nuovi dati vengono inseriti in append nel file (se esiste), altrimenti il file viene sovrascritto | ||
| + | * retv = true se il file e' stato creato nel path di destinazione definito | ||
| + | * La condizione di delete (where codice=...) viene applicata come segue: | ||
| + | * se esiste un campo codice, viene utilizzato nella codizione di update come segue | ||
| + | * nome espressivo: _codice (codice preceduto da underscore) | ||
| + | * condizione aggiunta: **where codice = $[_codice]** | ||
| + | * se non esiste un campo codice, l' | ||
| + | * nome espressivo: _codXXX (codice di chiave esterna preceduto da underscore) | ||
| + | * condizione aggiunta: **where codXXX = $[_codXXX] and codYYY = $[_codYYY] and ...** | ||
| + | === Tutte le operazioni === | ||
| + | * E' possibile creare un file json con tutte le operazioni (insert, update, delete) richiamando la seguente | ||
| + | * request = **taballop** | ||
| + | * p1 = rec(key, | ||
| + | * key = Main Key (nome del file senza estensione da creare) | ||
| + | * tabs = lista delle tabelle interessate separate da virgola senza spazi | ||
| + | * nume = 1 => i nuovi dati vengono inseriti in append nel file (se esiste), altrimenti il file viene sovrascritto | ||
| + | * retv = true se il file e' stato creato nel path di destinazione definito | ||
| + | |||
| + | === Esempio Insert (stesso per update) === | ||
| + | * **Chiamata** | ||
| + | * agente: **AgentData** | ||
| + | * tipo chiamata: **tell** | ||
| + | * request: **tabinsert** | ||
| + | * p1: **{" | ||
| + | {{: | ||
| + | |||
| + | ===== Utilizzo di più database ===== | ||
| + | * I file Json degli esempi precedenti non forniscono alcuna indicazione sull' | ||
| + | * In questi casi l' | ||
| + | * Tutti i prepared statement verranno quindi eseguiti attraverso tale agentdb | ||
| + | * E' possibile associare ciascuna prepared statement ad un differente agentdb | ||
| + | * A tal fine si può aggiungere, opzionalmente, | ||
| + | * L' | ||
| + | * mentre per i prepared statement che forniscono l' | ||
| + | * Questa possibilità è utile per: | ||
| + | * recuperare dati da differenti database | ||
| + | * inserire dati in differenti database | ||
| + | * replicare dati da un database ad un' | ||
| + | ==== Esempio Json per più database ==== | ||
| + | * Ipotizziamo di: | ||
| + | * dover inserire un nuovo utente in un sistema informativo | ||
| + | * che il sistema informativo sia composto dai seguenti database: | ||
| + | * userdb: database di gestione della protezione (nome dell' | ||
| + | * oeedb: database di gestione dell' | ||
| + | * mldb: database di gestione del machine ledger (nome dell' | ||
| + | * l' | ||
| + | * Vediamo di seguito un esempio di file JSON **opins.json**: | ||
| + | <code javascript> | ||
| + | [ | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | </ | ||
| + | * Attraverso una unica richiesta di esecuzione di multi-query implicita è possibile inserire l' | ||
| + | * si assegnano gli attributi codice, pwd, nominati, email dell' | ||
| + | * si esegue la ask con request = operains | ||
| + | * si pone nume = 1 per attivare le transazioni | ||
| + | * l' | ||
| + | * **Esempio Chiamata** | ||
| + | * agente: **AgentData** | ||
| + | * tipo chiamata: **ask** | ||
| + | * request: **opins** | ||
| + | * p1: **{" | ||
| + | * nume: **1** | ||
| + | {{: | ||
| + | |||
| + | ===== Parameters Augmentation ===== | ||
| + | L' | ||
| + | * utilizzando valori default specificati in configurazione | ||
| + | * andando a prelevare i dati dal database attraverso una prepared statement | ||
| + | * impostando i dati a NULL | ||
| + | Di seguito la specifica dell' | ||
| + | * Data una prepared S sia: | ||
| + | * P l' | ||
| + | * Q l' | ||
| + | * sia M = P - Q l' | ||
| + | * se M = 0 significa che tutti i parametri P richiesti da S sono stati forniti in Q | ||
| + | * Se Q ha una sola riga e M > 0, l' | ||
| + | * tale algoritmo cerca di assegnare automaticamente i parametri in M, come segue: | ||
| + | * applicazione dei parametri di default definiti nella subkey | ||
| + | * impostazione dei parametri a partire dal risultato derivante dall' | ||
| + | * impostazione dei parametri a valori NULL | ||
| + | * Siano S(1), S(2), ..., S(n) le prepared statement da cui prelevare i parametri | ||
| + | * Siano R(1), R(2), ..., R(n) i risultati dell' | ||
| + | * M = M - R(1) - R(2) - ... - R(n) è l' | ||
| + | * Se M > 0 ed è richiesto il setting a NULL | ||
| + | * l' | ||
| + | * Per poter applicare l' | ||
| + | * **paramsdef**: | ||
| + | * **paramsql**: | ||
| + | * **paramsnull**: | ||
| + | * **Esempio** | ||
| + | * vogliamo inserire una nuova linea di produzione | ||
| + | * creiamo una mainkey = linea e il corrispondente file linea.json | ||
| + | * per completare l' | ||
| + | * ubicaz: tutti i dati richiesti, con setting automatico a NULL di quelli non forniti | ||
| + | * lottim: solo il campo codice, non richiesto l' | ||
| + | * oeeconf (ORA): oeeconf orario, si preleva la configurazione da valori default | ||
| + | * oeeconf (DAY): oeeconf giornaliero, | ||
| + | * di seguito linea.json | ||
| + | <code javascript> | ||
| + | [ | ||
| + | {" | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | | ||
| + | } | ||
| + | ] | ||
| + | </ | ||
| + | * le key ubicazdef.oeeconfh e ubicazdef.oeeconfd sono presenti nel file ubicazdef.json, | ||
| + | <code javascript> | ||
| + | [ | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | </ | ||
| + | * L' | ||
| + | * **Chiamata** | ||
| + | * agente: **AgentData** | ||
| + | * request: **linea** | ||
| + | * p1: **{" | ||
| + | * nume: **2** | ||
| + | {{: | ||
| + | ** IMPORTANTE **: i parametri aggiunti con parameters augmentation possono essere soggetti a pre-processing dei parametri; ad esempio in un parametro default potrei impostare il valore di preprocessing **_getnume** | ||
| + | ===== Events ===== | ||
| + | * E' possibile associare ad ogni prepared statement un evento da inviare ad un agente qualora la prepared statement fosse stata eseguita con successo (es: un inserimento, | ||
| + | * E' possibile configurare uno (singolo oggetto) o più agenti (array json) destinatari dell' | ||
| + | * A seguito dell' | ||
| + | * La tell eseguita fornirà nell' | ||
| + | * Per configurare gli eventi è sufficiente integrare nel JSON del prepared statement il seguente attributo: | ||
| + | * **events** = oggetto json o array json, cosi composto: | ||
| + | * **to** = nome dell' | ||
| + | * **request** = request. | ||
| + | * **param** = l' | ||
| + | * Esempio di configurazione evento: | ||
| + | <code javascript> | ||
| + | [ | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | </ | ||
| + | * Se nell' | ||
| + | ===== Riga dummy ===== | ||
| + | * Nel caso in cui, per il primo oggetto del file JSON, non si specifichino gli attributi opzionali (//db, paramsql, paramsnull// | ||
| + | * La **riga dummy** permette all' | ||
| + | * La **riga dummy** va inserita come prima riga del json, di seguito un esempio: | ||
| + | <code javascript> | ||
| + | [ | ||
| + | {" | ||
| + | {...} | ||
| + | ] | ||
| + | </ | ||
| + | ===== Generazione di csv da Prepared Statement ===== | ||
| + | * Utilizzando la tell è possibile eseguire qualsiasi prepared statement come con la ask | ||
| + | * In questo caso l' | ||
| + | * E' possible generare file CSV a partire da una prepared statement, basta aggiungere nel JSON della richiesta i seguenti attributi: | ||
| + | * _csvfile: path completo del file csv | ||
| + | * _decimalpoint: | ||
| + | * _separator: (opzionale) si può indicare il carattere separatore dei campi nel file csv (default: ;) | ||
| + | * Se presente l' | ||
| + | |||
| + | ===== Attributi utili di una subkey ===== | ||
| + | ==== Rinominare nomi di campi ==== | ||
| + | Con l' | ||
| + | Vediamo il seguente esempio: | ||
| + | <code javascript> | ||
| + | [ | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | </ | ||
| + | In questo caso **renamemap** rinomina i campi //dbplant, linea, lavorato, previsto, e// assegnando nomi esplicativi. | ||
| + | |||
| + | ==== Normalizzare query lunghe ==== | ||
| + | Per poter normalizzare query lunghe in cui si adoperano ritorni a capo e spazi per poterle leggere meglio nel file JSON si può attivare l' | ||
| + | L' | ||
| + | Questa operazione è particolarmente utile per la visualizzazione dei LOG delle stringhe lunghe. \\ \\ | ||
| + | <code javascript> | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | g.codubi, | ||
| + | l.codart, | ||
| + | ca.tipopal as codpal, | ||
| + | ug.xabs as x, | ||
| + | ug.yabs as y, | ||
| + | ug.zabs as z, | ||
| + | CASE WHEN tp.stackable = 1 then 2 else 1 END as npallet, | ||
| + | u.tipocom, | ||
| + | u.tiposet, | ||
| + | 0.0 as a, | ||
| + | 0.0 as b | ||
| + | FROM | ||
| + | giacese g JOIN lottim l on l.codice=g.codlot | ||
| + | JOIN catego ca ON l.codart = ca.codice | ||
| + | JOIN ubicaz u on u.codice=g.codubi | ||
| + | JOIN tipopal tp on tp.codice = l.umext | ||
| + | LEFT JOIN ubigeo ug on ug.codubi = g.codubi | ||
| + | WHERE | ||
| + | g.codubi=$[codubi] | ||
| + | GROUP BY | ||
| + | g.codubi, | ||
| + | l.codart, | ||
| + | u.tipocom, | ||
| + | u.tiposet, | ||
| + | ca.tipopal, | ||
| + | ug.xabs, | ||
| + | ug.yabs, | ||
| + | ug.zabs, | ||
| + | tp.stackable | ||
| + | ORDER BY | ||
| + | max(g.codice)", | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | </ | ||
| + | La normalize riduce tutti gli spazi doppi o i ritorni a capo o i segni di tabulazione ad un unico spazio, in modo da avere la query su una unica riga. \\ \\ | ||
| + | **IMPORTANTE**: | ||
| + | ===== Q&A ===== | ||
| + | * E' possibile attivare la procedura di parameters augmentation per settare automaticamente attributi default indicati espressamente per valore oppure che utilizzano i valori default del campo nel db ? (tipo il null) | ||
| + | * **SI** basta utilizzare l' | ||
| + | * Come va gestito nel prepared statement le query con condizione where che richiede che un parametro sia parte di un certo insieme di parametri ? (esempio: where codice in (' | ||
| + | * di seguito la risposta: | ||
| + | <code javascript> | ||
| + | [ | ||
| + | ... | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | ... | ||
| + | ] | ||
| + | </ | ||
| + | * Come gestire un prepared statement con una like ? | ||
| + | * di seguito la risposta: | ||
| + | <code javascript> | ||
| + | [ | ||
| + | ... | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | </ | ||
| + | * Nel caso in cui una richiesta multi-query non sia vincolata da una transazione è possibile eseguire le query in parallelo ? | ||
| + | * //Nella versione attuale le query parallele sono possibili con le multi-query implicite che non prevedono transazioni; | ||
| + | * Come potremo orientarci all' | ||
| + | * E' necessario costruire un agente che si occupa di: | ||
| + | - tracciare tutte le key presenti nel sistema fornendo: | ||
| + | - commento, sql, path | ||
| + | - ricercare una key, subkey | ||
| + | - ricercare in modo intelligente un commento, una sql | ||
| + | - inserire / modificare / testare nuove key o nuove mainkey | ||