Implementando persistência/banco de dados a um aplicativo react-native
Tags: sqlite, reactnative, javascript, braziliandevs
Published: 2024-03-04 02:33:53

Neste artigo eu compartilho como implementar persistência local com react-native com expo, usando sqlite que é o banco de dados nativo para android.

## Requisitos 
- React-native
- expo
- expo-sqlite

## Instalando e importando

Primeiramente vamos usar a lib 'expo-sqlite'. O comando usado para instalar é:

```
npx expo install expo-sqlite
```
Pode-se importar da seguinte forma:

```
import * as SQLite from 'expo-sqlite'
```

## Criando e Conectando com Banco de dados

Para abrir um banco de dados ou criar, caso o banco não exista se usa a função OpenDatabase.
```
db = SQLite.openDatabase("myDatabase.db")
```

Para facilitar a forma como se obtém a a conexão e não ter que ficar repetindo o nome do banco em todos os lugares que tiver que fazer essa conexão, pode-se encapsular em uma função da seguinte forma:

```
export function getDBConnection() {
    let db = null
    try{ 
        db = SQLite.openDatabase("myDatabase.db")
    }
    catch(error){
        console.log("error openDatabase:", error)
    }
    return db
}
```

## Criando tabelas

Assim que se cria o banco o próximo passo é criar as tabelas, abaixo temos um exemplo de código onde se cria as tabelas caso elas não existam no banco de dados. Para isso é feita a conexão com o banco primeiro e a criação das tabelas é feita na mesma transação.

```
export function initDB(){
    
    try{
        const db = getDBConnection()
        if(db){
            
            // Execute consultas SQL para criar tabelas
            db.transaction(tx => {

                // Cria a tabela Subject
                tx.executeSql(
                    'CREATE TABLE IF NOT EXISTS Subject (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, start_time TEXT, end_time TEXT)',[], ()=>{console.log("successful create Subject")}, ()=>{console.log("error: create Subject")})

                // Cria a tabela Student
                tx.executeSql(
                    'CREATE TABLE IF NOT EXISTS Student (id INTEGER PRIMARY KEY, name TEXT)',[], ()=>{console.log("successful create Student")}, ()=>{console.error("error: create Student")});
        
                // Cria a tabela Machine
                tx.executeSql(
                    'CREATE TABLE IF NOT EXISTS Machine (id INTEGER PRIMARY KEY, is_available INTEGER)',[], ()=>{console.log("successful create Machine")}, ()=>{console.error("error: create Machine")})
                
                // Cria a tabela Loan   
                tx.executeSql(
                    'CREATE TABLE IF NOT EXISTS Loan (id INTEGER PRIMARY KEY AUTOINCREMENT, student INTEGER, machine INTEGER, subject INTEGER, loan_time TEXT, devolution_time TEXT, FOREIGN KEY (student) REFERENCES Student(id) ON DELETE NO ACTION, FOREIGN KEY (machine) REFERENCES Machine(id) ON DELETE NO ACTION, FOREIGN KEY (subject) REFERENCES Subject(id) ON DELETE NO ACTION)',[], ()=>{console.log("successful create Loan")}, ()=>{console.error("error: create Loan")});
                

                tx.executeSql(
                    'CREATE TABLE IF NOT EXISTS Student_Subject (student INTEGER, subject INTEGER, PRIMARY KEY (student, subject), FOREIGN KEY (student) REFERENCES Student(id), FOREIGN KEY (subject) REFERENCES Subject(id))',[], ()=>{console.log("successful create Student_Subject")}, ()=>{console.error("error: create Student_Subject")});

                    
                }, (error) =>{ console.error("error transition: ",error)},
                    ()=> { console.log('successful transition initDB')
                 
                })

    }
    }catch(error){
        console.log("error openDB", error)
    }
}
```

## Aprofundando na criação de tabela

```
if(db){           
 // Execute consultas SQL para criar tabelas
 db.transaction(tx => {
 // Operações no banco 
 }, (error) =>{ console.error("error transition: ",error)},
    ()=> { console.log('successful transition initDB')
}

```

Primeiramente é interessante verificar se o a conexão foi estabelecida, então eu verifico com o if(db) se for nulo e por que a conexão não foi estabelecida.

após isso uso a função transaction do db:

A função pode ser descrita com:

```
db.transaction(callback transaction, callback error, callback successful)
```
ou 
```
SQLiteDatabase.transaction(callback: SQLite.SQLTransactionCallback, errorCallback?: SQLite.SQLTransactionErrorCallback | undefined, successCallback?: (() => void) | undefined)
```

O primeiro callback é onde ocorre as operações com o banco, após isso tem um callback de erro onde se pode tratar o erro no caso mostrado aqui foi feito apenas um log para verificar se está ocorrendo e o ultimo argumento é o callback de sucesso, quando as operações são bem sucedidas, nessa aplicação também é feito apenas um log.


## Operações com o banco - SQL

```
db.transaction(tx => {

                // Cria a tabela Subject
                tx.executeSql(
                    'CREATE TABLE IF NOT EXISTS Subject (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, start_time TEXT, end_time TEXT)',
                    [],
                    ()=>{console.log("successful create Subject")},
                    ()=>{console.log("error: create Subject")})

...
```
O callback tem um parâmetro que é um objeto de transação (SQLite.SQLTransaction) e com esse objeto você pode usar a função 
executeSql que utiliza a linguagm [SQL](https://pt.wikipedia.org/wiki/SQL) (Structured Query Language) para fazer operações com o banco. Essa função recebe três parâmetros

```
tx.executeSql( string SQL, list params to SLQ, callback successful, callback error )
```
ou
```
SQLTransaction.executeSql(sqlStatement: string, args?: SQLite.SQLStatementArg[] | undefined, callback?: SQLite.SQLStatementCallback | undefined, errorCallback?: SQLite.SQLStatementErrorCallback | undefined): void
```
No exemplo que estou usando a lista de argumentos para o SQL está vazio pois na criação não precisamos passar nenhum argumento, os callbacks de sucesso e de erro aqui também só estação mostrando logs.

Um exemplo de quando se passa os argumentos para a lista de argumentos pode ser visto abaixo.
 
```
tx.executeSql(
            'INSERT INTO Subject (name, start_time, end_time) VALUES (?, ?, ?)',
            [name, startTime, endTime],
            (tx, results) => {
                console.log('Item adicionado com sucesso!', results);
                if(callback){
                 callback(results)
                }
            },
            (tx, error) => {
                console.error('Erro ao adicionar o item:', error);
            }
        );
```

aqui a lista 






 
## Referências

[MissCoding - Local SQLite Database for Expo React Native App](https://www.youtube.com/watch?v=1kSLd9oQX7c&t=243s)