Skip to content

Commit

Permalink
Merge pull request #11 from Terminal-Systems/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
dmerrill6 authored Apr 1, 2019
2 parents 5ac6a2d + d528ec5 commit 083898a
Show file tree
Hide file tree
Showing 15 changed files with 349 additions and 45 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-cursor-pagination",
"version": "0.3.0-alpha-3",
"version": "0.3.1",
"description": "Relay's Connection implementation for Apollo Server GraphQL library",
"main": "dist/index.js",
"repository": "https://github.com/Terminal-Systems/apollo-cursor-pagination",
Expand Down
52 changes: 24 additions & 28 deletions src/builder/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@ const applyCursorsToNodes = (
removeNodesBeforeAndIncluding,
removeNodesAfterAndIncluding,
}, {
orderColumn, ascOrDesc,
orderColumn, ascOrDesc, isAggregateFn, formatColumnFn,
},
) => {
let nodesAccessor = allNodesAccessor;
if (after !== undefined) {
nodesAccessor = removeNodesBeforeAndIncluding(nodesAccessor, after, { orderColumn, ascOrDesc });
nodesAccessor = removeNodesBeforeAndIncluding(nodesAccessor, after, {
orderColumn, ascOrDesc, isAggregateFn, formatColumnFn,
});
}
if (before !== undefined) {
nodesAccessor = removeNodesAfterAndIncluding(nodesAccessor, before, { orderColumn, ascOrDesc });
nodesAccessor = removeNodesAfterAndIncluding(nodesAccessor, before, {
orderColumn, ascOrDesc, isAggregateFn, formatColumnFn,
});
}
return nodesAccessor;
};
Expand All @@ -47,7 +51,7 @@ const nodesToReturn = async (
{
before, after, first, last,
}, {
orderColumn, ascOrDesc,
orderColumn, ascOrDesc, isAggregateFn, formatColumnFn,
},
) => {
const orderedNodesAccessor = orderNodesBy(allNodesAccessor, orderColumn, ascOrDesc);
Expand All @@ -58,7 +62,7 @@ const nodesToReturn = async (
removeNodesBeforeAndIncluding,
removeNodesAfterAndIncluding,
}, {
orderColumn, ascOrDesc,
orderColumn, ascOrDesc, isAggregateFn, formatColumnFn,
},
);

