1.0.0 • Published 9 months ago

reactite v1.0.0

Weekly downloads
-
License
MIT
Repository
github
Last release
9 months ago

reactite

reactite is a powerful and lightweight ORM designed specifically for React Native applications using SQLite3. It simplifies database management, offering a seamless way to interact with SQLite databases within your React Native apps.

Table of Contents

Key Features

  • Type-Safe API: Ensures that database operations are type-checked at compile time, reducing runtime errors and enhancing code reliability.
  • Easy Setup: Simplifies database setup and configuration with minimal boilerplate code.
  • React Integration: Provides hooks and context-based components for easy integration with React Native, making it straightforward to access and manage database connections.
  • Schema Management: Includes tools for defining and managing database schemas, allowing you to create, update, and manage tables effortlessly.
  • Flexible Configuration: Offers customizable options to tailor database behavior to your specific needs, including support for timestamps and connection settings.

Installation

To install Reactite, run one of the following commands based on your package manager:

# Using Yarn
yarn add reactite

# Using npm
npm install reactite

# Using pnpm
pnpm install reactite

Getting started

After installation, follow these steps to set up Reactite in your application:

Wrap Your Application: Wrap your app with the ReactiteClientProvider and provide it with a ReactiteClient client.

import { ReactiteClient, ReactiteClientProvider } from "reactite";

const client = new ReactiteClient({ dbName: "hi" });
const Layout = () => {
  return (
    <ReactiteClientProvider client={client}>
      <App />
    </ReactiteClientProvider>
  );
};

ReactiteClient

The ReactiteClient constructor takes an options object to configure the client on the sqlite3 database. The following table details the available arguments:

ArgumentTypeDescription
dbNamestringThe name of the SQLite database file to be used by Reactite. This is required to initialize the client.
optionsobjectOptional settings to configure the client.

ReactiteClient Options

The options object can include the following properties:

OptionTypeDescription
enableChangeListenerbooleanIf true, enables the change listener for the database. Default is false.
enableCRSQLitebooleanIf true, enables compatibility mode with CRSQLite. Default is false.
finalizeUnusedStatementsBeforeClosingbooleanIf true, finalizes unused statements before closing the database. Default is true.
useNewConnectionbooleanIf true, uses a new database connection instead of reusing the existing one. Default is false.

useReactiteClient() hook.

The useReactiteClient hook is used to access the SQLiteDatabase instance within your React components. This hook simplifies interacting with the database by providing a direct reference to the database client.

Here's an example of how to use the useReactiteClient hook:

import { useReactiteClient } from "reactite";

const MyComponent = () => {
  // Retrieve the SQLiteDatabase instance
  const client = useReactiteClient();

  // Use the client instance to perform database operations
  // Example: client.execute('SELECT * FROM users');

  return <View>{/* Your component code here */}</View>;
};

The client gives you flexibility of excecuting raw sql statements on the sql database without using reactite hooks.

useCreateTables() hook

A custom React hook that manages the creation of SQL tables with various options and lifecycle callbacks. This hook handles the creation, error management, and provides various callbacks for handling the state of the table creation process.

Arguments

ParameterTypeDescription
tableRecord<string, TTable>An object where each key is a table name and the value is the table's configuration (columns and options).
optionsCreateTableOptions(Optional) Configuration options for table creation. Default is { skipIfExist: true, snakeCase: false, timestamps: true }.
callbacksonError | onSuccess | onSettled | onStart | onFinish(Optional) An object containing callback functions for various stages of the table creation process.
options
OptionTypeDescription
skipIfExistbooleanIf true, creates the table only if it does not already exist. Default is true.
snakeCasebooleanIf true, converts table names and columns to snake_case. Default is false.
timestampsbooleanIf true, adds createdAt and updatedAt timestamps to the table. Default is true.
callbacks
CallbackDescription
onErrorCalled when an error occurs during the table creation.
onSuccessCalled when the table creation is successful.
onSettledCalled when the table creation process is settled, regardless of success or failure.
onStartCalled when the table creation process starts.
onFinishCalled when the table creation process finishes, either successfully or with an error.

Return Values

