litehelpers / Cordova-SQLitePlugin-legacy-iOS-broken-bug666

Cordova/PhoneGap SQLitePlugin for iOS as of September 2013, no longer supported - BROKEN due to BUG litehelpers/Cordova-sqlite-storage#666
89 stars 30 forks source link

Cordova/PhoneGap SQLitePlugin - Legacy iOS version - Summer 2013

Native interface to sqlite in a Cordova/PhoneGap plugin, working to follow the HTML5 Web SQL API as close as possible. NOTE that the API is now different from davibe / Phonegap-SQLitePlugin.

Created by @joenoon and @davibe

API changes by @brodybits (Chris Brody)

iOS nested transaction callback support by @ef4 (Edward Faulkner)

Cordova 2.7+ port with background processing by @j3k0 (Jean-Christophe Hoelt)

License for this version: MIT

Announcements

Highlights

As described in a recent posting:

Some other highlights:

Apps using Cordova/PhoneGap SQLitePlugin

Known limitations

Other versions

Usage

The idea is to emulate the HTML5 SQL API as closely as possible. The only major change is to use window.sqlitePlugin.openDatabase() (or sqlitePlugin.openDatabase()) instead of window.openDatabase(). If you see any other major change please report it, it is probably a bug.

Opening a database

There are two options to open a database:

IMPORTANT: Please wait for the "deviceready" event, as in the following example:

// Wait for Cordova to load
document.addEventListener("deviceready", onDeviceReady, false);

// Cordova is ready
function onDeviceReady() {
  var db = window.sqlitePlugin.openDatabase({name: "DB"});
  // ...
}

NOTE: The database file is created with .db extension.

Background processing

To enable background processing open a database like:

var db = window.sqlitePlugin.openDatabase({name: "DB", bgType: 1});

Sample with PRAGMA feature

This is a pretty strong test: first we create a table and add a single entry, then query the count to check if the item was inserted as expected. Note that a new transaction is created in the middle of the first callback.

    // Wait for Cordova to load
    document.addEventListener("deviceready", onDeviceReady, false);

    // Cordova is ready
    function onDeviceReady() {
      var db = window.sqlitePlugin.openDatabase({name: "DB"});

      db.transaction(function(tx) {
        tx.executeSql('DROP TABLE IF EXISTS test_table');
        tx.executeSql('CREATE TABLE IF NOT EXISTS test_table (id integer primary key, data text, data_num integer)');

        // demonstrate PRAGMA:
        db.executeSql("pragma table_info (test_table);", [], function(res) {
          console.log("PRAGMA res: " + JSON.stringify(res));
        });

        tx.executeSql("INSERT INTO test_table (data, data_num) VALUES (?,?)", ["test", 100], function(tx, res) {
          console.log("insertId: " + res.insertId + " -- probably 1");
          console.log("rowsAffected: " + res.rowsAffected + " -- should be 1");

          db.transaction(function(tx) {
            tx.executeSql("select count(id) as cnt from test_table;", [], function(tx, res) {
              console.log("res.rows.length: " + res.rows.length + " -- should be 1");
              console.log("res.rows.item(0).cnt: " + res.rows.item(0).cnt + " -- should be 1");
            });
          });

        }, function(e) {
          console.log("ERROR: " + e.message);
        });
      });
    }

Sample with transaction-level nesting

