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 - 2017 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 ArchivoNuevoProyecto 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 = this.connection.execute_select_command ("select * from demo"); } catch (e) { this.connection.execute_non_select_command ("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 los métodos de conexión 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 = 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>"; },

Línea 2: el comando SELECT. Se usa el método de conexión execute_select_command de GDA. 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.

Líneas 8‒9: se hacen dos cosas en cada lí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 los métodos de conexión 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.