Crear una base de datos con IndexedBD
Tags: javascript, webdev, programming, 100daysofcode
Published: 2022-01-04 01:18:19

Antes de crear o abrir (_open_) una base de datos usando **IndexedDB** debemos verificar que el navegador tenga el soporte necesario, para esto creamos una función que usaremos luego a la hora de crear la base de datos:

```jsx
function indexedDBSupport(){
	return 'indexedDB' in window;
}
```

Luego, se realiza una petición (*request*) para *abrir* la base de datos que devuelve un evento (`success` o `error`) a través del objeto **IDBOpenDBRequest**, el cual nos va a permitir acceder al evento.

La function `open(name, version)` recibe dos parámetros, donde el primero es el nombre de la base de datos que permitirá identificarla dentro del navegador del cliente, el segundo parámetro es la versión de nuestra base datos, esto es importante ya que se definirá un _Database Schema_ que determinará la estructura de los objetos que se almacenarán, por lo que, si se desea cambiar, solo debemos cambiar la versión de nuestra base de datos.

```jsx
// Por defecto, el valor de la version es 1
const request = window.indexedDB.open("MyDatabase", 1);
```

## Manejo de eventos
Como se menciono anteriormente, una vez hecha la petición para crear o _abrir_ la base de datos se pueden manejar 3 eventos con sus respectivas funciones:

`onerror`: Si la creación o conexión a la base de datos falla.

`onsuccess`: Se ejecuta cada vez que se conecta o se crea la base de datos.

`onupgradeneeded`: Se ejecuta solo una vez, cuando se crea la base de datos o se actualiza, por lo que acá se definirá la estructura de la misma (*Database Schema*).

> 💡 Una vez hecha la petición, obtenemos el objeto IDBOpenDBRequest, en el cual está almacenado el resultado de dicha petición

```jsx
// Guardamos la conexion a la base de datos en una variable global
// ya que luego se usara para realizar transacciones
let db;

function createDatabase() {

	if (!indexedDBSupport()) throw new Error("Your browser doesn't support IndexedBD");

	const request = window.indexedDB.open('MyDatabase', 1);

// Manejo de eventos
	request.onerror = (e) => {
		console.error(`IndexedDB error: ${request.errorCode}`);
	};

	request.onsuccess = (e) => {
		console.info('Successful database connection');
		db = request.result;
	};

	request.onupgradeneeded = (e) => {
		console.info('Database created');
		const db = request.result;
		//...
	};

}
```

## Usando `onupgradeneeded`
Como se menciono anteriormente, este evento es lanzado cuando se crea la base de datos por primera vez o cuando se actualiza su versión, por lo que es el lugar ideal para especificar el _Database Schema_.

### Creando un _Object Store_ (tabla)
Debemos definir dónde se almacenarán los objetos para la versión actual de nuestra base de datos. Para esto creamos una instancia de **IDBObjectStore** (representa un almacén de objetos) usando el método `createObjectStore(name, options)`, que recibe los siguientes parámetros:

- `name`: Nombre de la “tabla” o almacén de objetos (_Object Store_).

- `options`:  Parámetro opcional que contiene los siguientes atributos:

    - `keyPath`: Especifica el nombre del atributo que contendrá el índice con el que identificará a cada objeto.
    - `autoIncrement`: Si el valor es `true` se le dará un valor incremental al `keyPath`.

```jsx
//...

request.onupgradeneeded = (e) => {

	console.info('Database created');

	const db = request.result;
	
	const objectStore = db.createObjectStore('student', {keyPath: 'email'})
};

//...
```

> 💡Si se desea actualizar el _Object Store_, debe tener en cuenta que este tendrá la nueva estructura, pero estará vacio, por lo que se seria buena idea que, antes de crear el nuevo _Object Store_, guarde los objetos en otro lugar para luego eliminar el _Object Store_ antiguo y reinsertarlos en el nuevo.

### Creando Indexes (campos o atributos)
Para crear “campos” (_index_) en una tabla (_Object Store_) se usa el método `createIndex(indexName, keyPath, options)` del objeto **IDBObjectStore**, que recibe los siguientes parámetros:
- `indexName`: Es el nombre con el cual se identificará al “campo” dentro de la tabla.
- `keyPath`: Es la propiedad del objeto que contendrá el valor del campo. La mayoría de veces el `indexName` y el `keyPath` tienen el mismo valor, ya que es lógico que el campo se llame igual que la propiedad que contendrá su valor.
- `options`: La propiedad más útil es `unique` que no permite que haya valores duplicados dentro de una mismo *index*.

```jsx
//...

request.onupgradeneeded = (e) => {

	console.info('Database created');

	const db = request.result;
	
	const objectStore = db.createObjectStore('student', {keyPath: 'email'});

	// Indices
	objectStore.createIndex("email", "email", { unique: true });
	objectStore.createIndex("name", "name", { unique: false });
	objectStore.createIndex("lastname", "lastname", { unique: false });
	objectStore.createIndex("age", "age", { unique: false });

};

//...
```
Como se trabaja en base a peticiones (request) podemos usar el evento `complete` para verificar que la transacción fue completada y se creo el _Object Store_ con éxito para realizar alguna acción luego, en caso sea necesario.

```jsx
//...

request.onupgradeneeded = (e) => {

	console.info('Database created');

	const db = request.result;
	
	const objectStore = db.createObjectStore('student', {keyPath: 'email'});

	// Indices
	objectStore.createIndex('email', 'email', { unique: true });
	objectStore.createIndex('name', 'name', { unique: false });
	objectStore.createIndex('lastname', 'lastname', { unique: false });
	objectStore.createIndex('age', 'age', { unique: false });

	// Transaccion completada
	objectStore.transaction.oncompleted = (e)=> {
		console.log('Object store "student" created');
	}

};

//...
```