In this case, the same transaction in the first executeSql() callback is being reused to run executeSql() again.

    // Wait for Cordova to load
    document.addEventListener("deviceready", onDeviceReady, false);

    // Cordova is ready
    function onDeviceReady() {
      var db = window.sqlitePlugin.openDatabase("Database", "1.0", "Demo", -1);

      db.transaction(function(tx) {
        tx.executeSql('DROP TABLE IF EXISTS test_table');
        tx.executeSql('CREATE TABLE IF NOT EXISTS test_table (id integer primary key, data text, data_num integer)');

        tx.executeSql("INSERT INTO test_table (data, data_num) VALUES (?,?)", ["test", 100], function(tx, res) {
          console.log("insertId: " + res.insertId + " -- probably 1");
          console.log("rowsAffected: " + res.rowsAffected + " -- should be 1");

          tx.executeSql("select count(id) as cnt from test_table;", [], function(tx, res) {
            console.log("res.rows.length: " + res.rows.length + " -- should be 1");
            console.log("res.rows.item(0).cnt: " + res.rows.item(0).cnt + " -- should be 1");
          });

        }, function(e) {
          console.log("ERROR: " + e.message);
        });
      });
    }

This case will also works with Safari (WebKit), assuming you replace window.sqlitePlugin.openDatabase with window.openDatabase.

Installing

NOTE: There are now the following trees:

iOS platform

SQLite library

In the Project "Build Phases" tab, select the first "Link Binary with Libraries" dropdown menu and add the library libsqlite3.dylib or libsqlite3.0.dylib.

NOTE: In the "Build Phases" there can be multiple "Link Binary with Libraries" dropdown menus. Please select the first one otherwise it will not work.

SQLite Plugin

Drag .h and .m files into your project's Plugins folder (in xcode) -- I always just have "Create references" as the option selected.

Take the precompiled javascript file from build/, or compile the coffeescript file in src/ to javascript WITH the top-level function wrapper option (default).

Use the resulting javascript file in your HTML.

Enable the SQLitePlugin in config.xml:

--- config.xml.old  2013-05-17 13:18:39.000000000 +0200
+++ config.xml  2013-05-17 13:18:49.000000000 +0200
@@ -39,6 +39,7 @@
     <content src="https://github.com/litehelpers/Cordova-SQLitePlugin-legacy-iOS-broken-bug666/raw/legacy-ios/index.html" />

     <plugins>
+        <plugin name="SQLitePlugin" value="SQLitePlugin" />
         <plugin name="Device" value="CDVDevice" />
         <plugin name="Logger" value="CDVLogger" />
         <plugin name="Compass" value="CDVLocation" />

Dealing with ARC

A project generated by the create script from Cordova should already have the Automatic Reference Counting (ARC) option disabled. However, a project generated by the xcode GUI may have the ARC option enabled and this will cause a number of build problems with the SQLitePlugin.

To disable ARC for the module only (from @LouAlicegary): click on your app name at the top of the left-hand column in the Project Navigator, then click on the app name under "Targets," click on the "Build Phases" tab, and then double-click on the SQLitePlugin.m file under "Compile Sources" and add a "-fno-objc-arc" compiler flag to that entry

Common traps & pitfalls

Support

Community support is available via the new Google group: http://groups.google.com/group/pgsqlite

If you have an issue with the plugin please check the following first:

If you still cannot get something to work:

Then please post the issue to the pgsqlite forum.

Unit test(s)

Unit testing is done in test-www/index.html. To run the test(s) yourself please copy the files from test-www (index.html, qunit-1.5.0.js, & qunit-1.5.0.css) into the www directory of your iOS Cordova project and make sure you have SQLitePlugin completely installed (JS, Objective-C, and plugin registered).

Lawnchair Adapter Usage

Common adapter

Please look at the Lawnchair-adapter tree that contains a common adapter, which should also work with the Android version, along with a test-www directory.

Included files

Include the following js files in your html:

Sample

The name option will determine the sqlite filename. Optionally, you can change it using the db option.

In this example, you would be using/creating the database at: Documents/kvstore.sqlite3 (all db's in SQLitePlugin are in the Documents folder)

kvstore = new Lawnchair { name: "kvstore" }, () ->
  # do stuff

Using the db option you can create multiple stores in one sqlite file. (There will be one table per store.)

recipes = new Lawnchair {db: "cookbook", name: "recipes", ...}
ingredients = new Lawnchair {db: "cookbook", name: "ingredients", ...}

Contributing