Skip to content

Commit

Permalink
added support for connectionFields and adding where queries to connec…
Browse files Browse the repository at this point in the history
…tions
  • Loading branch information
mickhansen committed Nov 27, 2015
1 parent 79d7e95 commit 00176d8
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 105 deletions.
2 changes: 1 addition & 1 deletion src/generateIncludes.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default function generateIncludes(simpleAST, type, root, options) {
}
}

if (isConnection(fieldType)) {
if (isConnection(fieldType) && fieldAST.fields.edges) {
fieldAST = nodeAST(fieldAST);
fieldType = nodeType(fieldType);
}
Expand Down
203 changes: 115 additions & 88 deletions src/relay.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {

import _ from 'lodash';
import resolver from './resolver';
import simplifyAST from './simplifyAST';

class NodeTypeMapper {

Expand Down Expand Up @@ -79,11 +80,11 @@ export function nodeType(connectionType) {
return connectionType._fields.edges.type.ofType._fields.node.type;
}

export function sequelizeConnection({name, nodeType, target, orderBy: orderByEnum, before}) {
export function sequelizeConnection({name, nodeType, target, orderBy: orderByEnum, before, connectionFields, where}) {
const {
edgeType,
connectionType
} = connectionDefinitions({name, nodeType});
} = connectionDefinitions({name, nodeType, connectionFields});

const model = target.target ? target.target : target;
const SEPERATOR = '$';
Expand Down Expand Up @@ -128,111 +129,137 @@ export function sequelizeConnection({name, nodeType, target, orderBy: orderByEnu
};
};

return {
connectionType,
edgeType,
nodeType,
connectionArgs: $connectionArgs,
resolve: resolver(target, {
handleConnection: false,
include: true,
before: function (options, args) {
if (args.first || args.last) {
options.limit = parseInt(args.first || args.last, 10);
}
let argsToWhere = function (args) {
let result = {};

if (!args.orderBy) {
args.orderBy = [orderByEnum._values[0].value];
} else if (typeof args.orderBy === 'string') {
args.orderBy = [orderByEnum._nameLookup[args.orderBy].value];
}
_.each(args, (value, key) => {
if (key in $connectionArgs) return;
_.assign(result, where(key, value));
});

let orderBy = args.orderBy;
let orderAttribute = orderByAttribute(orderBy);
let orderDirection = args.orderBy[0][1];
return result;
};

if (args.last) {
orderDirection = orderDirection === 'ASC' ? 'DESC' : 'ASC';
}
let $resolver = resolver(target, {
handleConnection: false,
include: true,
before: function (options, args) {
if (args.first || args.last) {
options.limit = parseInt(args.first || args.last, 10);
}

options.order = [
[orderAttribute, orderDirection]
];
if (!args.orderBy) {
args.orderBy = [orderByEnum._values[0].value];
} else if (typeof args.orderBy === 'string') {
args.orderBy = [orderByEnum._nameLookup[args.orderBy].value];
}

if (orderAttribute !== model.primaryKeyAttribute) {
options.order.push([model.primaryKeyAttribute, 'ASC']);
}
let orderBy = args.orderBy;
let orderAttribute = orderByAttribute(orderBy);
let orderDirection = args.orderBy[0][1];

options.attributes.push(orderAttribute);
if (args.last) {
orderDirection = orderDirection === 'ASC' ? 'DESC' : 'ASC';
}

if (model.sequelize.dialect.name === 'postgres' && options.limit) {
options.attributes.push([
model.sequelize.literal('COUNT(*) OVER()'),
'full_count'
]);
}
options.order = [
[orderAttribute, orderDirection]
];

if (args.after || args.before) {
let cursor = fromCursor(args.after || args.before);
let orderValue = cursor.orderValue;
if (orderAttribute !== model.primaryKeyAttribute) {
options.order.push([model.primaryKeyAttribute, 'ASC']);
}

if (model.rawAttributes[orderAttribute].type instanceof model.sequelize.constructor.DATE) {
orderValue = new Date(orderValue);
}
options.attributes.push(orderAttribute);

options.where = options.where || {};
if (model.sequelize.dialect.name === 'postgres' && options.limit) {
options.attributes.push([
model.sequelize.literal('COUNT(*) OVER()'),
'full_count'
]);
}

let where = {
$or: [
{
[orderAttribute]: {
[orderDirection === 'ASC' ? '$gt' : '$lt']: orderValue
}
},
{
[orderAttribute]: {
$eq: orderValue
},
[model.primaryKeyAttribute]: {
$gt: cursor.id
}
}
]
};
options.where = argsToWhere(args);

// TODO, do a proper merge that won't kill another $or
_.assign(options.where, where);
}
if (args.after || args.before) {
let cursor = fromCursor(args.after || args.before);
let orderValue = cursor.orderValue;

return before(options);
},
after: function (values, args) {
if (!args.orderBy) {
args.orderBy = [orderByEnum._values[0].value];
if (model.rawAttributes[orderAttribute].type instanceof model.sequelize.constructor.DATE) {
orderValue = new Date(orderValue);
}

let edges = values.map((value) => {
return {
cursor: toCursor(value, args.orderBy),
node: value
};
});
let slicingWhere = {
$or: [
{
[orderAttribute]: {
[orderDirection === 'ASC' ? '$gt' : '$lt']: orderValue
}
},
{
[orderAttribute]: {
$eq: orderValue
},
[model.primaryKeyAttribute]: {
$gt: cursor.id
}
}
]
};

// TODO, do a proper merge that won't kill another $or
_.assign(options.where, slicingWhere);
}

let firstEdge = edges[0];
let lastEdge = edges[edges.length - 1];
let fullCount = values[0] && values[0].dataValues.full_count &&
parseInt(values[0].dataValues.full_count, 10) || 0;
return before(options);
},
after: function (values, args, root, {source}) {
if (!args.orderBy) {
args.orderBy = [orderByEnum._values[0].value];
}

let edges = values.map((value) => {
return {
edges,
pageInfo: {
startCursor: firstEdge ? firstEdge.cursor : null,
endCursor: lastEdge ? lastEdge.cursor : null,
hasPreviousPage: args.last !== null && args.last !== undefined ? fullCount > parseInt(args.last, 10) : false,
hasNextPage: args.first !== null && args.first !== undefined ? fullCount > parseInt(args.first, 10) : false,
}
cursor: toCursor(value, args.orderBy),
node: value
};
});

let firstEdge = edges[0];
let lastEdge = edges[edges.length - 1];
let fullCount = values[0] && values[0].dataValues.full_count &&
parseInt(values[0].dataValues.full_count, 10) || 0;

return {
source,
args,
where: argsToWhere(args),
edges,
pageInfo: {
startCursor: firstEdge ? firstEdge.cursor : null,
endCursor: lastEdge ? lastEdge.cursor : null,
hasPreviousPage: args.last !== null && args.last !== undefined ? fullCount > parseInt(args.last, 10) : false,
hasNextPage: args.first !== null && args.first !== undefined ? fullCount > parseInt(args.first, 10) : false,
}
};
}
});

return {
connectionType,
edgeType,
nodeType,
connectionArgs: $connectionArgs,
resolve: (source, args, info) => {
if (simplifyAST(info.fieldASTs[0], info).fields.edges) {
return $resolver(source, args, info);
}
})

return {
source,
args,
where: argsToWhere(args)
};
}
};
}
12 changes: 8 additions & 4 deletions src/resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ module.exports = function (target, options) {
}
return options.after(source.get(association.as), args, root, {
ast: simpleAST,
type: type
type: type,
source: source
});
}

Expand All @@ -77,7 +78,8 @@ module.exports = function (target, options) {

findOptions = options.before(findOptions, args, root, {
ast: simpleAST,
type: type
type: type,
source: source
});

if (!findOptions.order) {
Expand All @@ -91,14 +93,16 @@ module.exports = function (target, options) {
}
return options.after(result, args, root, {
ast: simpleAST,
type: type
type: type,
source: source
});
});
}
return model[list ? 'findAll' : 'findOne'](findOptions).then(function (result) {
return options.after(result, args, root, {
ast: simpleAST,
type: type
type: type,
source: source
});
});
};
Expand Down
Loading

0 comments on commit 00176d8

Please sign in to comment.