Typové příklady základního dotazování Web API (Query String)
Dále jsou uvedeny příklady pro základní dotazování - query string (parametry URL).
Klauzule select slouží k výběru polí BO, která budou vrácena ve výsledku dotazu.
Výběr kolekce faktur, každý objekt faktury bude obsahovat field ID a field DisplayName, který bude přejmenován na DocNumber.
Tímto způsobem je možné do výsledku zahrnout i uživatelské nebo nepersistentní fieldy Business objektu. Nicméně nepersistentní fieldy BO doporučujeme používat jen v krajních případech, při jejich výběru dochází k degradaci výkonu.
GET http://localhost/data/issuedinvoices?select=ID,DisplayName+as+DocNumber
Všimněte si, že místo mezer je napsáno +. Alternativně by bylo možné mezeru zakódovat jako %20. (Jedná se URL kódování, viz Základní dotazování - query string (parametry URL) Jednotlivé fieldy jsou odděleny čárkou.
Výběr kolekce faktur, každý objekt faktury bude obsahovat všechny persistentní fieldy a uživatelské položky Business objektu.
GET http://localhost/data/issuedinvoices?select=*
Výběr kolekce faktur, každý objekt faktury bude obsahovat částku (Amount) a název firmy, na kterou je faktura vystavena (Firm_ID.Name). První varianta vrátí název firmy v JSON vlastnosti s názvem "Firm_ID.Name", stejným názvem, jaký byl použit pro jeho výběr. Ve druhé variantě je vidět, jak lze field přejmenovat pomocí konstrukce as (výsledná JSON vlastnost se bude jmenovat "FirmName").
GET http://localhost/data/issuedinvoices?select=Amount,Firm_ID.NameGET http://localhost/data/issuedinvoices?select=Amount,Firm_ID.Name+as+FirmName
Výběr kolekce faktur, každý objekt faktury bude obsahovat fieldy ID a DisplayName, který je tentokrát složen pomocí polí načtených z provázaných objektů. Jedná se o rychlejší variantu než je uvedena v prvním příkladu, ve kterém je použita nepersistentní položka (DisplayName); jak již bylo zmíněno výše, nepersistentní položky znamenají degradaci výkonu (při jejich použití dochází k načtení BO). Všimněte si operátoru || sloužícího ke spojování řetězců.
GET http://localhost/data/issuedinvoices?select=ID,DocQueue_ID.Code||'-'||OrdNumber||'/'||Period_ID.Code+as+DocNumber
Klauzule where slouží k omezení vybíraných dat. Jeho hodnotou je výraz, který vrací booleanovskou hodnotu. Ve výrazech je možné využívat následující operátory pro porovnávání:
Výrazy je možné kombinovat pomocí logických operátorů (log. operátory viz tabulka níže). Pořadí provádění operací lze určovat pomocí závorek.
Výběr kolekce faktur, vybrány jsou pouze faktury s částkou větší než 10000.
GET http://localhost/data/issuedinvoices?select=Amount,Firm_ID.Name+as+FirmName&where=Amount+gt+10000
Výběr kolekce faktur, vybrány jsou pouze faktury, které mají částku větší než 10000 a zároveň se Firm_ID nerovná '1100000101'.
GET http://localhost/data/issuedinvoices?select=Amount,Firm_ID.Name+as+FirmName&where=Amount+gt+10000+and+Firm_ID+ne+'1100000101'
Ukázka práce s datumovými hodnotami. Pokud potřebujeme získat příjemky vystavené 2. 8. 2018 v 6:00 nebo později, můžeme pro vyjádření data a času použít variantně zápis ve formátu ISO 8601
GET http://localhost/data/receiptcards?select=DisplayName&where=CreatedAt$DATE+ge+timestamp'2018-08-02T06:00:00'
nebo číselný formát OLE (Excel)
GET http://localhost/data/receiptcards?select=DisplayName&where=CreatedAt$DATE+ge+43314.25
se stejným výsledkem.
Uvádění hodinových a minutových údajů je v obou případech nepovinné. 2. 8. 2018 je tak možné vyjádřit jako '2018-08-08' (ISO) nebo 43314 (OLE).
Pokud v zápisu explicitně neuvedete časovou zónu, předpokládá se, že máte na mysli lokální čas. Stejný požadavek by bylo možné zaslat také s uvedením časové zóny, např.
GET http://localhost/data/receiptcards?select=DisplayName&where=CreatedAt$DATE+ge+'2018-08-02T06:00:00+01:00'
Výše uvedené příklady se týkají zápisu data a času v odesílaných požadavcích. Při práci s Web API jsou nicméně časové údaje obsaženy také v odpovědích na požadavky, ve kterých jsou časové údaje vraceny jako UTC (koordinovaný světový čas) ve formátu ISO 8601 včetně specifikace časové zóny, tj. například 2018-08-02T05:00:00.000Z.
Výjimkou je používání agregačních funkcí, kdy se agregované časové údaje vrací v číselném formátu OLE (Excel). Viz příklad platnosti ceníků v kapitole Knihovna praktických příkladů Web API.
S touto skutečností je zapotřebí počítat a ke zpracování datumových a časových údajů ideálně využívat nějakou standardní knihovnu, která korektně interpretuje časové zóny.
Pokud používáte třídu java.time.format.DateTimeFormatter (Java 8 nebo novější), můžete využít předdefinovaný formát ISO_INSTANT.
Zcela nevhodné je zpracovávat vrácené hodnoty pouze řetězcovými funkcemi, jak si ukážeme na příkladu:
Hodnota 2019-02-10T23:00:00.000Z (vrácená v odpovědi na zaslaný požadavek) odpovídá místnímu času 2019-02-11T00:00:00.000. Pokud se pokusíte oddělit datum prostým odříznutím prvních 10 znaků z vráceného řetězce, získáte mylnou informaci (datum o 1 den starší, než je ve skutečnosti).
Od verze 22.1.9 již není nutné před uvedením času používat klíčové slovo timestamp.
Od verze 23.1. jsou datumové položky s hodnotou 0 v API místo ISOStringu vráceny s hodnotou null. Hodnota null je zároveň použitelná v klausuli where a vyhodnocuje se jako 0.
Ve starších verzích ABRA Gen nebyl údaj o časové zóně v odpovědích uváděn, což mohlo v určitých situacích vést k nejednoznačnostem (při práci s různými časovými pásmy nebo přechody ze standardního času na letní a zpět):
Požadavek (libovolná verze ABRA Gen):
GET http://localhost/data/issuedinvoices?where=id+eq+'3400000101'&select=docdate$date
Odpověď ve verzi ABRA Gen 19.x nebo novější:
[
{
"docdate$date": "2006-01-24T23:00:00.000Z"
}
]
Odpověď ve verzi ABRA Gen 18.x nebo starší (stejná data):
[
{
"docdate$date": "2006-01-25T00:00:00.000"
}
]
Ukázka omezení za skladové menu Hardware - vypíše menu Hardware a všechny jeho potomky:
GET http://localhost:80/demo/storemenuitems?select=text&where=id in (tree 'parent_id' where text eq 'hardware')
Ukázka omezení za skladové menu Hardware (první ID) a služby (druhé ID) a všechny jejich potomky (ilustruje použití logické podmínky or, ale stejnou službu udělá podmínka in s oběma ID):
GET http://localhost:80/demo/storemenuitems?select=text&where=id in (tree 'parent_id' where id eq '2000000101' or id eq '4000000101')
Ukázka omezení skladových karet> za menu Hardware všechny jeho potomky:
GET GET http://localhost:80/demo/storecards?select=storemenuitem_id.text,code,name&where=storemenuitem_id in (tree 'parent_id' where text eq 'hardware')
Za hardware a služby by to bylo obdobně jako výše - podmínky v segmentu tree se vždy týkají stromového číselníku, resp. stanovení základní úrovně, ke které se donačtou podřízené úrovně podle vazební položky. Pokud chceme filtrovat za všechno, tak do where tree části stačí dát podmínku parent_id eq null (případně jinou, která vrátí nejnadřazenější uzly, tzn. ty, které nemají parent_id).
Pokud není třeba omezovat, tak je lepší podmínku vůbec nepoužít.
Ukázka filtrování za firmu a její předchůdce. Toto je třeba provést přes rozšířený dotaz, protože standardní endpoint firms navíc vkládá podmínku za Firm_ID rovno null.
POST http://localhost:80/demo/query
{
"class": "firms",
"select": ["name", "id", "firm_id"],
"where": "id in (tree 'firm_id' where firm_id eq null and name like 'Oracle*')",
}
Odpověď:
POST http://localhost:80/demo/query
[
{
"name": "Oracle Czech s.r.o.",
"id": "4600000101",
"firm_id": null
},
{
"name": "Aktis a.s.",
"id": "M000000101",
"firm_id": "4600000101"
}
]
Aktuálně je podmínka řešena využitím common table expression výrazů. Při konstrukci se interně skládá i Path cesta a kontroluje se na zacyklení. Tzn. že i v případě chybného vstupu (cyklické tree struktury) dotaz nezpůsobí zamrznutí.
Klauzule expand slouží k rozvíjení odkazovaných BO a kolekcí BO. Je používán tehdy, chceme-li jedním dotazem získat Business objekt včetně BO, které jsou s ním propojeny (typicky fieldy, jejichž název končí na "_ID"). Může se jednat o jednotlivé objekty nebo jejich kolekce (typicky Rows - řádky dokladu). Využít lze i vnořeného expand, kdy lze kolekce a reference rozvíjet zanořeně. V klauzuli expand lze i kombinovat klauzuli selectschema
Chceme-li při použití expand použít i jiné než rozvíjené objekty, je nutné je uvést v klauzuli select.
Výběr kolekce faktur vydaných, každá faktura obsahuje částku (Amount) a celý objekt firmy (Firm_ID), na kterou byla vystavena.
GET http://localhost/data/issuedinvoices?select=Amount&expand=Firm_ID
Výběr kolekce faktur vydaných, každá faktura obsahuje částku (Amount) a objekt firmy (Firm_ID), na kterou byla vystavena - objekt firmy obsahuje pouze filedy specifikované v závorkách za názvem fieldu v klauzuli expand. Vybírané fieldy lze přejmenovávat pomocí operátoru as, stejně jako v klauzuli select.
GET http://localhost/data/issuedinvoices?select=Amount&expand=Firm_ID(ID, Code, Name)
Jedná se o zkrácenou formu zápisu, stejného výsledku lze dosáhnout následovně:
GET http://localhost/data/issuedinvoices?select=Amount&expand=Firm_ID(select ID, Code, Name)
Výběr kolekce faktur vydaných, každá faktura obsahuje částku (Amount), celý objekt firmy (Firm_ID), na kterou byla vystavena, a kolekci řádků faktury (Rows).
GET http://localhost/data/issuedinvoices?select=Amount&expand=Firm_ID, Rows
Výběr kolekce faktur vydaných, přičemž každá faktura obsahuje ID a podmnožinu kolekce řádků faktury (Rows) omezenou na řádky typu 3 (skladové). Navíc jsou vráceny pouze specifikované fieldy - ID, typ řádku a částka).
GET http://localhost/data/issuedinvoices?select=id&expand=Rows(select ID, RowType, TotalPrice where RowType eq 3)
Výběr kolekce faktur vydaných, přičemž každá faktura obsahuje ID a podmnožinu kolekce řádků faktury (Rows) omezenou na řádky typu 3 (skladové). Jsou vráceny pouze specifikované fieldy - ID, typ řádku a částka). Řádky jsou navíc seřazeny ve stejném pořadí jako na dokladu.
GET http://localhost/data/issuedinvoices?select=id&expand=Rows(select ID, RowType, TotalPrice where RowType eq 3 orderby PosIndex)
Řazení může být i sestupné:
http://localhost/data/issuedinvoices?select=id&expand=Rows(select ID, RowType, TotalPrice where RowType eq 3 orderby PosIndex desc)
Výběr kolekce faktur vydaných, přičemž každá faktura obsahuje ID a podmnožinu kolekce řádků faktury (Rows) omezenou na řádky typu 3 (skladové). Jsou vráceny pouze specifikované fieldy - ID, typ řádku a částka. Řádky jsou seřazeny ve stejném pořadí jako na dokladu. U skladových karet na řádcích chceme navíc získat jejich ID, kód a název.
GET http://localhost/data/issuedinvoices?select=id&expand=Rows(select ID, RowType, TotalPrice where RowType eq 3 orderby PosIndex), Rows.StoreCard_ID(select ID, Code, Name)
V příkladu je opakovaně využito zanořené expand na několika úrovních.
GET http://localhost/data/storecards?expand=storeunits(expand storeeans(expand parent_id))
V příkladu je kromě expand využita i klauzule selectschema
GET http://localhost/data/storecards?expand=storeunits(selectschema persistent)
Klauzule selectschema je query parametr pomocí kterého lze ovlivnit stejně jako v rozšířeném dotazování množina vracených položek. Využít lze parametry id, persistent, full a expanded
Příklad použití selectschema pro získání ID nad skladovými kartami:
GET http://localhost/data/storecards?selectschema=id
Klauzule groupby slouží k agregaci dat stejným způsobem, jako v SQL.
Výběr kolekce faktur vydaných, každý objekt faktury obsahuje částku ("Sum(Amount)") agregovanou dle firem, na které byly faktury vystaveny ("Firm_ID").
GET http://localhost/data/issuedinvoices?select=Sum(Amount),Firm_ID&groupby=Firm_ID
Výběr kolekce faktur vydaných, každý objekt faktury obsahuje částku ("Sum(Amount)") agregovanou dle firem, na které byly faktury vystaveny - Firm_ID obsahuje kompletní objekt firmy.
GET http://localhost/data/issuedinvoices?select=Sum(Amount)&groupby=Firm_ID&expand=Firm_ID
Ukázka použití funkce Floor, vrací pro kladná čísla celou část, pro záporná taky celou, ale směrem od nuly.
GET http://localhost/data/issuedinvoices?select=Sum(Amount),Firm_ID&groupby=Firm_IDGET http://localhost/data/issuedinvoices?select=Sum(Amount),Firm_ID&groupby=Firm_ID
Klauzule orderby slouží k řazení výstupu stejným způsobem jako v SQL.
Výběr kolekce faktur vydaných, každý objekt faktury obsahuje částku (Amount) a objekt firmy, na kterou je faktura vystavena (Firm_ID). Data jsou řazena podle částky (výchozí je vzestupné řazení).
GET http://localhost/data/issuedinvoices?select=Amount&expand=Firm_ID(ID,Code,Name)&orderby=Amount
Výběr kolekce faktur vydaných, každý objekt faktury obsahuje částku (Amount) a objekt firmy, na kterou je faktura vystavena (Firm_ID). Faktury jsou řazeny dle kódu firmy, na kterou jsou vystaveny, a následně podle částky. Řadit je možné i podle polí odkazovaných objektů, a také vícero polí obecně.
GET http://localhost/data/issuedinvoices?select=Amount&expand=Firm_ID(ID,Code,Name)&orderby=Firm_ID.Code,Amount
Výběr kolekce faktur vydaných, každý objekt faktury obsahuje částku (Amount) a objekt firmy, na kterou je faktura vystavena (Firm_ID). Faktury jsou řazeny dle kódu firmy, na kterou jsou vystaveny vzestupně, a následně podle částky sestupně.
GET http://localhost/data/issuedinvoices?select=Amount&expand=Firm_ID(ID,Code,Name)&orderby=Firm_ID.Code,Amount+desc
Klauzule skip a take slouží k omezování počtu vybraných záznamů. Typickým využitím je stránkování výpisu výsledků. Klauzule skip udává, kolik záznamů se má přeskočit, klauzule take počet záznamů, které se mají vrátit.
Klauzule skip a take je vhodné kombinovat s klauzulí orderby, která zajistí jednoznačné pořadí vypisovaných záznamů.
Výběr kolekce středisek s omezením pro účely stránkování výpisu. První požadavek vrátí prvních deset středisek (seřazených podle kódu), druhý požadavek dalších deset středisek atd.
GET http://localhost/data/divisions?select=code,name&orderby=code&skip=0&take=10
GET http://localhost/data/divisions?select=code,name&orderby=code&skip=10&take=10
...
Podobný příklad naleznete ve sbírce příkladů pod názvem Výběr skladových karet s omezením počtu vrácených záznamů.
Pro získání kompletní cesty u číselníků podporujících stromovou strukturu slouží funkce treepath(<tree field>, <tree expression>). Kromě cesty je možné využít i třídění pomocí aliasu položky.
Funkci lze použít v select části jak url, tak rozšířeného dotazování pomocí post query. V rámci tabulky, nad kterou se cesta vytváří(tedy ve které je definována tree položka), lze za výraz i řadit. Pokud se použije v klauzuli expand nebo obdobě v rozšířené verzi, tak řadit nelze (v tomto případě se totiž expand dotazy spouštějí jako samostatné subdotazy).
Aby bylo možné pomocí výrazu řadit správně, byly doplněny funkce lpad a rpad. Ty jsou taky obecné a dají se použít i na jiné položky. První parametr je výraz, který se má doplnit na požadovanou délku, druhý parametr je požadovaná délka a třetí vlastní pad řetězec.
Vypíše všechny dostupné cesty ke skladovému menu.
GET http://localhost:80/demo/storemenuitems?select=treepath(Parent_ID, '/' || text) as path&orderby=path&take=5&skip=10"
Odpověď:
[
{
"path": "/Hlavní činnost/Služby"
},
{
"path": "/Hlavní činnost/Služby/Servis"
},
{
"path": "/Hlavní činnost/Služby/Účetní služby"
},
{
"path": "/Hlavní činnost/Služby/Školení"
},
{
"path": "/Hlavní činnost/Software"
}
]
Získání skladového menu tříděného za posindex - pro správnost třídění je posindex doplněn pomocí lpad na stejnou délku.
GET http://localhost:80/demo/storemenuitems?select=text,treepath(Parent_ID, '/' || lpad(posindex, 5, ' ')) as path&orderby=path&take=5&skip=10
Odpověď:
[
{
"text": "Software",
"path": "/ 1/ 2"
},
{
"text": "ERP",
"path": "/ 1/ 2/ 1"
},
{
"text": "OS",
"path": "/ 1/ 2/ 2"
},
{
"text": "Ostatní",
"path": "/ 1/ 2/ 3"
},
{
"text": "Služby",
"path": "/ 1/ 3"
}
]
Získání cesty ve skladovém menu ke skladové kartě pomocí klauzule expand.
GET http://localhost:80/demo/storecards?select=code,name&expand=storemenuitem_id(select text, treepath(Parent_ID, '/' || text) as path)&where=code eq '48'
Odpověď:
[
{
"code": "48",
"name": "HDD Seagate 1 TB",
"storemenuitem_id": {
"text": "Počítač.komponenty",
"path": "/Hlavní činnost/Hardware/Počítač.komponenty"
}
}
]
Získání skladového menu tříděného za posindex pomocí rozšířeného dotazování na endpoint /query.
Tělo
body = {
"class": "storemenuitems",
"select": [
{
"name": "path",
"value": "treepath(parent_id, '/' || lpad(posindex, 3, '0'))",
},
],
"orderby": ["path"],
"take": 5,
"skip": 10,
}
Odpověď:
[
{
"path": "/001/002"
},
{
"path": "/001/002/001"
},
{
"path": "/001/002/002"
},
{
"path": "/001/002/003"
},
{
"path": "/001/003"
}
]
Získání cesty ve skladovém menu ke skladové kartě pomocí rozšířeného dotazování na endpoint /query.
Tělo:
body = {
"class": "storecards",
"select": [
{
"name": "storemenuitem_id",
"value": [{"name": "path", "value": "treepath(Parent_ID, ' / ' || text)"}],
},
],
"where": "code='48'",
}
Odpověď:
[
{
"storemenuitem_id": {
"path": " / Hlavní činnost / Hardware / Počítač.komponenty"
}
}
]