diff --git a/README.md b/README.md
index c51b869..0a7025d 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,10 @@
# numtel:mysql [![Build Status](https://travis-ci.org/numtel/meteor-mysql.svg?branch=master)](https://travis-ci.org/numtel/meteor-mysql)
Reactive MySQL for Meteor
-Wrapper of the [MySQL NPM module](https://github.com/felixge/node-mysql) with a few added methods.
+Wrapper of the [MySQL NPM module](https://github.com/felixge/node-mysql) with help from the [`mysql-live-select` NPM module](https://github.com/numtel/mysql-live-select) to bring reactive `SELECT` statement result sets.
* [Quick tutorial on using this package](getting_started.md)
* [Leaderboard example modified to use MySQL](https://github.com/numtel/meteor-mysql-leaderboard)
-* [Explanation of the implementation design process](context.md)
* [Talk at Meteor Devshop SF, December 2014](https://www.youtube.com/watch?v=EJzulpXZn6g)
## Server Implements
@@ -32,17 +31,26 @@ var result = db.queryEx(function(esc, escId){
* The first argument, `esc` is a function that escapes values in the query.
* The second argument, `escId` is a function that escapes identifiers in the query.
-### `connection.initUpdateTable(tableName)`
+### `connection.initBinlog(settings)`
-Specify a table (as string) to use for storing the keys used for notifying updates to queries. The table will be created if it does not exist. To install for the first time, specify a table name that does not currently exist.
+Initialize the Binary replication log transmission method. The one argument required, `settings` should be an object containing the settings to connect to the MySQL server with a user that has been granted replication slave privileges.
+
+> Using the binary log transmission method requires your MySQL server to be configured properly. Please see the [installation instructions on the `mysql-live-select` NPM package repository](https://github.com/numtel/mysql-live-select#installation).
-### `connection.initUpdateServer([port], [hostName])`
+In addition to the [`node-mysql` connection settings](https://github.com/felixge/node-mysql#connection-options), the following settings are available:
+
+Setting | Type | Description
+--------|------|------------------------------
+`serverId` | `integer` | [Unique number (1 - 232)](http://dev.mysql.com/doc/refman/5.0/en/replication-options.html#option_mysqld_server-id) to identify this replication slave instance. Must be specified if running more than one instance.
**Default:** `1`
+`minInterval` | `integer` | Pass a number of milliseconds to use as the minimum between result set updates. Omit to refresh results on every update. May be changed at runtime.
+
+### `connection.initUpdateTable(tableName)`
-***Abandoned feature, see notice:***
+Specify a table (as string) to use for storing the keys used for notifying updates to queries. The table will be created if it does not exist. To install for the first time, specify a table name that does not currently exist.
-Development of this feature has been abandoned in favor of using MySQL's binary replication logs to transmit updates.
+> When at all possible, it is recommended to use the binary log transmission method (`initBinlog()`).
-The [ZongJi NPM Module](https://github.com/nevill/zongji) has been completed and development of a `mysql-live-select` NPM module to use as the core component for this project is beginning. 2014/12/31
+The update table method automatically installs a new table as well as triggers on any tables that need to be watched. This transmission method limits the number of Meteor servers acting as client to the MySQL server to 1.
### `connection.select(subscription, options)`
@@ -54,16 +62,45 @@ Option | Type | Required | Description
------|-------|-----------|--------------
`query`|`string` or `function` | Required | Query to perform
`triggers`|`array`| Required | Description of triggers to refresh query
-`pollInterval` | `number` | Optional | Poll delay duration in milliseconds
+`pollInterval` | `number` | Optional | Poll delay duration in milliseconds (only used with the Update Table, not Binary log)
Each trigger object may contain the following properties:
Name | Type | Required | Description
-----|-------| --------|--------------
`table` | `string` | Required | Name of table to hook trigger
-`condition` | `string` or `function` | Optional | Access new row on insert or old row on update/delete using `$ROW`
*Example:*
`$ROW.name = "dude" or $ROW.score > 200`
+`condition` | `string` or `function` | Optional | Provide a conditional to filter rows
-**Notes:**
+#### Trigger Conditions
+
+Trigger conditions are defined differently based on the transmission method used:
+
+**Binary Log**
+
+When using the binary log transmission method (`initBinlog()`), a condition function accepts one or two arguments:
+
+Argument Name | Description
+--------------|-----------------------------
+`row` | Table row data
+`newRow` | New row data (only available on `UPDATE` queries)
+
+Return `true` when the row data meets the condition to update the result set.
+
+```javascript
+function(row, newRow){ return row.id === myId }
+```
+
+**Update Table**
+
+When using the update table transmision method (`initUpdateTable()`), a condition can be either string or function (in the `queryEx()` syntax).
+
+Access new row on insert or old row on update/delete using `$ROW`. This snippet is inserted into a SQL trigger so be very careful with the formatting.
+
+```
+$ROW.name = "dude" or $ROW.score > 200
+```
+
+#### Notes
* When a function is allowed in place of a string, use the `queryEx()` argument structure to escape values and identifiers.
diff --git a/context.md b/context.md
deleted file mode 100644
index faf13c0..0000000
--- a/context.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# Implementation Context
-
-In MySQL, triggers can not call the external environment without a UDF (user defined function) that must be compiled for the individual machine and able to be executed by any MySQL user. Please see this [StackOverflow answer about executing external programs from MySQL](http://stackoverflow.com/a/20439489). If you're more interested in trigger practices, be sure to read the linked article, [The Trouble with Triggers](http://www.oracle.com/technetwork/issue-archive/2008/08-sep/o58asktom-101055.html).
-
-Polling a table that is updated by triggers has been chosen as the method to update each select statement as the easiest option to reach. By compiling live-select update queries into `AFTER` triggers on each event (`INSERT`, `UPDATE`, and `DELETE`), a separate table keeps track of last updated triggers keyed by a hash generated from the table name and conditions for each select query published.
-
-## Next Frontier
-
-Multiple paths for notification of updates are available:
-
-Transmission method | Pros | Cons
---------------------|------|-------
-Poll Table |
| - Requires potentially slow recurring select poll
-UDF TCP Callback | | - Complicated setup
- Requires `ROOT` access
- Requires installing MySQL development packages
-`FILE` privilege export | | - Potentially insecure
- Support blocked on some hosting
-Binary Log | - Most similar to Oplog
- Least intrusive on schema
| - MySQL server must be configured to output binary log
-
-Benchmark comparing 2 repetitions of poll table, UDF callback, Mongo using Meteor interface, and Mongo using [`thinksoftware:mongo-direct` package](https://github.com/thinksoftware/meteor-mongo-direct/):
-
-![Benchmark graph output](benchmark-141211.png)
-
-Slower performance with UDF callback may be due to the fact that every row changed triggers a TCP callback while with the polling table, each row change results in only an update to a memory table value.
-
-### UDF TCP callback
-
-To realize OPLOG-esque integration with MySQL, a UDF written in C/C++ may be compiled and installed on the machine running MySQL server. `sudo` or `root` access is required to install the UDF in MySQL's plugin directory.
-
-Keeping the same package interface, a UDF backed update transmission option would offer lower latency and greater reliability.
-
-Trigger action bodies could change from conditionals that operate on an update polling table like this:
-
-```sql
-IF NEW.name = 'Maxwell' THEN
- UPDATE `perf_updates` as p
- JOIN (
- SELECT p1.`update` FROM `perf_updates` as p1
- ORDER BY p1.`update` DESC LIMIT 1) as g
- SET p.`update`= g.`update` + 1
- WHERE `key` = 2103814563;
-END IF;
-```
-
-To much simpler ones like this that would instantly broadcast updates to Meteor:
-```sql
-IF NEW.name = 'Maxwell' THEN
- DO meteor_update(3303291040);
-END IF;
-```
-
-See the [main readme about `initUpdateServer()`](https://github.com/numtel/meteor-mysql#connectioninitupdateserverport-hostname)...
-
-### `FILE` privilege
-
-MySQL supports a `FILE` privilege on users that allows data to be read and written to the filesystem. The use of this privilege presents a security risk and is not supported by many hosting providers.
-
-### Binary log
-
-Obtain direct log of changes to database.
-
-By using Statement-Based replication, the binary log can be tailed. This process can be slow though: a file (that can grow to be many gigabytes) must be watched for new statements or rows. Found solutions for MySQL binlog tailing in Javascript utilize the `watch()` or `watchFile()` method of the `fs` module, polling for changes to the [statistics of the] file.
-
-* [Script that uses `mysqlbinlog`](https://gist.github.com/petethomas/1572119) - Example of using `mysqlbinlog` command line interpreter included with MySQL
-* [Another script](https://gist.github.com/laverdet/958588) - Does not work in my tests, but it looks like it would parse a binlog in `statement` mode. `statement` mode results in a smaller replication log but for determining when to refresh a `select` statement, `row` mode is required unless a full replication of the data is kept.
-* [ZongJi NPM module](https://github.com/nevill/zongji) - Similar to the first example that uses `mysqlbinlog` except the binlog parser is written entirely in Javascript. Very promising but not finished, many column types still need to be supported.
-* [Hupu NPM module](https://github.com/HupuInc/node-mysql-listener) - Not tested but requires C++ compilation so probably not a good option as `sudo` or `root` would be required for installation along with the MySQL development package.
-
-The main advantage to using the Binlog would be to enable updates without modifying the underlying database with triggers. Theoretically, realizing Binlog updates appears as an ultimate solution to Meteor-MySQL integration but benchmarks and real world performance are necessary to tell the full story.
-
-The [ZongJi NPM Module](https://github.com/nevill/zongji) has been completed and development of a `mysql-live-select` NPM module is beginning. 2014/12/31
-
-## Postgres Sequel
-
-Postgres allows functions accessing external resources to be written using `plperlu` scripts (only as a super user). More research is required to determine whether this a path to a reactive Postgres integration without polling a table.
-
diff --git a/getting_started.md b/getting_started.md
index 140a010..e68625d 100644
--- a/getting_started.md
+++ b/getting_started.md
@@ -8,6 +8,8 @@ $ meteor add numtel:mysql
Publish a select statement, specifying when to refresh the query. By utilizing triggers and a highly optimized update table, polling queries are very simple and run quickly.
+> This tutorial displays how to utilize the update table transmission method. See the readme about using the Binary log transmission method for a more robust solution.
+
```javascript
// On the server
diff --git a/lib/binlogSelect.js b/lib/binlogSelect.js
new file mode 100644
index 0000000..31bca77
--- /dev/null
+++ b/lib/binlogSelect.js
@@ -0,0 +1,46 @@
+// numtel:mysql
+// MIT License, ben@latenightsketches.com
+// lib/binlogSelect.js
+
+binlogSelect = function(subscription, query, triggers){
+ var self = this;
+ var select = self._binlog.select(query, triggers);
+ var initLength;
+
+ // Send reset message (for code pushes)
+ subscription._session.send({
+ msg: 'added',
+ collection: subscription._name,
+ id: subscription._subscriptionId,
+ fields: { reset: true }
+ });
+
+ select.on('update', function(rows){
+ if(subscription._ready === false){
+ initLength = rows.length;
+ }
+ });
+
+ function selectHandler(eventName, fieldArgument, indexArgument, customAfter){
+ // Events from mysql-live-select are the same names as the DDP msg types
+ select.on(eventName, function(/* row, [newRow,] index */){
+ subscription._session.send({
+ msg: eventName,
+ collection: subscription._name,
+ id: subscription._subscriptionId + ':' + arguments[indexArgument],
+ fields: fieldArgument !== null ? arguments[fieldArgument] : undefined
+ });
+ if(customAfter) customAfter();
+ });
+ }
+
+ selectHandler('added', 0, 1, function(){
+ if(subscription._ready === false &&
+ select.data.length === initLength - 1){
+ subscription.ready();
+ }
+ });
+ selectHandler('changed', 1, 2);
+ selectHandler('removed', null, 1);
+
+};
diff --git a/lib/meteor_update.c b/lib/meteor_update.c
deleted file mode 100644
index 1fcfeb0..0000000
--- a/lib/meteor_update.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
-numtel:mysql
-MIT License, ben@latenightsketches.com
-lib/meteor_update.c
-
-User Defined Function (UDF) to broadcast database updates back to Meteor.
-
-Install dependency (on Ubuntu):
-sudo apt-get install libmysqlclient-dev
-
-Compile:
-gcc $(mysql_config --cflags) -shared -fPIC -o meteor_update.so lib/meteor_update.c
-
-Install:
-sudo cp meteor_update.so $(mysql_config --plugindir)
-
-Use connection.initUpdateServer() instead of initUpdateTable()
-
-*/
-
-#ifdef STANDARD
-/* STANDARD is defined, don't use any mysql functions */
-#include
-#include
-#include
-#include
-#ifdef __WIN__
-typedef unsigned __int64 ulonglong; /* Microsofts 64 bit types */
-typedef __int64 longlong;
-#else
-typedef unsigned long long ulonglong;
-typedef long long longlong;
-#endif /*__WIN__*/
-#else
-#include
-#include
-#if defined(MYSQL_SERVER)
-#include /* To get strmov() */
-#else
-/* when compiled as standalone */
-#include
-#define strmov(a,b) stpcpy(a,b)
-#define bzero(a,b) memset(a,0,b)
-#endif
-#endif
-#include
-#include
-
-#ifdef HAVE_DLOPEN
-
-#ifdef __WIN__
-#include
-#else
-#include
-#include
-#include
-#include
-#endif
-
-my_bool meteor_update_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
-void meteor_update_deinit(UDF_INIT *initid);
-char *meteor_update(UDF_INIT *initid, UDF_ARGS *args, char *result,
- unsigned long *length, char *null_value, char *error);
-
-
-my_bool meteor_update_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
-{
- if (args->arg_count != 1 || args->arg_type[0] != STRING_RESULT)
- {
- strmov(message,"Wrong arguments to lookup; Use the source");
- return 1;
- }
- initid->max_length=11;
- initid->maybe_null=1;
- return 0;
-}
-
-void meteor_update_deinit(UDF_INIT *initid __attribute__((unused)))
-{
-}
-
-char *meteor_update(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
- char *result, unsigned long *res_length, char *null_value,
- char *error __attribute__((unused)))
-{
- uint length;
- char msg_buffer[256];
- struct hostent *hostent;
- int sockfd, portno, n;
- struct sockaddr_in serv_addr;
- struct hostent *server;
-
- if (!args->args[0] || !(length=args->lengths[0]))
- {
- *null_value=1;
- return 0;
- }
- if (length >= sizeof(msg_buffer))
- length=sizeof(msg_buffer)-1;
- memcpy(msg_buffer,args->args[0],length);
- msg_buffer[length]=0;
-
- portno = 9801;
- sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if (sockfd < 0)
- {
- *null_value=1;
- return 0;
- }
- server = gethostbyname("localhost");
- if (server == NULL)
- {
- *null_value=1;
- return 0;
- }
- bzero((char *) &serv_addr, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- bcopy((char *)server->h_addr,
- (char *)&serv_addr.sin_addr.s_addr,
- server->h_length);
- serv_addr.sin_port = htons(portno);
- if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
- {
- *null_value=1;
- return 0;
- }
- n = write(sockfd,msg_buffer,strlen(msg_buffer));
- close(sockfd);
-
- return result;
-}
-
-#endif
diff --git a/lib/mysql.js b/lib/mysql.js
index 5b9329f..ec6228c 100644
--- a/lib/mysql.js
+++ b/lib/mysql.js
@@ -4,6 +4,7 @@
// lib/mysql.js
var Future = Npm.require('fibers/future');
+var LiveMysql = Npm.require('mysql-live-select');
mysql = Npm.require('mysql');
// Wrap original createConnection method
@@ -41,20 +42,9 @@ var mysqlMethods = {
}));
return fut.wait();
},
- initUpdateServer: function(port, selfHost){
+ initBinlog: function(settings){
var self = this;
- self._updatedKeys = [];
- self._updatePort = port || 9801;
- self._updatehost = selfHost || 'localhost';
- var net = Npm.require('net');
- net.createServer(function(sock) {
- sock.on('data', function(data) {
- self._updatedKeys.push(parseInt(data, 10));
- });
- }).listen(self._updatePort, self._updateHost);
- self.queryEx('DROP FUNCTION IF EXISTS `meteor_update`;');
- self.queryEx('CREATE FUNCTION meteor_update RETURNS STRING ' +
- 'SONAME "meteor_update.so";');
+ self._binlog = new LiveMysql(settings);
},
initUpdateTable: function(tableName){
var self = this;
@@ -73,11 +63,14 @@ var mysqlMethods = {
},
select: function(subscription, options){
var self = this;
- if(self._updatedKeys === undefined &&
- self._updateTable === undefined)
- throw new Error('no-update-mechanism');
- initTriggers.call(self, options.triggers);
- syncSelect.call(self, subscription, options);
+ if(self._binlog){
+ binlogSelect.call(self, subscription, options.query, options.triggers);
+ }else if(self._updateTable){
+ initTriggers.call(self, options.triggers);
+ syncSelect.call(self, subscription, options);
+ }else{
+ throw new Error('no-update-mechanism');
+ }
}
};
diff --git a/lib/syncSelect.js b/lib/syncSelect.js
index 24523e8..7a0c28b 100644
--- a/lib/syncSelect.js
+++ b/lib/syncSelect.js
@@ -76,15 +76,7 @@ var pollUpdateTable = function(connMeta){
var managePoll = function(){
_.each(connBuffer, function(connMeta){
- var updatedKeys;
- if(connMeta.conn._updatedKeys !== undefined){
- // Updated keys come from UDF callbacks
- updatedKeys = connMeta.conn._updatedKeys.splice(0,
- connMeta.conn._updatedKeys.length);
- }else{
- // Updated keys come from poll table
- updatedKeys = pollUpdateTable(connMeta);
- }
+ var updatedKeys = pollUpdateTable(connMeta);
_.each(selectBuffer, function(selectMeta){
if(selectMeta.conn === connMeta.conn){
_.each(selectMeta.updateKeys, function(updateKey){
diff --git a/package.js b/package.js
index 952ed51..fc3e622 100644
--- a/package.js
+++ b/package.js
@@ -1,12 +1,13 @@
Package.describe({
name: 'numtel:mysql',
summary: 'MySQL support with Reactive Select Subscriptions',
- version: '0.0.14',
+ version: '0.0.15',
git: 'https://github.com/numtel/meteor-mysql.git'
});
Npm.depends({
- mysql: '2.5.3'
+ 'mysql': '2.5.4',
+ 'mysql-live-select': '0.0.6'
});
Package.onUse(function(api) {
@@ -20,6 +21,7 @@ Package.onUse(function(api) {
'dist/murmurhash3_gc.js',
'lib/initTriggers.js',
'lib/syncSelect.js',
+ 'lib/binlogSelect.js',
'lib/mysql.js'
], 'server');
api.addFiles([
diff --git a/test/MysqlSubscription.js b/test/MysqlSubscription.js
index 37eefda..a74ae3f 100644
--- a/test/MysqlSubscription.js
+++ b/test/MysqlSubscription.js
@@ -59,41 +59,23 @@ function(test, done){
test.equal(arguments.length, 2);
eventRecords.push('removed');
});
- Meteor.call('getQueries', function(error, startQueries){
- // NOTE: On server, the result argument of the Meteor method call is
- // passed by reference, i.e. startQueries===endQueries
- var startQueriesLength = startQueries.length;
- Meteor.call('insPlayer', newPlayer, 100);
+ Meteor.call('insPlayer', newPlayer, 100);
+ Meteor.setTimeout(function(){
+ var newExpected = expectedRows.slice();
+ newExpected.unshift({ name: newPlayer, score: 100 });
+ test.equal(expectResult(players, newExpected), true, 'Row inserted');
+ Meteor.call('delPlayer', newPlayer);
Meteor.setTimeout(function(){
- var newExpected = expectedRows.slice();
- newExpected.unshift({ name: newPlayer, score: 100 });
- test.equal(expectResult(players, newExpected), true, 'Row inserted');
- Meteor.call('delPlayer', newPlayer);
- Meteor.call('getQueries', function(error, endQueries){
- var newQueries =
- filterPollQueries(endQueries.slice(startQueriesLength));
- var newQueriesResult = expectResult(newQueries, [
- /^insert into `players`/i,
- /^select \* from players/i,
- /^delete from `players`/i
- ]);
- if(newQueriesResult !== true){
- console.log(newQueries);
- }
- test.equal(newQueriesResult, true, 'Only running correct queries');
- Meteor.setTimeout(function(){
- players.removeEventListener(/test1/);
- test.equal(expectResult(eventRecords, [
- 'update', 'changed', 'update', 'changed', 'update', 'changed',
- 'update', 'changed', 'update', 'added', 'update', 'changed',
- 'update', 'changed', 'update', 'changed', 'update', 'changed',
- 'update', 'removed']), true, 'Expected events firing');
- test.equal(expectResult(players, expectedRows), true, 'Row removed');
- done();
- }, POLL_WAIT);
- });
+ players.removeEventListener(/test1/);
+ test.equal(expectResult(eventRecords, [
+ 'update', 'changed', 'update', 'changed', 'update', 'changed',
+ 'update', 'changed', 'update', 'added', 'update', 'changed',
+ 'update', 'changed', 'update', 'changed', 'update', 'changed',
+ 'update', 'removed']), true, 'Expected events firing');
+ test.equal(expectResult(players, expectedRows), true, 'Row removed');
+ done();
}, POLL_WAIT);
- });
+ }, POLL_WAIT);
});
Tinytest.addAsync(SUITE_PREFIX + 'Conditional Trigger Update',
diff --git a/test/benchmark/insertMany.js b/test/benchmark/insertMany.js
index ed8dcad..8052d7d 100644
--- a/test/benchmark/insertMany.js
+++ b/test/benchmark/insertMany.js
@@ -3,7 +3,7 @@
// test/benchmark/insertMany.js
// Benchmark number of inserts published to client per second
-// Compare MySQL poll table, UDF TCP callback, Mongo, and Mongo-Direct
+// Compare MySQL poll table, MySQL binlog, Mongo, and Mongo-Direct
var genMysqlTest = function(prefix){
var subscription = new MysqlSubscription(prefix + 'players');
return {
@@ -78,10 +78,10 @@ Benchmark.addCase({
count: 1000,
sampleSize: 1,
// Explictly specify methods for easy omission
- methods: ['mysql-poll', 'mysql-udf', 'mongo-standard', 'mongo-direct']
+ methods: ['mysql-poll', 'mysql-binlog', 'mongo-standard', 'mongo-direct']
},
'mysql-poll': genMysqlTest('benchmark_poll_'),
- 'mysql-udf': genMysqlTest('benchmark_udf_'),
+ 'mysql-binlog': genMysqlTest('benchmark_binlog_'),
'mongo-standard': genMongoTest('insDocs'),
'mongo-direct': genMongoTest('insDocsDirect')
});
diff --git a/test/benchmark/server.mysql.js b/test/benchmark/server.mysql.js
index b484f34..bcadbba 100644
--- a/test/benchmark/server.mysql.js
+++ b/test/benchmark/server.mysql.js
@@ -14,9 +14,13 @@ var connections = [
}
]
-Meteor.settings.udf && connections.push({
- tablePrefix: 'benchmark_udf_',
- init: function(conn){ conn.initUpdateServer(); }
+Meteor.settings.binlog && connections.push({
+ tablePrefix: 'benchmark_binlog_',
+ init: function(conn){
+ var settings = _.clone(Meteor.settings.mysql);
+ settings.serverId++; // Unique serverId required
+ conn.initBinlog(settings);
+ }
});
connections.forEach(function(def){
diff --git a/test/mock.connection.query.js b/test/mock.connection.query.js
index 0d6ac45..5c12568 100644
--- a/test/mock.connection.query.js
+++ b/test/mock.connection.query.js
@@ -3,7 +3,6 @@
// test/mock.connection.query.js
// Mock connection.query function to record processed queries
-queries = [];
// 2 Underscores as it's been wrapped once already
mysql.__createConnection = mysql.createConnection;
@@ -11,8 +10,9 @@ mysql.createConnection = function(config){
var result = mysql.__createConnection(config);
if(typeof result === 'object'){
var origQueryMethod = result.query;
+ result.__queries = [];
result.query = function(query, callback){
- queries.push(query);
+ result.__queries.push(query);
return origQueryMethod.apply(this, arguments);
}
}
diff --git a/test/mysql.js b/test/mysql.js
index bd18ac7..d30b2cf 100644
--- a/test/mysql.js
+++ b/test/mysql.js
@@ -15,8 +15,12 @@ Meteor.startup(function(){
db.queryEx(function(esc, escId){
return 'drop table if exists ' + escId(updateTable);
});
- db.initUpdateTable(updateTable);
-// db.initUpdateServer();
+
+ if(Meteor.settings.binlog){
+ db.initBinlog(Meteor.settings.mysql);
+ }else{
+ db.initUpdateTable(updateTable);
+ }
Meteor.publish('allPlayers', function(){
db.select(this, {
@@ -36,8 +40,8 @@ Meteor.startup(function(){
triggers: [
{
table: 'players',
- condition: function(esc, escId){
- return '$ROW.name = ' + esc(name);
+ condition: function(row, newRow){
+ return row.name === name;
}
}
]
@@ -63,7 +67,7 @@ Meteor.startup(function(){
});
},
'getQueries': function(){
- return queries; // test/mock.connection.query.js
+ return db.__queries; // test/mock.connection.query.js
}
});
@@ -128,6 +132,9 @@ Tinytest.add(SUITE_PREFIX + 'initUpdateTable', function(test){
});
Tinytest.add(SUITE_PREFIX + 'Trigger contents preserved', function(test){
+ var table = db._updateTable;
+ if(!table) return; // Only run test in poll table mode
+
var result = db.queryEx(function(esc, escId){
return [
"SELECT ACTION_STATEMENT AS body",
diff --git a/test/settings.local.json b/test/settings.local.json
index 674fe10..cd077cd 100644
--- a/test/settings.local.json
+++ b/test/settings.local.json
@@ -3,7 +3,9 @@
"host": "localhost",
"user": "root",
"password": "numtel",
- "database": "test_package"
+ "database": "test_package",
+ "serverId": 129,
+ "minInterval": 200
},
- "udf": true
+ "binlog": false
}
diff --git a/test/settings.travis.json b/test/settings.travis.json
index 452416f..f132d64 100644
--- a/test/settings.travis.json
+++ b/test/settings.travis.json
@@ -5,5 +5,5 @@
"password": "",
"database": "myapp_test"
},
- "udf": false
+ "binlog": false
}