Pular para o conteúdo principal

Database

Fachada somente estática sobre o núcleo nativo SQLite (src/database/Database.class.ts). Todo método delega para a mesma conexão nativa subjacente — não há instância para construir, e não há new Database().

import { Database } from '@salve-software/react-native-salve-db';

Configuração

Database.configure(props: IConfigureProps): void

Abre (ou cria) o arquivo de banco de dados local e define as configurações de sync/auth. Deve ser chamado uma vez, antes de register, select/insert/update/delete, ou execute.

interface IConfigureProps {
name: string;
baseUrl?: string;
network?: { timeout: number };
credentials?: ICredentialsDefinition; // Apenas OAuth2 no MVP
walMode?: boolean; // padrão true
syncOnAppOpen?: boolean; // padrão true
background?: {
minimumInterval: number;
requiresNetwork?: boolean;
requiresCharging?: boolean;
};
}
Database.configure({
name: 'my-app.db',
baseUrl: 'https://api.example.com',
credentials: {
provider: 'oauth2',
tokens: { accessToken, refreshToken },
refresh: {
endpoint: '/auth/refresh',
response: { accessToken: '$.access_token', refreshToken: '$.refresh_token' },
},
},
background: { minimumInterval: 15 * 60 * 1000, requiresNetwork: true },
});

Database.register(props: IRegisterProps): Promise<void>

Registra um schema: cria sua tabela na primeira execução, ou aplica migrações ADD COLUMN pendentes se schema.version aumentou desde a última execução. Requer que configure já tenha sido executado. Lança erro se schema.name, schema.version, ou schema.primaryKey estiver ausente, ou se primaryKey não for uma chave em schema.columns.

interface IRegisterProps {
schema: AnySchema;
}
await Database.register({ schema: UserSchema });

Database.reset(): Promise<void>

Apaga todos os dados locais e credenciais — um logout completo. Limpa o usuário atual em memória (veja setCurrentUser abaixo) antes da limpeza nativa, independentemente de ela ter sucesso ou não. Após isso, register() de cada schema retoma o uso local; configure() novamente só é necessário para restaurar o sync.

await Database.reset();

Database.logout(): void

Limpa apenas os tokens de credenciais armazenados; dados locais, schemas e configuração permanecem intactos. Use para um logout normal. Limpa o usuário atual antes da chamada nativa, independentemente de ela ter sucesso ou não.

Database.logout();

Database.setCurrentUser(id: string): void

Registra o id do usuário atualmente logado, resolvido pelo helper currentUser() a nível de pacote (veja Operadores & Tipos) dentro de .where()/.values(). Chame novamente a cada cold start, assim que a própria sessão do app for reidratada — esse estado é apenas em memória, não é persistido por esta biblioteca. Lança erro se id estiver vazio ou em branco.

Database.setCurrentUser('user-123');

Database.getCurrentUser(): string | null

Leitura sem lançamento de erro do id do usuário atual, ou null se nenhum estiver definido.

const userId = Database.getCurrentUser();

Consultas (Queries)

Todo método de query retorna um builder escopado ao schema; nada é executado até que você chame .execute(). Veja Query Builder para a explicação completa e Operadores & Tipos para os operadores de condição de where() e os tipos de linha inferidos.

Database.select<TSchema>(schema: TSchema): ISelectQueryBuilder<TSchema>

Inicia um SELECT na tabela de schema.

interface ISelectQueryBuilder<TSchema> {
where(condition: Condition): this;
orderBy(column: keyof InferSelectModel<TSchema>, direction?: 'asc' | 'desc'): this;
limit(n: number): this;
offset(n: number): this;
execute(): InferSelectModel<TSchema>[];
}

execute() usa MAX_SYNC_PAGE_SIZE (500) como padrão de limit quando omitido, e lança erro se limit o excede. Toda coluna referenciada em where()/orderBy() precisa ser a coluna líder de um índice declarado (ou a chave primária) — veja o FAQ.

const rows = Database.select(UserSchema)
.where(eq('id', currentUser()))
.orderBy('createdAt', 'desc')
.limit(20)
.execute();

Database.insert<TSchema>(schema: TSchema): IInsertQueryBuilder<TSchema>

Inicia um INSERT na tabela de schema.

interface IInsertQueryBuilder<TSchema> {
values(row: InferInsertModel<TSchema> | InferInsertModel<TSchema>[]): this;
/** Upsert: em conflito de chave primária, sobrescreve toda outra coluna inserida com `excluded.col`. */
onConflictDoUpdate(): this;
execute(): void;
}

