Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeffrey Young committed Oct 17, 2017
0 parents commit c25e1c8
Show file tree
Hide file tree
Showing 8 changed files with 1,179 additions and 0 deletions.
59 changes: 59 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

Binary file added db/db.sl3
Binary file not shown.
14 changes: 14 additions & 0 deletions db/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const db = require('sqlite');
const _ = require('lodash');
const faker = require('faker');
const {getAllUsers, batchGetUsers, batchGetFollowers} = require('./queries');
const setup = require('./setup');

module.exports = {
initialize: setup,
batchGetUsers: batchGetUsers,
batchGetFollowers: batchGetFollowers,
getAllUsers: getAllUsers
};


39 changes: 39 additions & 0 deletions db/queries.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const db = require('sqlite');
const _ = require('lodash');
const faker = require('faker');
let dbQueries = 0;
function logQuery(type) {
console.log('query', type, ++dbQueries);
}

async function batchGetFollowers(user_ids) {
logQuery('batchGetFollowers');
const rows = await db.all(`SELECT Persons.firstName, Persons.lastName, Persons.id, FollowerEdges.user_id as following_id
FROM Persons
INNER JOIN FollowerEdges WHERE FollowerEdges.follower_id = Persons.id
AND FollowerEdges.user_id in (${user_ids.join(', ')})`)
const rowsGroupedByUserID = _.groupBy(rows, 'following_id');
return user_ids.map(id => rowsGroupedByUserID[id]);
}

async function batchGetUsers(user_ids) {
logQuery('batchGetUsers');
const rows = await db.all(`SELECT * from Persons WHERE id in (${user_ids.join(', ')})`);
const keyedRows = _.keyBy(rows, 'id');
return user_ids.map(id => keyedRows[id]);
}

async function getAllUsers() {
logQuery('getAllUsers');
return db.all(`SELECT * FROM Persons`);
}



module.exports = {
batchGetUsers: batchGetUsers,
batchGetFollowers: batchGetFollowers,
getAllUsers: getAllUsers
};


53 changes: 53 additions & 0 deletions db/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const db = require('sqlite');
const _ = require('lodash');
const faker = require('faker');
let dbQueries = 0;
async function createTables(db) {
await db.run(`
CREATE TABLE Persons (
id INTEGER PRIMARY KEY AUTOINCREMENT,
firstName TEXT,
lastName TEXT
);
`);

await db.run(`
CREATE TABLE FollowerEdges (
user_id NOT_NULL INTEGER,
follower_id NOT_NULL INTEGER,
FOREIGN KEY(user_id) REFERENCES Persons(id)
FOREIGN KEY(follower_id) REFERENCES Persons(id)
PRIMARY KEY(user_id,follower_id)
);
`)

return true;
}

async function mockData(db) {
let statement = await db.prepare(`INSERT INTO Persons (firstName, lastName) VALUES (?, ?)`);
_.range(9).forEach(i => statement.run(faker.name.firstName(), faker.name.lastName()));
await statement.finalize();
const rows = await db.all(`SELECT * FROM Persons`);
let edgesStatement = await db.prepare('INSERT INTO FollowerEdges (user_id, follower_id) VALUES (?, ?)');
rows.forEach(person => {
rows.filter(r => r.id !== person.id).forEach(personToFollow => {
edgesStatement.run(personToFollow.id, person.id);
})
});
await edgesStatement.finalize();

}

async function setupDB() {
await db.open(':memory:')
await createTables(db);
await mockData(db);
return Promise.resolve(true);
//let followers = await batchGetFollowers(db, [1, 2]);
//let users = await batchGetUsers(db, [1,2]);
}

module.exports = setupDB;


61 changes: 61 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
const express = require('express');
const graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');
const db = require('./db')
const DataLoader = require('dataloader');

const userLoader = new DataLoader(async (keys) => {
const rows = await db.batchGetUsers(keys);
return rows.map(r => new User(r));
});
const followersLoader = new DataLoader(async (keys) => {
const rows = await db.batchGetFollowers(keys);
return rows.map(r => r.map(c =>new User(c)));
});
// Construct a schema, using GraphQL schema language
var schema = buildSchema(`
type User {
firstName: String!
lastName: String!
followers: [User]
}
type Query {
users: [User]
}
`);

// This class implements the RandomDie GraphQL type
class User {
constructor(data) {
this.id = data.id;
this.firstName = data.firstName;
this.lastName = data.lastName;
}

async followers(a, b, c) {
return followersLoader.load(this.id);
return followers;
}
}

// The root provides the top-level API endpoints
var root = {
users: async function () {
const rows = await db.getAllUsers();
let result = rows.map(data => new User(data));
return result;
}
}

var app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));

db.initialize().then(() => {
app.listen(4000);
console.log('Running a GraphQL API server at localhost:4000/graphql');
});
21 changes: 21 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "graphql-dataloader-sqlite",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index"
},
"author": "",
"license": "ISC",
"dependencies": {
"dataloader": "^1.3.0",
"express": "^4.16.2",
"express-graphql": "^0.6.11",
"faker": "^4.1.0",
"graphql": "^0.11.7",
"lodash": "^4.17.4",
"sqlite": "^2.8.0",
"sqlite3": "^3.1.13"
}
}
Loading

0 comments on commit c25e1c8

Please sign in to comment.