Skip to content

Commit

Permalink
Add simple sql batch interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Christopher J. Brody committed Feb 7, 2016
1 parent 1246edf commit b39c836
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 0.x.x-xx

- Simple sql batch transaction function
- Echo test function
- Remove extra runInBackground: step from iOS version
- Android-sqlite-connector (NDK) support removed from this version branch
Expand Down
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ I raised [Cordova bug CB-9830](https://issues.apache.org/jira/browse/CB-9830) to

## Announcements

- Added simple sql batch query function
- Added echo test function to verify installation of this plugin
- All iOS operations are now using background processing (reported to resolve intermittent problems with [email protected])
- Published [brodybits / Cordova-quick-start-checklist](https://github.com/brodybits/Cordova-quick-start-checklist) and [brodybits / Cordova-troubleshooting-guide](https://github.com/brodybits/Cordova-troubleshooting-guide)
Expand Down Expand Up @@ -297,6 +298,7 @@ This option is ignored if `androidDatabaseImplementation: 2` is not specified.

The following types of SQL transactions are supported by this version:
- Single-statement transactions
- SQL batch query transactions
- Standard asynchronous transactions

### Single-statement transactions
Expand All @@ -311,7 +313,27 @@ db.executeSql("SELECT LENGTH('tenletters') AS stringlength", [], function (res)
});
```

## Standard asynchronous transactions
### SQL batch query transactions

Sample:

```Javascript
db.sqlBatch([
'DROP TABLE IF EXISTS MyTable',
'CREATE TABLE MyTable (SampleColumn)',
[ 'INSERT INTO MyTable VALUES (?)', ['test-value'] ],
], function() {
db.executeSql('SELECT * FROM MyTable', [], function (res) {
console.log('Sample column value: ' + res.rows.item(0).SampleColumn);
});
}, function(error) {
console.log('Populate table error: ' + error.message);
});
```

In case of an error, all changes in a sql batch are automatically discarded using ROLLBACK.

### Standard asynchronous transactions

Standard asynchronous transactions follow the HTML5/[Web SQL API](http://www.w3.org/TR/webdatabase/) which is very well documented and uses BEGIN and COMMIT or ROLLBACK to keep the transactions failure-safe. Here is a very simple example from the test suite:

Expand Down
27 changes: 27 additions & 0 deletions SQLitePlugin.coffee.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,33 @@
@addTransaction new SQLitePluginTransaction(this, myfn, null, null, false, false)
return

SQLitePlugin::sqlBatch = (sqlStatements, success, error) ->
if !sqlStatements || sqlStatements.constructor isnt Array
throw newSQLError 'sqlBatch expects an array'

batchList = []

for st in sqlStatements
if st.constructor is Array
if st.length == 0
throw newSQLError 'sqlBatch array element of zero (0) length'

batchList.push
sql: st[0]
params: if st.length == 0 then [] else st[1]

else
batchList.push
sql: st
params: []

myfn = (tx) ->
for elem in batchList
tx.addStatement(elem.sql, elem.params, null, null)

@addTransaction new SQLitePluginTransaction(this, myfn, error, success, true, false)
return

## SQLite plugin transaction object for batching:

SQLitePluginTransaction = (db, fn, error, success, txlock, readOnly) ->
Expand Down
1 change: 1 addition & 0 deletions spec/www/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<script src="spec/browser-check-startup.js"></script>
<script src="spec/self-test.js"></script>
<script src="spec/simple-test.js"></script>
<script src="spec/sql-batch-test.js"></script>
<script src="spec/legacy.js"></script>

</head>
Expand Down
133 changes: 133 additions & 0 deletions spec/www/spec/sql-batch-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/* 'use strict'; */

var MYTIMEOUT = 12000;

var DEFAULT_SIZE = 5000000; // max to avoid popup in safari/ios

var isAndroid = /Android/.test(navigator.userAgent);
var isWP8 = /IEMobile/.test(navigator.userAgent); // Matches WP(7/8/8.1)
//var isWindows = /Windows NT/.test(navigator.userAgent); // Windows [NT] (8.1)
var isWindows = /Windows /.test(navigator.userAgent); // Windows (8.1)
//var isWindowsPC = /Windows NT/.test(navigator.userAgent); // Windows [NT] (8.1)
//var isWindowsPhone_8_1 = /Windows Phone 8.1/.test(navigator.userAgent); // Windows Phone 8.1
//var isIE = isWindows || isWP8 || isWindowsPhone_8_1;
var isIE = isWindows || isWP8;
var isWebKit = !isIE; // TBD [Android or iOS]

// NOTE: In the core-master branch there is no difference between the default
// implementation and implementation #2. But the test will also apply
// the androidLockWorkaround: 1 option in the case of implementation #2.
var scenarioList = [
isAndroid ? 'Plugin-implementation-default' : 'Plugin',
'Plugin-implementation-2'
];

var scenarioCount = isAndroid ? 2 : 1;

// simple tests:
var mytests = function() {

for (var i=0; i<scenarioCount; ++i) {

describe(scenarioList[i] + ': BATCH SQL test(s)', function() {
var scenarioName = scenarioList[i];
var suiteName = scenarioName + ': ';
var isImpl2 = (i === 1);

// NOTE: MUST be defined in function scope, NOT outer scope:
var openDatabase = function(name, ignored1, ignored2, ignored3) {
if (isImpl2) {
return window.sqlitePlugin.openDatabase({
// prevent reuse of database from default db implementation:
name: 'i2-'+name,
androidDatabaseImplementation: 2,
androidLockWorkaround: 1
});
} else {
return window.sqlitePlugin.openDatabase(name, '1.0', 'Test', DEFAULT_SIZE);
}
}

describe(scenarioList[i] + ': Basic sql batch test(s)', function() {

it(suiteName + 'Single-column batch sql test', function(done) {
var db = openDatabase('Single-column-batch-sql-test.db', '1.0', 'Test', DEFAULT_SIZE);

expect(db).toBeDefined();

db.sqlBatch([
'DROP TABLE IF EXISTS MyTable',
'CREATE TABLE MyTable (SampleColumn)',
[ 'INSERT INTO MyTable VALUES (?)', ['test-value'] ],
], function() {
db.executeSql('SELECT * FROM MyTable', [], function (res) {
expect(res.rows.item(0).SampleColumn).toBe('test-value');
done();
});
}, function(error) {
expect(true).toBe(false);
done();
});
}, MYTIMEOUT);

it(suiteName + 'batch sql with syntax error', function(done) {
var db = openDatabase('batch-sql-syntax-error-test.db', '1.0', 'Test', DEFAULT_SIZE);

expect(db).toBeDefined();

db.sqlBatch([
'DROP TABLE IF EXISTS MyTable',
// syntax error below:
'CRETE TABLE MyTable (SampleColumn)',
[ 'INSERT INTO MyTable VALUES (?)', ['test-value'] ],
], function() {
// not expected:
expect(true).toBe(false);
done();
}, function(error) {
// expected:
expect(true).toBe(true);
done();
});
}, MYTIMEOUT);

it(suiteName + 'batch sql failure-safe semantics', function(done) {
var db = openDatabase('batch-sql-failure-safe-test.db', '1.0', 'Test', DEFAULT_SIZE);

expect(db).toBeDefined();

db.executeSql('DROP TABLE IF EXISTS MyTable');
db.executeSql('CREATE TABLE MyTable (SampleColumn)');
db.executeSql('INSERT INTO MyTable VALUES (?)', ['test-value'], function() {
db.sqlBatch([
'DELETE FROM MyTable',
// syntax error below:
[ 'INSRT INTO MyTable VALUES (?)', 'test-value' ]
], function() {
// not expected:
expect(true).toBe(false);
done();
}, function(error) {
// check integrity:
db.executeSql('SELECT * FROM MyTable', [], function (res) {
expect(res.rows.item(0).SampleColumn).toBe('test-value');
done();
});
});

}, function(error) {
expect(true).toBe(false);
done();
});
}, MYTIMEOUT);

});

});
}
}

if (window.hasBrowser) mytests();
else exports.defineAutoTests = mytests;

/* vim: set expandtab : */
35 changes: 35 additions & 0 deletions www/SQLitePlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,41 @@
this.addTransaction(new SQLitePluginTransaction(this, myfn, null, null, false, false));
};

SQLitePlugin.prototype.sqlBatch = function(sqlStatements, success, error) {
var batchList, j, len1, myfn, st;
if (!sqlStatements || sqlStatements.constructor !== Array) {
throw newSQLError('sqlBatch expects an array');
}
batchList = [];
for (j = 0, len1 = sqlStatements.length; j < len1; j++) {
st = sqlStatements[j];
if (st.constructor === Array) {
if (st.length === 0) {
throw newSQLError('sqlBatch array element of zero (0) length');
}
batchList.push({
sql: st[0],
params: st.length === 0 ? [] : st[1]
});
} else {
batchList.push({
sql: st,
params: []
});
}
}
myfn = function(tx) {
var elem, k, len2, results;
results = [];
for (k = 0, len2 = batchList.length; k < len2; k++) {
elem = batchList[k];
results.push(tx.addStatement(elem.sql, elem.params, null, null));
}
return results;
};
this.addTransaction(new SQLitePluginTransaction(this, myfn, error, success, true, false));
};

SQLitePluginTransaction = function(db, fn, error, success, txlock, readOnly) {
if (typeof fn !== "function") {

Expand Down

0 comments on commit b39c836

Please sign in to comment.