Return ValueTypeDescription
creatingbooleanIndicates whether the table creation process is currently in progress.
successbooleanIndicates whether the table creation was successful.
errorstring \| nullContains the error message if the table creation fails, or null if there is no error.
sqlstring[]An array of SQL statements that were executed to create the tables.
tablesstring[] \| nullAn array of the names of the tables that were created, or null if no tables were created.
status"error" \| "success" \| "creating" \| nullThe current status of the table creation process.
retry() => voidA function that can be called to retry the table creation process.

useTables() hook

This hook allows you to get all the table names in your sqlite database.

const { tables, loading } = useTables();

useDatabaseName() hook

This hook is used to get the currenly connected database name with reactite.

const { db } = useDatabaseName();

useQuery() hook

The useQuery() hook is a powerful utility for retrieving records from an SQLite database within a React Native application. It allows you to perform SQL queries while managing the state of the query process, including loading, success, and error states.

const { data, error, querying, status, success, refetchQuery } = useQuery<
  {
    username: string;
    id: number;
    avatar: string;
  }[],
  any
>(
  "users",
  flt.geq("id", 8),
  ["id", "username", "avatar"],
  {
    distinct: true,
    limit: 3,
    offset: 1,
    order: { column: "id", order: "asc" },
  },
  {
    onSettled(result) {
      console.log({ result });
    },
  }
);

Arguments

ArgumentTypeDescription
tableNamestringThe name of the table from which you want to retrieve data.
filtersTFilter<TValue> | TOperator<TValue> | undefinedFilters or conditions to be applied to the query, such as equality checks, ranges, etc. Can be an operator or filter provided by reactite.
selectstring | string[] | undefinedThe columns you want to retrieve from the table. If not provided, all columns are selected by default.
optionsTQueryOptionsOptions to used when querying a record or records
callbacksTCallbacksCallbacks that get called during fetching a record using the hook.

Return Values

The useQuery() hook returns an object containing the following properties:

PropertyTypeDescription
refetchQuery() => Promise<void>A function to manually re-execute the query, useful for refreshing the data.
queryingbooleanIndicates whether the query is currently being executed.
dataTData \| nullThe records retrieved by the query, or null if no data is found or the query hasn't run yet.
errorstring \| nullContains error information if the query fails, otherwise null.
status"error" \| "success" \| "querying" \| nullRepresents the current status of the query (e.g., querying, success, error, or null if idle).
successbooleanIndicates whether the query was successful.
Options

The third option of this hook is options which are the option that are passed with a query. These options are:

OptionTypeDescription
distinctbooleanSpecifies whether to return distinct results. (true means distinct)
limitnumberLimits the number of results returned.
offsetnumberSpecifies the number of rows to skip before starting to return results.
orderasc| descDefines the sorting order of the results.
callbacks

As a forth argument the useQuery have callback functions that are called during the query operation.

PropertyDescription
onErrorCalled when an error occurs during the query process.
onSuccessCalled when the query is successful.
onSettledCalled when the query process has completed, regardless of success or failure.
onStartCalled when the query process starts.
onFinishCalled when the query process finishes.
onDataCalled when data is returned during the query process.

Usage Notes

  • The useQuery() hook is essential for fetching and displaying data from an SQLite database in your React Native components.
  • Use the refetchQuery method to manually refresh the data when needed, such as in response to user actions.
  • The querying state is useful for displaying loading indicators during data fetching.
  • The error and status properties provide detailed error handling, allowing you to respond appropriately to query failures.

👍 If you want to do pagination with your SQLite reactite exposes a hook called usePaginatedQuery() which is different from the useQuery() in the sense that this hoot returns a paginated result instead of a regular query result.

usePaginatedQuery() hook

The usePaginatedQuery hook is designed to fetch paginated data from a SQLite table with various options for filtering, selecting specific columns, and handling different stages of the query process through callbacks.

import { usePaginatedQuery } from "reactite";

const { data, error, querying, status, success, fetchNextPage, refetchPage } =
  usePaginatedQuery<
    {
      username: string;
      id: number;
      avatar: string;
    }[],
    any
  >(
    "users",
    {
      distinct: true,
      pageSize: 2,
      order: { column: "id", order: "asc" },
      cursor: 1,
    },
    flt.gt("id", 5),
    ["id", "username", "avatar"],
    {
      onSettled({ data }) {},
    }
  );

Arguments

