Anuncios

Bienvenidos sean a este post, hoy veremos otra forma de almacenar nuestras notas en la aplicacion.

Anuncios

En el post anterior vimos como instalar sqlite3 para disponer de esta base de datos para nuestra aplicacion, para continuar con este tema vamos a necesitar el codigo de nuestra aplicacion notas sino lo poseen les dejo un link para descargarlo:

Anuncios

Una vez descargado el archivo simplemente extraigan el directorio en el PC y ya tenemos la aplicacion lista para ser usada, nuestro primer paso sera ingresar al directorio notas y aqui crearemos la base de sqlite3 y para ello ejecutaremos el siguiente comando:

$ sqlite3 notas.sqlite3
Anuncios

Esto nos abrira el programa y generara un archivo con ese nombre que representara a la base de datos, dentro del interprete ejecutaremos la siguiente secuencia:

$ sqlite3 notas.sqlite3
SQLite version 3.34.1 2021-01-20 14:10:07
Enter ".help" for usage hints.
sqlite> create table if not exists notas (
...> clave varchar(255),
...> titulo varchar(255),
...> cuerpo text
...> );
sqlite>
Anuncios
Anuncios

Primero ingresan la linea de create table, la cual creara la nueva tabla sino existe alguna previa y cuando presionen Enter les habilitara el nuevo prompt, en cada linea ingresaran los campos de nuestra nota, indicamos el tipo de dato que almacenara y la cantidad de caracteres que permitira salvo en cuerpo que usa uno generico para el texto, cuando lo cierren con el punto y coma, se creara la tabla y nos devolvera el prompt para trabajar, una forma de verificar si funciona es mediante el siguiente comando:

sqlite> .schema notas
Anuncios

Esto nos devolvera la sintaxis que usamos para crear la tabla, veamos la salida que nos devolvio::

sqlite> .schema notas
CREATE TABLE notas (
clave varchar(255),
titulo varchar(255),
cuerpo text
);
sqlite>
Anuncios

Ahora simplemente presionen Ctrl+D o mediante .exit para salir de sqlite3 y volver a nuestra aplicacion, pero antes de comenzar con la esta debemos instalar el modulo de sqlite3, para ello desde el directorio notas ejecuten el siguiente comando:

$ npm install sqlite3
Anuncios

Una vez finalizado podemos pasar a nuestro siguiente paso y este sera crear un nuevo archivo con el nombre de schema-sqlite3.sql en el directorio models, y le agregaremos el siguiente codigo:

models/schema-sqlite3.sql

CREATE TABLE IF NOT EXISTS notas (
clave varchar(255),
titulo varchar(255),
cuerpo text
);
Anuncios

En este caso es basicamente para crear nuestra tabla en caso de que no exista, nuestro siguiente paso sera ir al archivo package.json y en la seccion de scripts agregaremos la siguiente linea:

"sqlite3-setup": "sqlite3 notas.sqlite3 --init models/schema-sqlite3.sql"
Anuncios
Anuncios

Esta sera la encargada de iniciar nuestra tabla en la base de datos, llama a sqlite3, establece el nombre del archivo que sera la base y luego mediante init ejecutara el script que le pasemos, en este caso para generar la tabla en la base, lo malo de esto si lo utilizan es que nos deja en el programa sqlite3 y deben usar Ctrl + D o .exit para salir del mismo pero es una buena alternativa para generar la base y tabla automaticamente, con esto comentado vamos a trabajar en el codigo de nuestra aplicacion, para ello debemos ir al directorio models y crearemos un nuevo archivo con el nombre de notas-sqlite3.mjs y agregaremos el siguiente codigo:

models/notas-sqlite3.mjs

import util from 'util';
import { Nota, AlmacenNotasAbs } from './Notas.mjs';
import { default as sqlite3 } from 'sqlite3';
import { default as DBG } from 'debug';
const debug = DBG('notas:notas-sqlite3');
const error = DBG('notas:error-sqlite3');

let db;

async function conectarDB() {
if (db) return db;
const dbfile = process.env.SQLITE_FILE || "notas.sqlite3";
await new Promise((resolve, reject) => {
db = new sqlite3.Database(dbfile,
sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE,
err => {
if (err) return reject(err);
resolve(db);
});
});
return db;
}
Anuncios
Anuncios

Al comienzo importaremos todos los modulos que necesitemos, entre ellos lo de las notas asi como tambien los de sqlite3 y el de depuracion, la siguiente seran dos objetos que nos identificaran en la salida de depuracion si es una actividad o un error, luego tenemos la funcion que se encarga de conectarnos con la base de datos, para ello primero chequearemos si existe el objeto db, en caso de ser asi lo devuelve porque ya esta conectado, despues definimos una variable donde almacena el archivo donde esta la base, este puede informarse mediante una variable del sistema y sino informamos alguno usa como nombre predeterminado el del archivo que creamos anteriormente, con este valor establecido mediante una promesa estableceremos el objeto db donde mediante Database abriremos el archivo y lo usaremos para leer/escribir o crear, a este le analizaremos un error, en caso de existir lo pasamos como rechazado y devolveremos el error en particular, en caso de no presentarse lo damos como resuelto y esto nos da la posibilidad de devolver el objeto creado, tomemos el archivo y agreguemos el siguiente codigo:

export default class AlmacenNotasSQL3 extends AlmacenNotasAbs {
async cerrar() {
const _db = db;
db = undefined;
return _db ?
new Promise((resolve, reject) => {
_db.close(err => {
if (err) reject(err);
else resolve();
});
}) : undefined;
}
}
Anuncios
Anuncios

Esta sera la clase que se encargara de manejar las notas mediante sqlite3, para ello la establecemos como default dado que la fabrica del archivo notas-almacen.mjs lo extrae de esa forma, sobre esto hablamos en este post, y sera heredera de AlmacenNotasAbs que es una clase abstracta donde definiremos los «prototipos» de esta, en este caso definimos la primera funcion que es cerrar donde la usaremos para eliminar el objeto db o lo mismo que cerrar la conexion creada, observen que devolvemos el resultado de aplicar el operador condicional a la copia de nuestra conexion, para ello usaremos una promesa para al momento de cerrar la conexion evaluamos si existe algun error, en caso de ser verdadero usaremos a reject para informar porque se rechazo de lo contrario lo pasaremos como resolve, en cambio si el objeto db esta vacio procedemos a devolver un undefined porque no existe como tal, nuestro siguiente paso sera agregar las siguientes funciones en la clase:

        async update(clave, titulo, cuerpo) {
const db = await conectarDB();
const nota = new Nota(clave, titulo, cuerpo);
await new Promise((resolve, reject) => {
db.run("UPDATE notas " +
"SET titulo = ?, cuerpo = ? WHERE clave = ?",
[titulo, cuerpo, clave ], err => {
if (err) return reject(err);
resolve(nota);
});
});
return nota;
}

async create(clave, titulo, cuerpo) {
const db = await conectarDB();
const nota = new Nota(clave, titulo, cuerpo);
await new Promise((resolve, reject) => {
db.run("INSERT INTO notas (clave, titulo, cuerpo) " +
"VALUES (?, ?, ?);", [clave, titulo, cuerpo],
err => {
if (err) return reject(err);
resolve(nota);
});
});
return nota;
}
Anuncios
Anuncios

Estas dos funciones se encargan de modificar (update) e ingresar (create) nuevas notas, las dos son muy similares pero la diferencia estara marcada principalmente a la hora de manejar los datos, en ambos primero se conecta a la base, luego genera la nota con los valores recibidos, despues mediante una promesa usaremos al metodo run en el objeto de la base, en el caso de update le pasaremoe el comando sql de UPDATE para actualizar en la tabla notas los valores del titulo y el cuerpo, y en este caso la clave sera identificar cual debemos modificar, observen que en los tres casos usamos un signo de interrogacion para despues pasar los tres valores en el mismo orden para que se asignen a cada signo de interrogacion, despues usaremos una funcion de callback para verificar si hubo algun error, en caso de ser verdadero lo pasaremos a reject para rechazarlo e informar cual es, y en caso contrario pasaremos la nota como resuelto y luego lo devolveremos, en el caso de create con el metodo run usamos al comando sql INSERT INTO donde primero indicaremos los tres campos de la tabla para luego usar los signos de interrogacion para los valores, y al igual que el caso anterior pasamos los tres valores en el mismo orden que informamos, el caso del error es exactamente el mismo, ya tenemos lo suficiente para crear y modificar con lo cual podemos pasar a agregar la siguiente funcion:

        async read(clave) {
const db = await conectarDB();
const nota = await new Promise((resolve, reject) => {
db.get("SELECT * FROM notas where clave = ?",
[clave], (err, fila) => {
if (err) return reject(err);
const nota = new Nota(fila.clave, fila.titulo,
fila.cuerpo);
resolve(nota);
});
});
return nota;
}
Anuncios
Anuncios

Esta sera la encargada de buscar la nota con la clave que le pasemos, primero nos conectaremos a la base mediante la funcion conectarDB despues crearemos un objeto llamado nota y mediante una promesa haremos una busqueda y para ello usaremos el metodo get y a este le pasaremos un query mediante SELECT donde tomaremos todos los datos y le pasaremos la clave que recibimos como argumento, luego usaremos un funcion de callback y ahi tomaremos dos valores, el primero sera para cualquier error y la siguiente sera para la fila donde estan los datos, despues tenemos un condicional donde si ocurrio algun error lo pasaremos a reject para informar porque fallo, en caso contrario creara un nuevo objeto correspondiente a la nota pero esta vez sacaremos los datos de esta y lo pasaremos a resolve para permitirnos devolverlo como resuelto y al final de la funcion, observen un detalle que en las funciones anteriores usamos a run para ejecutar el query sin necesidad de obtener un resultado, en cambio debimos usar a get para obtener un resultado despues de ejecutado el query, pasemos a agregar la siguiente funcion:

        async delete(clave) {
const db = await conectarDB();
return await new Promise((resolve, reject) => {
db.run("DELETE FROM notas WHERE clave = ?",
[clave], err => {
if (err) return reject(err);
resolve();
});
});
}
Anuncios

