Permalink
Browse files

Fold feed rewatch into feed watch

  • Loading branch information...
lovett committed Aug 2, 2018
1 parent 9ffa107 commit 26e6d34e654476dc69803f81466abd82db664da9
1 .ackrc
@@ -1,5 +1,6 @@
--ignore-dir=coverage
--ignore-dir=docs
--ignore-dir=fixtures
--ignore-dir=.nyc_output
--ignore-dir=node_modules
--ignore-dir=static

This file was deleted.

Oops, something went wrong.
@@ -1,5 +1,14 @@
/** @module feed/watch */
'use strict';

/**
* Callback for the feed-watch event.
*
* @callback feedWatchCallback
* @param {error} [err] - Database error.
*
*/

/**
* Subscribe a user to one or more feeds.
*
@@ -8,41 +17,39 @@
* Polling is requested immediately after subscription creation to
* minimize delay of the initial fetch.
*
* @param {Number} userId - The unique identifier of a user.
* @param {Object[]} feeds - A list of objects with at least a url property.
* @event feed-watch
*
*/
module.exports = function (userId, feedIds, callback = () => {}) {
module.exports = function (userId, feeds=[], callback) {
const self = this;

function done (err, ids) {
callback(err, ids);
}

if (feedIds.length === 0) {
done(new Error('no feed ids given'), []);
if (!feeds || feeds.length === 0) {
callback(null);
return;
}

self.db.serialize(() => {
self.db.run('BEGIN TRANSACTION');

feedIds.forEach((feedId) => {
self.db.run(
'INSERT OR IGNORE INTO userFeeds (userId, feedId) VALUES (?, ?)',
[userId, feedId],
(err) => {
if (err) {
self.emit('log:error', `Failed to insert into userFeeds table: ${err.message}`);
return;
}
}
);
});

self.db.run('COMMIT', [], (err) => {
if (feedIds.length > 0) {
const placeholders = feeds.map(() => `(${userId}, ?, ?)`).join(',');

const values = feeds.reduce((accumulator, feed) => {
if (!feed.title) {
feed.title = null;
}
return accumulator.concat(feed.id, feed.title, feed.title);
}, []);

self.db.run(
`INSERT INTO userFeeds (userId, feedId, title) VALUES ${placeholders}
ON CONFLICT (userId, feedId) DO UPDATE SET title=?`,
values,
(err) => {

if (!err) {
self.emit('feed:poll', true);
}

done(err, feedIds);
});
});
callback(err);
}
);
};
@@ -18,6 +18,7 @@
* @listens startup
* @listens feed-watched
* @listens feed-unwatch
* @listens feed-watch
* @listens fetch-feed
* @listens fetch-hackernews
*/
@@ -50,8 +51,7 @@ emitter.on('schema', require('./schema'));

// Feeds
emitter.on('feed:poll', require('./feed/poll'));
emitter.on('feed:watch', require('./feed/watch'));
emitter.on('feed:rewatch', require('./feed/rewatch'));
emitter.on('feed-watch', require('./feed/watch'));
emitter.on('feed-unwatch', require('./feed/unwatch'));
emitter.on('feed-watched', require('./feed/watched'));
emitter.on('feed:add', require('./feed/add'));
@@ -24,7 +24,7 @@ module.exports = (req, res, next) => {

const feedIds = addResult.map(feed => feed.id);

dispatcher.emit('feed:watch', 1, feedIds, (err, watchResult) => {
dispatcher.emit('feed-watch', 1, feedIds, (err, watchResult) => {
res.send(watchResult);
next();
});
@@ -16,7 +16,7 @@ module.exports = (req, res, next) => {
return next(new errors.BadRequestError('Nothing to update'));
}

dispatcher.emit('feed:rewatch', 1, feeds, (err, result) => {
dispatcher.emit('feed-watch', 1, feeds, (err, result) => {
if (err) {
return next(new errors.InternalServerError(err.message));
}
@@ -8,35 +8,21 @@ const assert = require('assert');
const events = require('events');
const path = require('path');

describe('feed:watch', function() {
describe('feed-watch', function() {

beforeEach(function (done) {
const self = this;
this.schemaRoot = path.join(__dirname, '../../', 'schema');
const schemaRoot = path.join(__dirname, '../../', 'schema');
const fixtureRoot = path.join(__dirname, 'fixtures', 'feed-watch');
this.db = new sqlite3.Database(':memory:');
this.feedUrl = 'http://example.com/feed.rss';
this.emitter = new events.EventEmitter();
this.emitter.unlisten = function () {};
this.emitter.on('startup', startup);
this.emitter.on('schema', schema);
this.emitter.on('feed:watch', watch);
this.emitter.emit('startup', this.db, this.schemaRoot, () => {
self.db.serialize(() => {
self.db.run(
'INSERT INTO users (username, passwordHash) VALUES ("test", "test")',
function () {
self.userId = this.lastID;
}
);

self.db.run(
'INSERT INTO feeds (url, title) VALUES ("http://example.com/feed", "test feed")',
function () {
self.feedIds = [this.lastID];
done();
}
);
});
this.emitter.on('feed-watch', watch);
this.userId = 100;
this.emitter.emit('startup', this.db, schemaRoot, () => {
this.emitter.emit('schema', fixtureRoot, 2, done);
});
});

@@ -45,27 +31,62 @@ describe('feed:watch', function() {
this.emitter.removeAllListeners();
});

it('adds rows to the userFeeds tables', function (done) {
it('inserts to userFeeds table', function (done) {
const self = this;

self.emitter.emit('feed-watch', self.userId, [{ id: 201, title: 'my title'}], (err) => {
assert.ifError(err);

self.db.all('SELECT * FROM userFeeds', (selectErr, rows) => {
assert.ifError(selectErr);
assert.strictEqual(rows.length, 2);
assert.strictEqual(rows[1].title, 'my title');
done();
});
});
});

it('upserts when re-subscribing', function (done) {
const self = this;

self.emitter.emit('feed-watch', self.userId, [{id: 200, title: 'my other title'}], (err) => {
assert.ifError(err);

self.db.all('SELECT * FROM userFeeds', (selectErr, rows) => {
assert.ifError(selectErr);
assert.strictEqual(rows.length, 1);
assert.strictEqual(rows[0].title, 'my other title');
done();
});
});
});

it('handles empty list of feed ids', function (done) {
const self = this;

self.emitter.emit(
'feed:watch',
self.userId,
self.feedIds,
(err) => {
assert.strictEqual(err, null);

self.db.get(
'SELECT COUNT(*) as count FROM userFeeds',
function (err, row) {
if (err) {
throw err;
}
assert.strictEqual(row.count, 1);
done();
}
);
}
);
self.emitter.emit('feed-watch', self.userId, [], (err) => {
assert.ifError(err);

self.db.get('SELECT COUNT(*) as count FROM userFeeds', (countErr, row) => {
assert.ifError(countErr);
assert.strictEqual(row.count, 1);
done();
});
});
});

it('handles non-array value for feed list', function (done) {
const self = this;

self.emitter.emit('feed-watch', self.userId, null, (err) => {
assert.ifError(err);

self.db.get('SELECT COUNT(*) as count FROM userFeeds', (countErr, row) => {
assert.ifError(countErr);
assert.strictEqual(row.count, 1);
done();
});
});
});

});
@@ -0,0 +1,15 @@
--
-- Fixture for a user and feeds available for subscription.
--
INSERT INTO users (id, username, passwordHash)
VALUES (100, 'test', 'test');

INSERT INTO feeds (id, url)
VALUES (200, 'http://example.com/feed.rss'),
(201, 'http://example.com/feed2.rss'),
(202, 'http://example.com/feed3.rss');

INSERT INTO userFeeds (userId, feedId)
VALUES (100, 200);

INSERT INTO versions (schemaVersion) VALUES (2);

0 comments on commit 26e6d34

Please sign in to comment.