ArgumentTypeDescription
tableNamestringThe name of the table to query.
optionsTPaginatedQueryOptionsOptions for configuring pagination, ordering, and other query-related settings.
filtersTFilter<TValue> \| TOperand<TValue> (optional)Filters or operands to apply to the query for conditional data retrieval.
selectstring \| string[] (optional)Columns to select from the table. If not provided, all columns are selected.
callbacksTPaginatedCallBacks<TPaginatedData<TData>, TStatus> (optional)Callbacks to handle different stages of the query (e.g., onStart, onSuccess, onError, etc.).

TPaginatedQueryOptions

OptionTypeDescription
distinctbooleanWhether to return distinct rows only.
pageSizenumberThe number of records to fetch per page.
order{ column: string, order: "asc" \| "desc" }The column and order to sort the results.
cursornumber | stringThe cursor value to start the pagination from based on the type of the primary key column your your table.

Callbacks

CallbackTypeDescription
onData(data: TPaginatedData<TData>) => void (optional)Callback triggered when data is successfully fetched.
onError(error: string) => void (optional)Callback triggered when an error occurs during the query.
onFinish(status: TStatus) => void (optional)Callback triggered when the query finishes, regardless of success or failure.
onSettled(result: { data: TPaginatedData<TData>; status: TStatus }) => void (optional)Callback triggered after the query has settled, whether successful or not.
onStart(status: TStatus) => void (optional)Callback triggered when the query starts.
onSuccess(result: { data: TPaginatedData<TData>; status: TStatus }) => void (optional)Callback triggered when the query is successful.

Return Types

Return ValueTypeDescription
refetchPage() => Promise<void>Function to refetch the current page of data.
fetchNextPage() => Promise<void>Function to fetch the next page of data.
queryingbooleanIndicates whether the query is currently being executed.
dataTPaginatedData<TData>The paginated data returned from the query.
errorstring \| nullError message, if any, returned during the query.
statusTStatusThe current status of the query (e.g., "loading", "error", "success").
successbooleanIndicates whether the query was successful.
hasNextPagebooleanIndicates if there is another page of data available.
isFirstPagebooleanIndicates if the current page is the first page.
isLastPagebooleanIndicates if the current page is the last page.

useMutation() hook

The useMutation hook is a versatile hook used for performing asynchronous mutations (insert, update, delete) on a database table within a React Native component.

import { useMutation } from "reactite";

const Post = () => {
  const [mutateAsync, { mutating }] = useMutation<{
    id: string;
    username: string;
    avatar: string | null;
    password: string;
    createAt: string;
    updatedAt: string;
  }>("users", "delete", {
    onData(result) {
      console.log(JSON.stringify(result, null, 2));
    },
    onError(error) {
      console.log(error);
    },
  });

  return (
    <Button
      title="Delete"
      onPress={async () => {
        await mutateAsync(op.or(flt.eq("id", 1), flt.in("id", [10, 11])));
      }}
    />
  );
};

This hooks takes the following as arguments:

Arguments

ArgumentTypeDescription
tableNamestringThe name of the table on which the mutation is to be performed.
operation"insert" \| "update" \| "delete"The type of mutation operation to perform (insert, update, or delete).
callbacksonError| onSuccess| onSettled| onStart| onFinish | onData An object containing optional callback functions for handling various stages of the mutation process.
callbacks
PropertyDescription
onErrorCalled when an error occurs during the mutation process.
onSuccessCalled when the mutation is successful.
onSettledCalled when the mutation process has completed, regardless of success or failure.
onStartCalled when the mutation process starts.
onFinishCalled when the mutation process finishes.
onDataCalled when data is returned during the mutation process.

This hook return a tuple of 2 values, the mutation function and a result which is an object that contains the following properties

PropertyTypeDescription
mutatingbooleanIndicates if the mutation process is ongoing.
dataTData \| TData[] \| nullThe data returned from the mutation, if any.
errorstring \| nullAn error message if the mutation fails.
status"error" \| "success" \| "mutating" \| nullThe current status of the mutation process.
successbooleanIndicates if the mutation was successful.

👍 The useMutation hook is effective when you want to run mutations based on filters. However, there is a hook called useMutationByPK, which does the same thing but doesn't accept filters as it uses the table's primary key to mutate documents. Note that this hook only works for the delete and update operations.