Esta se encargara de borrar la nota en base a la clave que le pasemos, en estructura es muy similar a lo anterior donde se conecta y luego usa una promesa, en este caso volvemos a usar a run para usar el comando DELETE para eliminar la nota, observen que usamos una estructura similar con el signo de interrogacion y el valor pasado, volvemos a usar el callback con la misma estructura del primer caso porque no necesitamos devolver ningun valor, pasemos a agregar la siguiente funcion:

        async listarClaves() {
const db = await conectarDB();
const clavez = await new Promise((resolve, reject) => {
const clavez = [];
db.all("SELECT clave FROM notas", (err, filas) => {
if (err) return reject(err);
resolve(filas.map(fila => {
return fila.clave;
}));
});
});
return clavez;
}
Anuncios
Anuncios

Esta sera la encargada de listar solamente las claves de las notas, de vuelta tenemos una estructura similar, nos conectamos a la base despues usamos una promesa para obtener los valores pero a diferencia de read no usamos al metodo get sino el metodo all, esto es para que nos devuelva todas las filas y no solamente una o la primer coincidente con la consulta, observen que usamos a SELECT para que devuelva todas las claves de las notas y volvemos a aplicar una funcion de callback con el error y las filas, verificamos si hubo algun error y en caso de ser verdadero lo devolvemos con reject para informar cual fue, en caso contrario usamos un map para tomar todas las filas devueltas y las pasaremos a resolve para que este lo asigne al objeto original y lo podamos devolver, pasemos a agregar la ultima funcion que nos falta:

        async contar() {
const db = await conectarDB();
const contar = await new Promise((resolve, reject) => {
db.get("SELECT count(clave) as contar from notas",
(err, fila) => {
if (err) return reject(err);
resolve(fila.contar);
});
});
return contar;
}
Anuncios
Anuncios

Como en los casos anteriores volvemos a hacer lo mismo, en este caso volvemos a usar a get para obtener solamente el primer valor, pero en el query observen que usamos a count para contar las todos los valores en el campo de claves y le pondremos la etiqueta contar y en este caso la diferencia mas importante es al momento de resolver a favor donde usaremos la fila y le pasaremos la etiqueta que le asignamos a count para el valor devuelto, con esto ya tenemos nuestra clase terminada solo nos resta una modificacion mas y para ello deben ir al archivo package.json y en la seccion de scripts agreguen la siguiente linea:

"sql3-start": "cross-env SQLITE_FILE=notas.sqlite3 DEBUG=notas:* MODELO_NOTAS=sqlite3 node ./app.mjs"
Anuncios

Esta se encargara de permitirnos ejecutar a la aplicacion con nuestro nuevo modelo de notas asi como tambien especificamos cual debe ser el archivo de la base de datos, con esto pueden probarlo mediante el siguiente comando:

$ npm run sql3-start
Anuncios

Con esto pueden probar como funciona ahora nuestra aplicacion y este les debe permitir poder crear, editar, ver y borrar las notas pero ahora tienen la posibilidad de poder ver por fuera de la aplicacion, para ello en el directorio notas ejecuten lo siguiente:

$ sqlite3 notas.sqlite3
Anuncios

Este ingresara a la base y mediante el prompt que nos devuelve podemos hacer lo siguiente:

$ sqlite3 notas.sqlite3
SQLite version 3.34.1 2021-01-20 14:10:07
Enter ".help" for usage hints.
sqlite> select * from notas;
id0001|Primera nota|Nota de prueba
id0002|Segunda nota|Texto de la segunda nota
id0003|Tercer nota|Nota que corresponde a la tercera
id0004|Ultima nota|Esta es la ultima nota
sqlite>
Anuncios
Anuncios

En este caso utilice el comando select para que realice una consulta contra la base de datos y observen como nos devolvio todos los datos sin necesidad de tener que hacerlo mediante la aplicacion, como podran ver trabajamos con una base de datos SQL por lo tanto con muy pocas modificaciones podemos usarlo para realizar conexiones a otras bases de este estilo como pueden ser mariadb, mysql o el mismo sql, pero ese sera tema de otro post, antes de finalizar les dejo un link para un archivo con todos los archivos del proyecto asi como los trabajado en este post:

Anuncios

En resumen, hoy hemos visto otra forma de almacenar nuestras notas, en este caso lo haremos mediante sqlite3, esta es una base de datos de tipo SQL no tan completas como otras pero al tener funciones basicas pudimos ver como ejecutarlas, espero les haya sido de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Donación

Es para mantenimento del sitio, gracias!

$1.50