1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
|
<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="record-collection.js" xml:lang="cs">
<info>
<title type="text">Sbírka alb (JavaScript)</title>
<link type="guide" xref="js#examples"/>
<desc>Jak vytvořit malou databázovou aplikaci pro roztřídění vaší hudební sbírky.</desc>
<revision pkgversion="0.1" version="0.1" date="2011-02-22" status="review"/>
<credit type="author">
<name>Dokumentační projekt GNOME</name>
<email its:translate="no">gnome-doc-list@gnome.org</email>
</credit>
<credit type="author">
<name>Johannes Schmid</name>
<email its:translate="no">jhs@gnome.org</email>
</credit>
<credit type="editor">
<name>Marta Maria Casetti</name>
<email its:translate="no">mmcasettii@gmail.com</email>
<years>2013</years>
</credit>
</info>
<title>Sbírka alb</title>
<synopsis>
<p>V této lekci se seznámíme s následujícími věcmi:</p>
<list>
<item><p>Jak se připojit k databázi pomocí libgda.</p></item>
<item><p>Jak vložit záznam do databázové tabulky a jak záznamy procházet.</p></item>
</list>
</synopsis>
<section id="intro">
<title>Úvod</title>
<p>Tato ukázka používá programovací jazyk JavaScript. Budeme předvádět připojení k databázi a její použití z programu GTK pomocí knihovny GDA (GNOME Data Access). Z toho důvodu potřebujete mít tuto knihovnu nainstalovanou.</p>
<p>GNOME Data Access (GDA) je knihovna, jejímž učelem je poskytovat univerzální přístup do různých druhů a typů datových zdrojů. Ty sahají od tradičních relačních databázových systémů až po jakékoliv představitelné datové zdroje, jako je poštovní server nebo adresář LDAP. Více informací a ucelenou dokumentaci k API najdete na <link href="http://library.gnome.org/devel/libgda/stable/">webových stránkách GDA</link>.</p>
<p>Přestože velká část kódu souvisí s uživatelským rozhraním, hodláme zaměřit tuto lekci na databázovou část (i když jiné části můžeme též zmínit, pokud uvidíme nějakou souvislost). Jestli se chcete dozvědět více o programování v jazyce JavaScript v GNOME, podívejte se na lekci <link xref="image-viewer.js">Prohlížeč obrázků</link>.</p>
</section>
<section id="anjuta">
<title>Vytvoření projektu ve studiu Anjuta</title>
<p>Než začnete s kódováním, musíte ve studiu Anjuta vytvořit nový projekt. Tím se vytvoří všechny soubory, které budete později potřebovat k sestavení a spuštění kódu. Je to také užitečné kvůli udržení všeho pohromadě.</p>
<steps>
<item>
<p>Spusťte IDE Anjuta a klikněte na <guiseq><gui>Soubor</gui> <gui>Nový</gui> <gui>Projekt</gui></guiseq>, aby se otevřel průvodce projektem.</p>
</item>
<item>
<p>Na kartě <gui>JS</gui> zvolte <gui>Obecný JavaScript</gui>, klikněte na <gui>Pokračovat</gui> a na několika následujících stránkách vyplňte své údaje. Jako název projektu a složky použijte <file>record-collection</file>.</p>
</item>
<item>
<p>Klikněte na <gui>Dokončit</gui> a vytvoří se vám projekt. Otevřete <file>src/main.js</file> na kartě <gui>Projekt</gui> nebo <gui>Soubor</gui>. Měl by obsahovat úplně základní příklad kódu.</p>
</item>
</steps>
</section>
<section id="structure">
<title>Struktura programu</title>
<media type="image" mime="image/png" src="media/record-collection.png"/>
<p>Tato ukázka je jednoduchou aplikací GTK (s jedním oknem) se schopností vkládat záznamy do databázové tabulky a procházet je. Tabulka má dvě pole: <code>id</code> (celé číslo) a <code>name</code> (varchar). V první části aplikace (nahoře) můžete vkládat záznamy do tabulky. V poslední části (dole) můžete vidět všechny záznamy v tabulce. Zobrazení obsahu se aktualizuje pokaždé, když je vložen nový záznam a při spuštění aplikace.</p>
</section>
<section id="start">
<title>Začíná zábava</title>
<p>Začněme prozkoumáním kostry programu:</p>
<code mime="application/javascript" style="numbered">
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Gda = imports.gi.Gda;
const Lang = imports.lang;
function Demo () {
this._init ();
}
Demo.prototype = {
_init: function () {
this.setupWindow ();
this.setupDatabase ();
this.selectData ();
}
}
Gtk.init (null, null);
var demo = new Demo ();
Gtk.main ();</code>
<list>
<item><p>Řádek 1 – 4: Inicializační importy. Zvláštní pozornost věnujte řádku 3, který říká, aby JavaScript naimportovat knihovnu GDA, na kterou se tato lekce zaměřuje.</p></item>
<item><p>Řádek 6 – 17: Definuje naši třídu <code>Demo</code>. Zvláštní pozornost věnujte řádkům 13 – 15, kde se volají 3 metody, které udělají celou práci. Podrobněji to bude vysvětleno dále.</p></item>
<item><p>Řádek 19 – 23: Spuštění aplikace.</p></item>
</list>
</section>
<section id="design">
<title>Návrh aplikace</title>
<p>Podívejme se na metodu <code>setupWindow</code>. Ta zodpovídá za vytvoření uživatelského rozhraní. Protože uživatelským rozhraním se teď nezabýváme, vysvětlíme si jen podstatné části.</p>
<code mime="application/javascript" style="numbered">
setupWindow: function () {
this.window = new Gtk.Window ({title: "Data Access Demo", height_request: 350});
this.window.connect ("delete-event", function () {
Gtk.main_quit();
return true;
});
// Hlavní box
var main_box = new Gtk.Box ({orientation: Gtk.Orientation.VERTICAL, spacing: 5});
this.window.add (main_box);
// První popisek
var info1 = new Gtk.Label ({label: "<b>Insert a record</b>", xalign: 0, use_markup: true});
main_box.pack_start (info1, false, false, 5);
// Vodorovný box pro "Insert a record"
var insert_box = new Gtk.Box ({orientation: Gtk.Orientation.HORIZONTAL, spacing: 5});
main_box.pack_start (insert_box, false, false, 5);
// Pole ID
insert_box.pack_start (new Gtk.Label ({label: "ID:"}), false, false, 5);
this.id_entry = new Gtk.Entry ();
insert_box.pack_start (this.id_entry, false, false, 5);
// Pole Name
insert_box.pack_start (new Gtk.Label ({label: "Name:"}), false, false, 5);
this.name_entry = new Gtk.Entry ({activates_default: true});
insert_box.pack_start (this.name_entry, true, true, 5);
// Tlačítko Insert
var insert_button = new Gtk.Button ({label: "Insert", can_default: true});
insert_button.connect ("clicked", Lang.bind (this, this._insertClicked));
insert_box.pack_start (insert_button, false, false, 5);
insert_button.grab_default ();
// TextView pro prohlížení
var info2 = new Gtk.Label ({label: "<b>Browse the table</b>", xalign: 0, use_markup: true});
main_box.pack_start (info2, false, false, 5);
this.text = new Gtk.TextView ({editable: false});
var sw = new Gtk.ScrolledWindow ({shadow_type:Gtk.ShadowType.IN});
sw.add (this.text);
main_box.pack_start (sw, true, true, 5);
this.count_label = new Gtk.Label ({label: "", xalign: 0, use_markup: true});
main_box.pack_start (this.count_label, false, false, 0);
this.window.show_all ();
},</code>
<list>
<item><p>Řádky 22 a 27: Vytvoří 2 vstupní pole (pro dvě databázová pole), do kterých uživatel bude psát to, co chce do databáze vložit.</p></item>
<item><p>Řádek 31 – 34: Vytvoří tlačítko „Insert“. Jeho signál <code>"clicked"</code> napojíme na soukromou metodu <code>_insertClicked</code> třídy. Tato metoda je podrobněji rozebrána níže.</p></item>
<item><p>Řádek 39: Vytvoří widget (<code>TextView</code>), ve kterém budeme zobrazovat obsah tabulky.</p></item>
<item><p>Řádek 44: Vytvoří popisek, ve kterém budeme zobrazovat počet záznamů v tabulce. Na začátku je prázdný, později bude aktualizován.</p></item>
</list>
</section>
<section id="connect">
<title>Připojení k databázi a její inicializace</title>
<p>Kód, který provádí připojení do databáze je v metodě <code>setupDatabase</code> níže:</p>
<code mime="application/javascript" style="numbered">
setupDatabase: function () {
this.connection = new Gda.Connection ({provider: Gda.Config.get_provider("SQLite"),
cnc_string:"DB_DIR=" + GLib.get_home_dir () + ";DB_NAME=gnome_demo"});
this.connection.open ();
try {
var dm = this.connection.execute_select_command ("select * from demo");
} catch (e) {
this.connection.execute_non_select_command ("create table demo (id integer, name varchar(100))");
}
},</code>
<list>
<item>
<p>Rádky 2 – 3: Vytvoří objekt <code>Connection</code> z knihovny GDA. Jeho konstruktoru musíme poskytnout některé vlastnosti:</p>
<list>
<item>
<p><code>provider</code>: Jeden z podporovaných poskytovatelů v knihovně GDA. Podporovány jsou SQLite, MySQL, PostgreSQL, Oracle a řada dalších. Pro předváděcí účely použijeme databázi SQLite, protože je standardně předinstalovaná ve většině distribucí a je jednoduchá na používání (prostě používá soubor jako databázi).</p>
</item>
<item>
<p><code>cnc_string</code>: Připojovací řetězec. Může si lišit poskytovatel od poskytovatele. Pro SQLite je syntax: <code>DB_DIR=<var>CESTA</var>;DB_NAME=<var>NÁZEV_SOUBORU</var></code>. V této ukázce přistupujeme k databázi s názvem gnome_demo v domovské složce uživatele (všimněte si volání funkce <code>get_home_dir</code>).</p>
</item>
</list>
<note>
<p>V případě, že poskytovatel není v GDA podporován nebo že v připojovacím řetězci schází nějaká část, vyvolá řádek 2 výjimku. V reálném použití bychom ji měli obsloužit konstrukcí <code>try</code> … <code>catch</code> jazyka JavaScript.</p>
</note>
</item>
<item><p>Řádek 4: Otevře připojení. U poskytovatele SQLite, když databáze neexistuje, dojde v tomto kroku k jejímu vytvoření.</p></item>
<item>
<p>Řádky 6 – 10: Zkusí udělat jednoduchý dotaz, aby se ověřilo, že tabulka existuje (řádek 7). Pokud neexistuje (protože databáze byla teprve vytvořena), vyvolá tento příkaz výjimku, která se obslouží v bloku <code>try</code> … <code>catch</code>. V tomto případě provedeme příkaz, který tabulku vytvoří (řádek 9).</p>
<p>Ke spuštění příkazů SQL výše používáme metody připojení GDA s názvem <code>execute_select_command</code> a <code>execute_non_select_command</code>. Ty jsou jednoduché na použití a požadují jen dva argumenty: objekt <code>Connection</code> a příkaz SQL, který se má zpracovat.</p>
</item>
</list>
<p>V tuto chvíli máme vytvořenu databázi a jsme připraveni ji použít.</p>
</section>
<section id="select">
<title>Vybírání</title>
<p>Po připojení do databáze konstruktor v naší ukázce zavolá metodu <code>selectData</code>. Ta zodpovídá za získání všech záznamů z tabulky a jejich zobrazení ve widgetu <code>TextView</code>. Pojďme se na to podívat:</p>
<code mime="application/javascript" style="numbered">
selectData: function () {
var dm = this.connection.execute_select_command ("select * from demo order by 1, 2");
var iter = dm.create_iter ();
var text = "";
while (iter.move_next ()) {
var id_field = Gda.value_stringify (iter.get_value_at (0));
var name_field = Gda.value_stringify (iter.get_value_at (1));
text += id_field + "\t=>\t" + name_field + '\n';
}
this.text.buffer.text = text;
this.count_label.label = "<i>" + dm.get_n_rows () + " record(s)</i>";
},</code>
<list>
<item><p>Řádek 2: Příkaz <code>SELECT</code>. K tomu používáme metodu připojení GDA s názvem <code>execute_select_command</code>. Vrací objekt <code>DataModel</code>, který je později použit k získání řádků.</p></item>
<item><p>Řádek 3: Vytvoří objekt <code>Iter</code>, který se používá k procházení záznamů v <code>DataModel</code>.</p></item>
<item><p>Řádek 7: Ve smyčce prochází všechny záznamy, které získává pomocí objektu <code>Iter</code>. V totmo místě proměnná <code>iter</code> obsahuje aktuálně získaná data. Jeho metoda <code>move_next</code> vrací <code>false</code>, když je dosažen poslední záznam.</p></item>
<item>
<p>Řádek 8 – 9: Na každém řádku děláme dvě věci:</p>
<list>
<item><p>Použijeme metodu <code>get_value_at</code> třídy <code>Iter</code>, která požaduje jen jeden argument: číslo sloupce, který se má získat, počítáno od 0. Náš příkaz <code>SELECT</code> vrací dva sloupce, takže získáváme sloupce 0 a 1.</p></item>
<item><p>Metoda <code>get_value_at</code> vrací pole ve formátu <code>GValue</code> knihovny GLib. Jednoduchým způsobem, jak převést tento formát na řetězec, je použít globální funkci knihovny GLib <code>value_stringify</code>. Což je přesně to, co zde děláme a výsledky pak uložíme do proměnných <code>id_field</code> a <code>name_field</code>.</p></item>
</list>
</item>
<item><p>Řádek 11: Spojí dvě pole, aby vytvořila jeden textový řádek, přičemž jsou oddělená pomocí <code>"=>"</code>, a uloží je do proměnné <code>text</code>.</p></item>
<item><p>Řádek 14: Když je smyčka dokončená, máme všechny záznamy naformátované v proměnné <code>text</code>. V tomto řádku pomocí ní nastavíme obsah widgetu <code>TextView</code>.</p></item>
<item><p>Řádek 15: Zobrazí počet záznamů v tabulce pomocí metody <code>get_n_rows</code> objektu <code>DataModel</code>.</p></item>
</list>
</section>
<section id="insert">
<title>Vkládání</title>
<p>Nuže, nyní víme, jak se připojit k databázi a jak vybrat řádky z tabulky. Nyní je čas na vkládání do tabulky pomocí <code>INSERT</code>. Pamatujete si z dřívějška, jak jsem v metodě <code>setupWindow</code> napojili signál <code>"clicked"</code> od tlačítka <gui>Insert</gui> na metodu <code>_insertClicked</code>? Pojďme se podívat na implementaci této metody.</p>
<code mime="application/javascript" style="numbered">
_insertClicked: function () {
if (!this._validateFields ())
return;
// Gda.execute_non_select_command (this.connection,
// "insert into demo values ('" + this.id_entry.text + "', '" + this.name_entry.text + "')");
var b = new Gda.SqlBuilder ({stmt_type:Gda.SqlStatementType.INSERT});
b.set_table ("demo");
b.add_field_value_as_gvalue ("id", this.id_entry.text);
b.add_field_value_as_gvalue ("name", this.name_entry.text);
var stmt = b.get_statement ();
this.connection.statement_execute_non_select (stmt, null);
this._clearFields ();
this.selectData ();
},</code>
<p>Naučili jsme se, jako používat metody připojení GDA s názvy <code>execute_select_command</code> a <code>execute_non_select_command</code>, které slouží k rychlému provedení příkazů SQL v databázi. GDA umožňuje vytvořit výraz SQL nepřímo, pomocí jejího objektu <code>SqlBuilder</code>. Jaké to přináší výhody? GDA vygeneruje výraz SQL dynamicky a ten bude platný pro použitého poskytovatele připojení (použije se varianta SQL, kterou používá onen poskytovatel). Pojďme se podívat na kód:</p>
<list>
<item><p>Řádky 2 – 3: Zkontroluje se, jestli uživatel vyplnil všechna pole. Kód soukromé metody <code>_validateFields</code> je opravdu jednoduchý a můžete si jej přečíst v kompletním kódu této ukázky.</p></item>
<item><p>Řádek 5: Rychlejší způsob, jak provést <code>INSERT</code>. Zde je zakomentováno, protože chceme ukázat, jak použít objekt <code>SqlBuilder</code> k sestavení výrazu SQL přenositelného mezi databázemi.</p></item>
<item><p>Řádek 7: Vytvoří objekt <code>SqlBuilder</code>. Musíme předat typ výrazu, který se chystáme sestavit. Může to být <code>SELECT</code>, <code>UPDATE</code>, <code>INSERT</code> nebo <code>DELETE</code>.</p></item>
<item><p>Řádek 8: Nastaví název tabulky, nad kterou bude sestavený výraz operovat (vygeneruje <code>INSERT INTO demo</code>)</p></item>
<item><p>Řádek 9 – 10: Nastaví pole a jejich hodnoty, které budou součástí výrazu. První argument je název pole (tak, jak je v tabulce). Druhý je hodnota pro toto pole.</p></item>
<item><p>Řádek 11: Získá dynamicky vygenerovaný objekt <code>Statement</code>, který představuje výraz SQL.</p></item>
<item><p>Řádek 12: Nakonec se provede výraz SQL (<code>INSERT</code>).</p></item>
<item><p>Řádek 14: Smaže pole id a name na obrazovce. Kód pro soukromou metodu <code>_clearFields</code> je opravdu jednoduchý a můžete si jej přečíst v kompletním zdrojovém kódu ukázky.</p></item>
<item><p>Řádek 15: Aktualizuje zobrazení na obrazovce provedením jiného výrazu <code>SELECT</code>.</p></item>
</list>
<note><p>Můžete také použít parametrické sestavení výrazu. Pomocí objektů <code>SqlBuilder</code> a parametrů budu výrazy méně náchylné k útokům, jako je SQL injection. Na další informace o parametrech se podívejte do <link href="http://library.gnome.org/devel/libgda/stable/">dokumentace k GDA</link>.</p></note>
</section>
<section id="run">
<title>Spuštění aplikace</title>
<p>Všechen kód, který potřebujete, je již na svém místě, takže jej pojďme zkusit spustit. Nyní máte databázi pro svoji sbírku alb.</p>
</section>
<section id="impl">
<title>Ukázková implementace</title>
<p>Pokud v této lekci narazíte na nějaké problémy, porovnejte si svůj kód s tímto <link href="record-collection/record-collection.js">ukázkovým kódem</link>.</p>
</section>
</page>
|