[go: up one dir, main page]

Skip to content

LiteSync Plugin for React Native (Android and iOS)

License

Notifications You must be signed in to change notification settings

litesync/react-native-litesync

 
 

Repository files navigation

LiteSync logo

React Native LiteSync

LiteSync plugin for React Native (Android and iOS)

This plugin works as a wrapper over the LiteSync native library. It can be used with both the free and the full versions

This is a fork of react-native-sqlite-storage

Main differences:

  • Links to the LiteSync native library
  • Query parameters are not converted to strings

Features:

  • iOS and Android supported via identical JavaScript API
  • SQL transactions
  • JavaScript interface via callbacks or Promises
  • Pre-populated SQLite database import from application bundle and sandbox (for dbs that do not use LiteSync)

Installation

# using yarn
yarn add react-native-litesync react-native-udp

# using npm
npm install react-native-litesync react-native-udp

Then run:

cd ios && pod install && cd ..

For React Native 0.59 and below (manual linking) please follow these instructions

Native Libraries

To install the free version of LiteSync native libraries, execute the following:

wget http://litesync.io/download/litesync.aar
wget http://litesync.io/download/litesync-free-ios-native-libs.tar.gz
tar zxvf litesync-free-ios-native-libs.tar.gz lib
mv lib node_modules/react-native-litesync/platforms/ios/
mv litesync.aar node_modules/react-native-litesync/platforms/android/

When moving to the full version just copy the libraries to the respective folders as done above, replacing the existing files.

How to Use

Here is an example code:

var SQLite = require('react-native-litesync')

on_error = (err) => {
  console.log("Error:", err);
}

on_success = () => {
  console.log("SQL executed");
}

on_db_open = () => {
  console.log("The database was opened");
}

// open the database
var uri = "file:test.db?node=secondary&connect=tcp://server:port";
var db = SQLite.openDatabase({name: uri}, on_db_open, on_error);

db.on('error', on_error);  // this should be the first callback

db.on('not_ready', () => {
  // the user is not logged in. show the login screen (and do not access the database)
  ...
});

db.on('ready', () => {
  // the user is already logged in or the login was successful. show the main screen
  ...
});

db.on('sync', () => {
  // the db received an update. update the screen with new data
  show_items();
});

insert_items = () => {
  db.transaction((tx) => {
    // CREATE TABLE IF NOT EXISTS tasks (id INTEGER PRIMARY KEY, name, done, row_owner)
    tx.executeSql("INSERT INTO tasks (name,done) VALUES ('Learn React Native',1)", []);
    tx.executeSql("INSERT INTO tasks (name,done) VALUES ('Use SQLite',1)", []);
    tx.executeSql("INSERT INTO tasks (name,done) VALUES ('Test LiteSync',0)", []);
  }, () => {
    // success callback = transaction committed
    show_items();
  }, on_error);
}

show_items = () => {
  db.executeSql('SELECT * FROM tasks', [], (result) => {
    // Get rows with Web SQL Database spec compliance
    var len = result.rows.length;
    for (let i = 0; i < len; i++) {
      let task = result.rows.item(i);
      console.log(`Task: ${task.name}, done: ${task.done}`);
    }
    // Alternatively, you can use the non-standard raw method
    /*
    let tasks = result.rows.raw();  // shallow copy of the rows Array
    tasks.forEach(row => console.log(`Task: ${task.name}, done: ${task.done}`));
    */
  });
}

Working Examples

These example apps can be used with the AwesomeProject generated by React Native. All you have to do is to copy one of those files into your AwesomeProject replacing the index.js

Opening a Database

SQLite.openDatabase({name: uri}, successcb, errorcb);

Database Status

⚠️ The application should NOT access the database before it is ready for read and write!

The app should subscribe to database events to act according to its state

If the database is not ready, the not_ready event will be fired. This generally means that it is the first time the app is being open and/or the user has not signed up or logged in yet:

db.on('not_ready', () => {
  // the user is not logged in. show the login screen (and do not access the database)
  ...
});

If the user has already signed up or logged in, then the database will fire the ready event:

db.on('ready', () => {
  // the user is already logged in or the login was successful. show the main screen
  ...
});

It is also possible to subscrive to sync events, so the app can read fresh data from the database and update the screen:

db.on('sync', () => {
  // the db received an update. update the screen with new data
  ...
});

To check the full status of the database we can use:

db.executeSql("pragma sync_status", [], (result) => {
  if (result.rows && result.rows.length > 0) {
    var status = result.rows.item(0);
    console.log('sync status:', status.sync_status);
  } else {
    console.log('LiteSync is not active')
  }
}, (msg) => {
  console.log('could not run "pragma sync_status":', msg)
});

User Sign Up & User Login

LiteSync replicates the same database to all the users.

You need to implement the authorization by yourself, if required.

For an easier approach that supports user login, check OctoDB

Importing a pre-populated database

This is NOT supported if the database uses LiteSync, because the database will be downloaded from the primary node(s) at the first run.

But as this library also supports normal SQLite databases, you can import an existing pre-populated database file into your application when opening a normal SQLite database.

On this case follow the instructions at the original repo

Attaching another database

SQLite3 offers the capability to attach another database to an existing database instance, i.e. for making cross database JOINs available. This feature allows to SELECT and JOIN tables over multiple databases with only one statement and only one database connection. To archieve this, you need to open both databases and to call the attach() method of the destination (or master) database to the other ones.

let dbMaster, dbSecond;

dbSecond = SQLite.openDatabase({name: 'second'},
  (db) => {
    dbMaster = SQLite.openDatabase({name: 'master'},
      (db) => {
        dbMaster.attach( "second", "second", () => console.log("Database attached successfully"), () => console.log("ERROR"))
      },
      (err) => console.log("Error on opening database 'master'", err)
    );
  },
  (err) => console.log("Error on opening database 'second'", err)
);

The first argument of attach() is the name of the database, which is used in SQLite.openDatabase(). The second argument is the alias, that is used to query on tables of the attached database.

The following statement would select data from the master database and include the "second" database within a simple SELECT/JOIN statement:

SELECT * FROM user INNER JOIN second.subscriptions s ON s.user_id = user.id

To detach a database use the detach() method:

dbMaster.detach( 'second', successCallback, errorCallback );

There is also Promise support for attach() and detach() as shown in the example application under the test folder

Promises

To enable promises, run:

SQLite.enablePromise(true);

Known Issues

  1. React Native does not distinguish between integers and doubles. Only a Numeric type is available on the interface point. You can check the original issue

The current solution is to cast the bound value in the SQL statement as shown here:

INSERT INTO products (name,qty,price) VALUES (?, cast(? as integer), cast(? as real))

About

LiteSync Plugin for React Native (Android and iOS)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C# 41.3%
  • JavaScript 24.3%
  • Java 20.4%
  • Objective-C 13.5%
  • Ruby 0.5%