useMutationByPK() hook

The useMutationByPK hook is a specialized hook for performing asynchronous mutations (update, delete) on a database table using the primary key of the records. This hook is a streamlined alternative to the useMutation hook, focusing on operations where only the primary key is needed.

import { useMutationByPK } from "reactite";

const Post = () => {
  const [mutateAsync, { mutating }] = useMutationByPK<{
    id: string;
    username: string;
    avatar: string | null;
    password: string;
    createAt: string;
    updatedAt: string;
  }>("users", "delete", {
    onData(result) {
      console.log(JSON.stringify(result, null, 2));
    },
    onError(error) {
      console.log(error);
    },
  });

  return (
    <Button
      title="Delete"
      onPress={async () => {
        await mutateAsync(1);
      }}
    />
  );
};

Arguments

ArgumentDescription
tableNameThe name of the table on which the mutation is to be performed.
operationThe type of mutation operation to perform (update or delete).
callbacksAn optional object containing callback functions for handling various stages of the mutation process.

Note that the return types of this hooks and callbacks are the same as the ones in the useMutation() hook.

👍 If you want to perform mutations based on multiple ids the useMutationByPKs do that.

useMutationByPKs() hook

The useMutationByPKs hook is a specialized hook for performing asynchronous mutations (update, delete) on multiple records in a database table using their primary keys. This hook is designed for operations where multiple primary keys are needed for the mutation.

import { useMutationByPKs } from "reactite";

const Post = () => {
  const [mutateAsync, { mutating }] = useMutationByPKs<{
    id: string;
    username: string;
    avatar: string | null;
    password: string;
    createAt: string;
    updatedAt: string;
  }>("users", "delete", {
    onData(result) {
      console.log(JSON.stringify(result, null, 2));
    },
    onError(error) {
      console.log(error);
    },
  });

  return (
    <Button
      title="Delete"
      onPress={async () => {
        await mutateAsync([1, 2, 7]);
      }}
    />
  );
};

Arguments

ArgumentDescription
tableNameThe name of the table on which the mutation is to be performed.
operationThe type of mutation operation to perform (update or delete).
callbacksAn optional object containing callback functions for handling various stages of the mutation process.

👍 The useMutationByPK and useMutationByPKs hooks are quite similar. The key difference is that useMutationByPK accepts a single ID, while useMutationByPKs accepts an array of IDs.

useQueryByPK() hook

The useQueryByPK() hook is designed to retrieve a record from a table in your SQLite database based on a primary key. It also allows you to specify which columns to retrieve. To use the useQueryByPK() hook, call it within your functional component, passing in the table name, an array of primary key values, and an optional array of column names you wish to retrieve. The hook returns an object containing the queried data and other useful states.

import { useQueryByPK } from "reactite";
....

const { data, error, querying, status, success, refetchQuery } = useQueryByPK<
  {
    id: string;
    username: string;
  },
  number
>("users", 8, ["id", "username"]);

Arguments

ArgumentTypeDescription
tableNamestringThe name of the table from which to query the record.
pkstring \| numberThe primary key value of the record you want to retrieve. Allows either a string or number type based on the table's primary key type.
selectstring \| string[]An optional array of column names or a single column name to include in the result.

Return Values

PropertyTypeDescription
dataTData \| nullThe record retrieved from the database based on the primary key, or null if no record is found.
errorstring \| nullContains the error message if the query fails, otherwise null.
queryingbooleanIndicates whether the query is currently in progress.
status"error" \| "success" \| "querying" \| nullThe current status of the query (error, success, querying, or null).
successbooleanIndicates whether the query was successful.
refetchQueryFunctionA function to refetch the query.

👍 Note: The difference between useQuery and useQueryByPK is that the former takes in filters, while the latter uses your primary key column to retrieve a single record by its value.

callbacks

As a third argument the useQueryByPK have callback functions that are called during the query operation.

PropertyDescription
onErrorCalled when an error occurs during the query process.
onSuccessCalled when the query is successful.
onSettledCalled when the query process has completed, regardless of success or failure.
onStartCalled when the query process starts.
onFinishCalled when the query process finishes.
onDataCalled when data is returned during the query process.

