# Colección de música (JavaScript)

Cree una pequeña aplicación con una base de datos para ordenar su colección de música
Proyecto de documentación de GNOME
gnome-doc-list@gnome.org
Johannes Schmid
jhs@gnome.org
Marta Maria Casetti
mmcasettii@gmail.com 2013
Daniel Mustieles
daniel.mustieles@gmail.com 2011 - 2014
Nicolás Satragno
nsatragno@gmail.com 2012 - 2013
Jorge González
jorgegonz@svn.gnome.org 2011

# Colección de música

      En este tutorial aprenderá:

        Cómo conectar con una base de datos usando libgda
        Cómo insertar y examinar registros en una tabla de una base de datos

# Introducción

Esta demostración usa el lenguaje Javascript. Se va a demostrar cómo conectar y usar una base de datos desde un programa GTK, usando la bilbioteca GDA («GNOME Data Access», Acceso a datos de GNOME). Por lo tanto, es necesario tener instalada también esta biblioteca.

Acceso a Datos de GNOME (GDA) es una biblioteca cuyo propósito es proporcionar acceso universal a diferentes tipos de fuentes de datos. Esto abarca desde los tradicionales sistemas de bases da datos relacionales hasta cualquier fuente de datos imaginable como un servidor de correo-e, un directorio LDAP, etc. Para obtener más información y una documentación completa de la API, visite la página web de GDA.

Aunque una gran parte del código se refiere a la interfaz de usuario (IU), el tutorial se enfocará a las partes de las bases de datos (aunque se puede hacer mención a otras partes que se consideren relevantes). Para aprender más sobre los programas en Javascript en GNOME, consulte el tutorial del programaVisor de Imágenes

# Crear un proyecto en Anjuta

Antes de empezar a programar, deberá configurar un proyecto nuevo en Anjuta. Esto creará todos los archivos que necesite para construir y ejecutar el código más adelante. También es útil para mantener todo ordenado.

Inicie Anjuta y pulse Archivo Nuevo Proyecto para abrir el asistente de proyectos.

Elija JavaScript genérico de la pestaña JS, pulse Adelante y rellene los detalles en las siguientes páginas. Use coleccion-de-albumes como nombre de proyecto y de carpeta.

Pulse Finalizar y se creará el proyecto. Abra src/main.js desde la pestaña Proyecto o Archivo. Contiene un ejemplo de código muy básico.

# Estructura del programa

Esta demostración es una aplicación GTK sencilla (con una única ventana) capaz de insertar registros en la tabla de una base de datos, así como de examinar todos los registros de la tabla. La tabla tiene dos campos: `id`, un entero, y `name`, un «varchar». La primera sección (en la parte superior) de la aplicación le permite insertar un registro en la tabla. La última sección (en la parte inferior) le permite ver todos los registros de la tabla. El contenido se actualiza cada vez que se insertar un registro y al inicio de la aplicación.

# Empezar la diversión

Empezar examinando el esqueleto del programa:

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 ();

Líneas 1‒4: importaciones iniciales. Preste especial atención a la línea 3, que indica a Javascript que importe la biblioteca GDA, nuestro objetivo en este tutorial.

Líneas 6‒17: definir la clase `Demo`. Preste especial atención a las líneas 13‒15, donde se llama a 3 métodos que harán todo el trabajo. Se detallarán más adelante.

Líneas 19‒23: iniciar la aplicación.

# Diseñar la aplicación

Eche un vistazo al método `setupWindow`. Es el responsable de crear la interfaz de usuario (IU). Ya que la IU no es el objetivo, sólo se explicarán las partes relevantes.

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; });

// main box var main_box = new Gtk.Box ({orientation: Gtk.Orientation.VERTICAL, spacing: 5}); this.window.add (main_box);

// first label var info1 = new Gtk.Label ({label: "<b>Insert a record</b>", xalign: 0, use_markup: true}); main_box.pack_start (info1, false, false, 5);

// "insert a record" horizontal box var insert_box = new Gtk.Box ({orientation: Gtk.Orientation.HORIZONTAL, spacing: 5}); main_box.pack_start (insert_box, false, false, 5);

// ID field 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);

// Name field 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);

// Insert button 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 ();

// Browse textview 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 (); },

Líneas 22 y 27: crear las dos entradas (para los dos campos) en las que el usuario escribirá algo para insertarlo en la base de datos.

Líneas 31‒34: crear el botón «Insertar». Se conecta su señal `clicked` con el método privado `_insertClicked` de la clase. Este método se detalla a continuación.

Línea 39: crear el widget (`TextView`) donde se mostrarán los contenidos de la tabla.

Línea 44: crear la etiqueta donde se mostrará el número de registros de la tabla. Inicialmente está vacía, se actualizará más tarde.

# Conectar e inicializar la base de datos

El código que hace la conexión con la base de datos está en método `setupDatabase` siguiente:

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 = Gda.execute_select_command (this.connection, "select * from demo"); } catch (e) { Gda.execute_non_select_command (this.connection, "create table demo (id integer, name varchar(100))"); } },

Líneas 2‒3: crear el objeto de GDA `Connection`. Se deben proporcionar a su constructor algunas propiedades:

`provider`: uno de los proveedores de GDA soportados. GDA soporta SQLite, MySQL, PostgreSQL, Oracle y muchos otros. Para la demostración se usará una base de datos SQLite, ya que viene instalada de manera predeterminada en la mayoría de las distribuciones y es fácil de usar (sólo usa un archivo como base de datos).