Expand Down Expand Up @@ -90,12 +94,14 @@ const hasPreviousPage = async (allNodesAccessor,
}, {
before, after, first, last,
}, {
orderColumn, ascOrDesc,
orderColumn, ascOrDesc, isAggregateFn, formatColumnFn,
}) => {
if (last) {
const nodes = applyCursorsToNodes(allNodesAccessor, { before, after }, {
removeNodesBeforeAndIncluding, removeNodesAfterAndIncluding,
}, { orderColumn, ascOrDesc });
}, {
orderColumn, ascOrDesc, isAggregateFn, formatColumnFn,
});
const length = await getNodesLength(nodes);
if (length > last) return true;
}
Expand All @@ -118,12 +124,14 @@ const hasNextPage = async (allNodesAccessor,
}, {
before, after, first, last,
}, {
orderColumn, ascOrDesc,
orderColumn, ascOrDesc, isAggregateFn, formatColumnFn,
}) => {
if (first) {
const nodes = applyCursorsToNodes(allNodesAccessor, { before, after }, {
removeNodesBeforeAndIncluding, removeNodesAfterAndIncluding,
}, { orderColumn, ascOrDesc });
}, {
orderColumn, ascOrDesc, isAggregateFn, formatColumnFn,
});
const length = await getNodesLength(nodes);
if (length > first) return true;
}
Expand All @@ -133,18 +141,9 @@ const hasNextPage = async (allNodesAccessor,

const totalCount = async (allNodesAccessor,
{
removeNodesBeforeAndIncluding,
removeNodesAfterAndIncluding,
getNodesLength,
}, {
before, after,
}, {
orderColumn, ascOrDesc,
}) => {
const nodes = applyCursorsToNodes(allNodesAccessor, { before, after }, {
removeNodesBeforeAndIncluding, removeNodesAfterAndIncluding,
}, { orderColumn, ascOrDesc });
const length = await getNodesLength(nodes);
const length = await getNodesLength(allNodesAccessor);
return length;
};

Expand All @@ -167,6 +166,7 @@ const apolloCursorPaginationBuilder = ({
},
opts = {},
) => {
const { isAggregateFn, formatColumnFn } = opts;
let {
orderColumn, ascOrDesc,
} = opts;
Expand All @@ -189,13 +189,13 @@ const apolloCursorPaginationBuilder = ({
}, {
before, after, first, last,
}, {
orderColumn, ascOrDesc,
orderColumn, ascOrDesc, isAggregateFn, formatColumnFn,
},
);
const edges = convertNodesToEdges(nodes, {
before, after, first, last,
}, {
orderColumn,
orderColumn, ascOrDesc, isAggregateFn, formatColumnFn,
});
return {
pageInfo: {
Expand All @@ -204,22 +204,18 @@ const apolloCursorPaginationBuilder = ({
}, {
before, after, first, last,
}, {
orderColumn, ascOrDesc,
orderColumn, ascOrDesc, isAggregateFn, formatColumnFn,
}),
hasNextPage: hasNextPage(allNodesAccessor, {
removeNodesBeforeAndIncluding, removeNodesAfterAndIncluding, getNodesLength,
}, {
before, after, first, last,
}, {
orderColumn, ascOrDesc,
orderColumn, ascOrDesc, isAggregateFn, formatColumnFn,
}),
},
totalCount: totalCount(allNodesAccessor, {
removeNodesBeforeAndIncluding, removeNodesAfterAndIncluding, getNodesLength,
}, {
before, after, first, last,
}, {
orderColumn, ascOrDesc,
getNodesLength,
}),
edges,
};
Expand Down
52 changes: 38 additions & 14 deletions src/orm-connectors/knex/custom-pagination.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,42 +32,66 @@ const getDataFromCursor = (cursor) => {
if (data[0] === undefined || data[1] === undefined) {
throw new Error(`Could not find edge with cursor ${cursor}`);
}
return data;
const values = data[1].split(ARRAY_DATA_SEPARATION_TOKEN).map(v => JSON.parse(v));
return [data[0], values];
};

const formatColumnIfAvailable = (column, formatColumnFn) => {
if (formatColumnFn) {
return formatColumnFn(column);
}
return column;
};

const buildRemoveNodesFromBeforeOrAfer = (beforeOrAfter) => {
const getComparator = (orderDirection) => {
if (beforeOrAfter === 'after') return orderDirection === 'asc' ? '<' : '>';
return orderDirection === 'asc' ? '>' : '<';
};
return (nodesAccessor, cursorOfInitialNode, { orderColumn, ascOrDesc }) => {
return (nodesAccessor, cursorOfInitialNode, {
orderColumn, ascOrDesc, isAggregateFn, formatColumnFn,
}) => {
const data = getDataFromCursor(cursorOfInitialNode);
const [id, columnValue] = data;
const initialValue = nodesAccessor.clone();

const result = operateOverScalarOrArray(initialValue, orderColumn, (orderBy, index, prev) => {
let orderDirection;
let value;
const values = columnValue.split(ARRAY_DATA_SEPARATION_TOKEN);
const values = columnValue;
let currValue;
if (index !== null) {
orderDirection = ascOrDesc[index].toLowerCase();
value = values[index];
currValue = values[index];
} else {
orderDirection = ascOrDesc.toLowerCase();
value = columnValue;
currValue = values[0];
}
const comparator = getComparator(orderDirection);

if (index > 0) {
const nested = prev.orWhere(function () {
this.where(orderColumn[index], `${comparator}=`, values[index])
.andWhere(orderColumn[index - 1], '=', values[index - 1]);
});
const operation = (isAggregateFn && isAggregateFn(orderColumn[index - 1])) ? 'orHavingRaw' : 'orWhereRaw';
const nested = prev[operation](
`(${formatColumnIfAvailable(orderColumn[index - 1], formatColumnFn)} = ? and ${formatColumnIfAvailable(orderBy, formatColumnFn)} ${comparator} ?)`,
[values[index - 1], values[index]],
);

return nested;
}

return prev.where(orderBy, index === null ? `${comparator}=` : comparator, value);
}, prev => prev.whereNot({ id }));
const operation = (isAggregateFn && isAggregateFn(orderBy)) ? 'havingRaw' : 'whereRaw';

return prev[operation](`(${formatColumnIfAvailable(orderBy, formatColumnFn)} ${comparator} ?)`, [currValue]);
}, (prev, isArray) => {
// Result is sorted by id as the last column
const comparator = getComparator(ascOrDesc);
const lastOrderColumn = isArray ? orderColumn.pop() : orderColumn;
const lastValue = columnValue.pop();
const operation = (isAggregateFn && isAggregateFn(lastOrderColumn)) ? 'orHavingRaw' : 'orWhereRaw';
const nested = prev[operation](
`(${formatColumnIfAvailable(lastOrderColumn, formatColumnFn)} = ? and ${formatColumnIfAvailable('id', formatColumnFn)} ${comparator} ?)`,
[lastValue, id],
);
return nested;
});
return result;
};
};
Expand Down Expand Up @@ -126,7 +150,7 @@ const convertNodesToEdges = (nodes, _, {
}) => nodes.map((node) => {
const dataValue = operateOverScalarOrArray('', orderColumn, (orderBy, index, prev) => {
const nodeValue = node[orderBy];
const result = `${prev}${index ? ARRAY_DATA_SEPARATION_TOKEN : ''}${nodeValue}`;
const result = `${prev}${index ? ARRAY_DATA_SEPARATION_TOKEN : ''}${JSON.stringify(nodeValue)}`;
return result;
});

Expand Down
28 changes: 28 additions & 0 deletions tests/test-app/compiled-dist/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"use strict";

var _apolloServer = require("apollo-server");

var _schema = _interopRequireDefault(require("./schema"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

// import createLoaders from './loaders';
const server = new _apolloServer.ApolloServer({
schema: _schema.default,
formatError: error => {
console.log(error);
return error;
},
formatResponse: response => {
console.log(response);
return response;
},
engine: false,
tracing: true,
cacheControl: true
});
server.listen().then(({
url
}) => {
console.log(`🚀 Cats server ready at ${url}`);
});
16 changes: 16 additions & 0 deletions tests/test-app/compiled-dist/models/Cat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use strict";

const BaseModel = require('./base-model');

const knex = require('./db');

BaseModel.knex(knex);

class Cat extends BaseModel {
static get tableName() {
return 'cats';
}

}

module.exports = Cat;
23 changes: 23 additions & 0 deletions tests/test-app/compiled-dist/models/base-model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use strict";

const {
Model
} = require('objection'); // models/BaseModel.js


class BaseModel extends Model {
static get modelPaths() {
return [__dirname];
}

$beforeUpdate() {
this.updatedAt = new Date().toISOString();
}

$beforeInsert() {
this.createdAt = new Date().toISOString();
}

}

module.exports = BaseModel;
9 changes: 9 additions & 0 deletions tests/test-app/compiled-dist/models/db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"use strict";

const Knex = require('knex');

const knexOptions = require('../../knexfile');

const env = process.env.NODE_ENV || 'development';
const knex = Knex(knexOptions[env]);
module.exports = knex;
12 changes: 12 additions & 0 deletions tests/test-app/compiled-dist/queries/cat/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use strict";

var _catsConnection = _interopRequireDefault(require("./root/cats-connection"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

module.exports = {
Query: {
catsConnection: _catsConnection.default
},
Cat: {}
};
33 changes: 33 additions & 0 deletions tests/test-app/compiled-dist/queries/cat/root/cats-connection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"use strict";

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;

var _apolloCursorPagination = require("apollo-cursor-pagination");

var _Cat = _interopRequireDefault(require("../../../models/Cat"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var _default = async (_, args) => {
// const {
// first, last, before, after, orderBy, orderDirection, orderByMultiple, orderDirectionMultiple
// } = args;
const orderBy = args.orderBy || args.orderByMultiple;
const orderDirection = args.orderDirection || args.orderDirectionMultiple;

const baseQuery = _Cat.default.query().sum('id as idsum').select('cats.*').groupBy('id');

const result = await (0, _apolloCursorPagination.knexPaginator)(baseQuery, { ...args,
orderBy,
orderDirection
}, {
isAggregateFn: column => column === 'idsum',
formatColumnFn: column => column === 'idsum' ? 'sum(id)' : column
});
return result;
};

exports.default = _default;
Loading

0 comments on commit 083898a

Please sign in to comment.