Um lote maior que MAX_BATCH_INSERT_ROWS (500 linhas) lança erro — veja o FAQ.

Database.insert(UserSchema)
.values({ id: '1', name: 'Ada', createdAt: Date.now() })
.execute();

Database.insert(UserSchema)
.values(rows)
.onConflictDoUpdate()
.execute();

Database.update<TSchema>(schema: TSchema): IUpdateQueryBuilder<TSchema>

Inicia um UPDATE na tabela de schema.

interface IUpdateQueryBuilder<TSchema> {
set(patch: Partial<InferInsertModel<TSchema>>): this;
where(condition: Condition): this;
execute(): void;
}
Database.update(UserSchema)
.set({ name: 'Ada Lovelace' })
.where(eq('id', '1'))
.execute();

Database.delete<TSchema>(schema: TSchema): IDeleteQueryBuilder<TSchema>

Inicia um DELETE na tabela de schema.

interface IDeleteQueryBuilder<TSchema> {
where(condition: Condition): this;
execute(): void;
}
Database.delete(UserSchema).where(eq('id', '1')).execute();

Database.count<TSchema>(schema: TSchema): ICountQueryBuilder<TSchema>

Inicia um COUNT(*) na tabela de schema.

interface ICountQueryBuilder<TSchema> {
where(condition: Condition): this;
execute(): number;
}
const total = Database.count(UserSchema).where(eq('active', true)).execute();

Database.transaction<T>(fn: (tx: IQueryClient) => T): T

Executa fn dentro de uma transação nativa BEGIN/COMMIT, revertendo (rollback) se fn lançar um erro. tx expõe a mesma superfície select/insert/update/delete/count/execute/ transaction que o próprio Database, escopada àquela transação.

interface IQueryClient {
select<TSchema>(schema: TSchema): ISelectQueryBuilder<TSchema>;
insert<TSchema>(schema: TSchema): IInsertQueryBuilder<TSchema>;
update<TSchema>(schema: TSchema): IUpdateQueryBuilder<TSchema>;
delete<TSchema>(schema: TSchema): IDeleteQueryBuilder<TSchema>;
count<TSchema>(schema: TSchema): ICountQueryBuilder<TSchema>;
transaction<T>(fn: (tx: IQueryClient) => T): T;
execute(sql: string, params?: unknown[]): unknown[];
}

Toda escrita dentro de tx ainda dispara os triggers normalmente — a fila de sync é populada no COMMIT, não em cada escrita isolada.

Database.transaction((tx) => {
tx.insert(OrderSchema).values(order).execute();
tx.update(UserSchema).set({ orderCount: count + 1 }).where(eq('id', userId)).execute();
});

Database.execute(sql: string, params?: unknown[]): unknown[]

Válvula de escape: executa SQL parametrizado bruto e retorna as linhas resultantes como objetos simples. Sem segurança de tipos ou inferência, mas como os triggers são definidos no nível de tabela do SQLite, o SQL bruto ainda é rastreado normalmente pela sync_queue.

const rows = Database.execute('SELECT * FROM users WHERE id = ?', ['1']);

Assinaturas de mudanças (Change subscriptions)

Database.subscribeToChanges(callback: (tables: string[]) => void): number

Assina notificações de escrita a nível de tabela (insert/update/delete — de qualquer origem: query builder, SQL bruto, migrações, ou sync em background). Retorna um id de assinatura, passe-o para unsubscribeFromChanges para parar de escutar. useQuery/useInfiniteQuery usam isso internamente — veja Hooks — prefira os hooks a menos que você precise de uma assinatura manual, fora do React.

const subId = Database.subscribeToChanges((tables) => {
if (tables.includes('users')) refreshUserList();
});

Database.unsubscribeFromChanges(id: number): void

Para uma assinatura previamente criada por subscribeToChanges.

Database.unsubscribeFromChanges(subId);

Sync

Veja Sync para o contrato completo de push/pull e resolução de conflitos.

Database.sync(schemaName: string): Promise<NativeSyncResult>

Dispara uma sessão de sync para um único schema.

await Database.sync('users');

Database.syncAll(): Promise<NativeSyncResult[]>

Dispara uma sessão de sync para todo schema registrado com sync.enabled.

await Database.syncAll();