useQueryByPKs() hook.

The useQueryByPKs() hook is designed to retrieve multiple records from a table in your SQLite database based on an array of primary keys. It also allows you to specify which columns to retrieve.

import { useQueryByPKs } from "reactite";
....

 const { data, error, querying, status, success, refetchQuery } =
    useQueryByPKs<
      {
        id: string;
        username: string;
      },
      number
    >("users", [3, 8], ["id", "username"]);

Arguments

ArgumentTypeDescription
tableNamestringThe name of the table from which to query the records.
pksArray<TPK>An array of primary key values for the records you want to retrieve. TPK can be either a string or number depending on the table's primary key type.
selectstring \| string[]An optional array of column names or a single column name to include in the result.

Return Values

PropertyTypeDescription
dataTData[] \| nullThe records retrieved from the database based on the primary key(s), or null if no records are found.
errorstring \| nullContains the error message if the query fails, otherwise null.
queryingbooleanIndicates whether the query is currently in progress.
status"error" \| "success" \| "querying" \| nullThe current status of the query (error, success, querying, or null).
successbooleanIndicates whether the query was successful.
refetchQueryFunctionA function to refetch the query.

👍 Note: The difference between useQueryByPK and useQueryByBKs is that the former takes in a single value of id, while the latter uses list or array primary keys to retrieve records by their primary keys.

callbacks

As a third argument the useQueryByPKs have callback functions that are called during the query operation.

PropertyDescription
onErrorCalled when an error occurs during the query process.
onSuccessCalled when the query is successful.
onSettledCalled when the query process has completed, regardless of success or failure.
onStartCalled when the query process starts.
onFinishCalled when the query process finishes.
onDataCalled when data is returned during the query process.

Operands

The reactite operands allows you to use one or more filters in a query.

import { flt, op, useQuery } from "reactite";

// ....

const { data, error, querying, status, success, refetchQuery } = useQuery<
  {
    username: string;
    id: number;
  }[],
  any
>("users", op.or(flt.notIn("id", [8, 9]), flt.eq("id", 9)), ["id", "username"]);

Here are the supported operands in reactite.

OperationExplanationExample
andCombines multiple filter conditions using a logical AND. All specified conditions must be true for the query to match.op.and(filter1, filter2) generates a SQL condition like filter1 AND filter2.
orCombines multiple filter conditions using a logical OR. At least one of the specified conditions must be true for the query to match.op.or(filter1, filter2) generates a SQL condition like filter1 OR filter2.

Filters

You can get all the supported filters from reactite as follows:

import {flt} from `reactite`

 const { data, error, querying, status, success, refetchQuery } = useQuery<
    {
      username: string;
      id: number;
    }[],
    any
  >("users", flt.in("id", [8, 9]), ["id", "username"]);

Here are the filters that can be applied within queries and mutations.

FilterExplanationExample
eqIndicates equality. It checks if the value is equal to the specified criteria.column = $columnValue
neqIndicates inequality. It checks if the value is not equal to the specified criteria.column != $columnValue
inChecks if the value is within a specified list of values.column IN ($value1, $value2, ...)
notInChecks if the value is not within a specified list of values.column NOT IN ($value1, $value2, ...)
ltChecks if the value is less than the specified criteria.column < $columnValue
leqChecks if the value is less than or equal to the specified criteria.column <= $columnValue
gtChecks if the value is greater than the specified criteria.column > $columnValue
geqChecks if the value is greater than or equal to the specified criteria.column >= $columnValue
likeChecks if the value matches a specified pattern.column LIKE $columnValue
notChecks if the value does not equal the specified criteria.NOT column = $columnValue
betweenChecks if the value is between two specified values. Requires exactly two values in the array.column BETWEEN $columnValue1 AND $columnValue2

Examples

In this section we are going to create 2 applications that demonstrate how to use reactite in a react native expo project.

  1. Basic Crud
  2. Pagination Example

Contribution

To contribute follow our guides in the CONTRIBUTION.md file

Change logs.

All the changes that will be done to reactite will be documented in the CHANGELOG.md

LICENSE

This project is using the MIT.

1.0.0

9 months ago

0.0.4

10 months ago

0.0.3

10 months ago

0.0.2

10 months ago

0.0.1

10 months ago