lib/relation.js
/**
* Copyright 2015 Oursky Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const _ = require('lodash');
import User from './user';
export const Outward = 'outward';
export const Inward = 'inward';
export const Mutual = 'mutual';
const format = /^[a-zA-Z]+$/;
export class Relation {
constructor(identifier, direction, targets = []) {
if (!Relation.validName(identifier)) {
throw new Error(
'Relation identifier can only be [a-zA-Z]+');
}
this.identifier = identifier;
if (Relation.validDirection(direction)) {
this.direction = direction;
} else {
throw new Error(
'Relation direction not supported.');
}
this.targets = targets;
this.fails = [];
}
get targetsID() {
return _.map(this.targets, function (user) {
return user.id;
});
}
static validDirection(direction) {
return direction === Mutual
|| direction === Outward
|| direction === Inward;
}
static validName(identifier) {
return format.test(identifier);
}
}
export class RelationQuery {
constructor(relationCls) {
this.identifier = relationCls.prototype.identifier;
this.direction = relationCls.prototype.direction;
this.limit = 50;
this.page = 0;
}
toJSON() {
return {
name: this.identifier,
direction: this.direction,
limit: this.limit,
page: this.page
};
}
}
export class RelationResult {
constructor(results) {
this.success = [];
this.fails = [];
this.partialError = false;
let len = results.length;
for (let i = 0; i < len; i++) {
if (results[i].type === 'error') {
this.fails.push(results[i]);
this.partialError = true;
} else {
this.success.push(new User(results[i].data));
}
}
}
}
export class RelationRemoveResult {
constructor(results) {
this.success = [];
this.fails = [];
this.partialError = false;
let len = results.length;
for (let i = 0; i < len; i++) {
if (results[i].type === 'error') {
this.fails.push(results[i]);
this.partialError = true;
} else {
this.success.push(results[i].id);
}
}
}
}
export class RelationQueryResult extends Array {
static createFromBody(body) {
let users = _.map(body.result, function (attrs) {
return new User(attrs.data);
});
let result = new RelationQueryResult();
users.forEach((val) => result.push(val));
let info = body.info;
result._overallCount = info ? info.count : undefined;
return result;
}
get overallCount() {
return this._overallCount;
}
}
export class RelationAction {
constructor(container) {
this.container = container;
}
query(queryObj) {
let relationAction = this;
return new Promise(function (resolve, reject) {
relationAction.container.makeRequest('relation:query', queryObj.toJSON())
.then(function (body) {
let users = RelationQueryResult.createFromBody(body);
resolve(users);
}, function (err) {
reject(err);
});
});
}
queryFriend(actor) {
if (actor === null) {
actor = this.container.currentUser;
}
let query = new RelationQuery(this.Friend);
query.user = actor;
return this.query(query);
}
queryFollower(actor) {
if (actor === null) {
actor = this.container.currentUser;
}
let query = new RelationQuery(this.Follower);
query.user = actor;
return this.query(query);
}
queryFollowing(actor) {
if (actor === null) {
actor = this.container.currentUser;
}
let query = new RelationQuery(this.Following);
query.user = actor;
return this.query(query);
}
add(relation) {
return new Promise(function (resolve, reject) {
this.container.makeRequest('relation:add', {
name: relation.identifier,
direction: relation.direction,
targets: relation.targetsID
}).then(function (body) {
let result = new RelationResult(body.result);
resolve(result);
}, function (err) {
reject(err);
});
}.bind(this));
}
remove(relation) {
return new Promise(function (resolve, reject) {
this.container.makeRequest('relation:remove', {
name: relation.identifier,
direction: relation.direction,
targets: relation.targetsID
}).then(function (body) {
let result = new RelationRemoveResult(body.result);
resolve(result);
}, function (err) {
reject(err);
});
}.bind(this));
}
get Query() {
return RelationQuery;
}
get Friend() {
return RelationAction.extend('friend', Mutual);
}
get Follower() {
return RelationAction.extend('follow', Inward);
}
get Following() {
return RelationAction.extend('follow', Outward);
}
static extend(identifier, direction) {
if (!Relation.validName(identifier)) {
throw new Error(
'Relation identifier can only be [a-zA-Z]+');
}
let RelationProto = {
identifier: identifier,
direction: direction
};
function RelationCls(targets = []) {
Relation.call(this, identifier, direction);
this.targets = targets;
}
RelationCls.prototype = _.create(Relation.prototype, RelationProto);
return RelationCls;
}
}