`cnc_string`: la cadena de conexión. Puede cambiar de un proveedor a otro. La sintaxis de SQLite es: `DB_DIR=PATH;DB_NAME=FILENAME`. En esta demostración se accederá a una base de datos llamada «gnome_demo» en la carpeta del usaurio (tenga en cuenta la llamada a la función `get_home_dir` de GLib).

Si GDA no soporta el proveedor, o si falta algún elemento en la cadena de conexión, la línea 2 elevará una excepción. Por esto, en la vida real hay que manejarlo con la sentencia `try`...`catch` de JavaScript.

Línea 4: abrir la conexión. En el proveedor de SQLite, si la base de datos no existe, se creará en este paso.

Líneas 6‒10: intentar hacer una selección simple para comprobar si la tabla existe. Si no existe (porque la base de datos se acaba de crear), este comando elevará una excepción, que se maneja en el bloque `try`...`catch` block. Si este es el caso, se ejecuta la sentencia para crear tabla (línea 9).

Para ejecutar los comandos SQL anteriores se usan las funcionas globales de GDA `execute_select_command` y `execute_non_select_command`. Son fáciles de usar, y sólo requieren dos argumentos: el objeto `Connection` y el comando SQL que analizar.

En este punto, ya está configurada la base de datos y lista para usarse.

# Seleccionar

Después de conectar a la base de datos, el constructor de la demostración llama al método `selectData`. Es el responsable de obtener todos los registros de la tabla y de mostrarlos en el widget `TextView`. Échele un vistazo:

selectData: function () { var dm = Gda.execute_select_command (this.connection, "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>"; },

Línea 2: el comando `SELECT`. Se usan funciones la función global de GDA `execute_select_command`. Devuelve un objeto `DataModel`, que se usa más tarde para obtener las filas.

Línea 3: crear un objeto `Iter`, que se usa para iterar sobre los registros de `DataModel`.

Línea 7: recorrer todos los registros, recuperándolos con la ayuda del objeto `Iter`. En este punto, la variable `iter` contiene los datos obtenidos actualmente. Su método `move_next` devuelve `false` cuando se alcanza el último registro.

Líneas 8‒9: se hacen dos cosas en cada línea:

Use el método `get_value_at` de `Iter`, que sólo necesita un argumento: el número de columna que recuperar, empezando por 0. Ya que el comando `SELECT` sólo devuelve dos columnas, se están recuperando las columnas 0 y 1.

El método `get_value_at` devuelve el campo en el formato `GValue` de GLib. Una manera sencilla de convertir este valor en una cadena es usar la función global de GDA `value_stringify`. Es lo que se está haciendo aquí, y el resultado se almacena en las variables `id_field` y `name_field`.

Línea 11: concatenar los dos registros para formar una línea de texto, separados por `"=>"`, y almacenarla en la variable `text`.

Línea 14: cuando termine el bucle, se tendrán todos los registros formateados en la variable `text`. En esta línea, simplemente se establece el contenido del `TextView` con esta variable.

Línea 15: mostrar el número de registros en la tabla, usando el método `get_n_rows` de `DataModel` `get_n_rows`.

# Insertar

Bien, ahora ya sabe cómo conectarse a la base de datos y cómo seleccionar filas de una tabla. Ahora es el momento de hacer un `INSERT` en la tabla. ¿Recuerda cuando antes, en el método `setupWindow`, se conectó la señal `clicked` del botón Insertar al método `_insertClicked`?. Vea la implementación de este método.

_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 (); },

Se ha aprendido a usar las funciones de conveniencia de GDA `execute_select_command` y `execute_non_select_command` para ejecutar comandos SQL rápidamente en la base de datos. GDA le permite construir una sentencia SQL de manera indirecta, usando su objeto `SqlBuilder`. ¿Cuáles son los beneficios de esto? GDA generará la sentencia SQL dinámicamente, y será válida para el proveedor de la conexión usado (usará el mismo dialecto de SQL que usa el proveedor). Estudie el código:

Líneas 2‒3: comprobar si el usuario ha rellenado todos los campos. El código del método privado `_validateFields` es realmente simple y puede leerlo en el código fuente completo de la demostración.

Línea 5: la manera más rápida de hacer el `INSERT`. Se ha comentado que se quiere mostrar cómo usar el objeto `SqlBuilder` para construir una sentencia SQL portable entre bases de datos.

Línea 7: crear el objeto `SqlBuilder`. Se debe pasar el tipo de sentencia que se va a construir. Puede ser `SELECT`, `UPDATE`, `INSERT` o `DELETE`.

Línea 8: establecer el nombre de la base de datos en la que operará la sentencia construida (generará `INSERT INTO demo`)

Líneas 9‒10: establecer los campos que formarán parte de la sentencia y sus valores. El primer argumento es el nombre del campo (como aparece en la tabla). El segundo es el valor de este campo.

Línea 11: obtener el objeto `Statement` generado dinámicamente, que representa una sentencia SQL.

Línea 12: finalmente, ejecutar la sentencia SQL (`INSERT`).

Línea 14: limpiar los campos «id» y «name» en la pantalla. El código del método privado `_clearFields` es muy sencillo, y puede leerlo en el código fuente de la demostración completa.

Línea 15: actualizar la vista en la pantalla haciendo otro `SELECT`.

También puede usar parámetros mientras construye la sentencia. Usando objetos y parámetros `SqlBuilder` será menos susceptible a ataques de inyección de SQL. Para obtener información adicional sobre los parámetros, consulte la documentación de GDA.

# Ejecutar la aplicación

Todo el código que necesita debe estar en su lugar, así que trate de ejecutar el código. Ahora tiene una base de datos para su colección de registros.

# Implementación de referencia

Si tiene problemas con este tutorial, compare su código con este código de referencia.