A modern React / Node.js application
Part 5.1: Updating our GraphQL schema and API for search & pagination
Let’s create some data
First thing’s first, let’s generate some properties. We’ll create a script that generates and adds Property
objects to our Mongo instance. So let’s create a directory in server/scripts/database
called seeds
. In the top-level directory, run:
mkdir server/scripts/database/seeds
Inside our new seeds
directory, we’ll have two files:
001.do.addProperties.js
:
/*
This script generates N random Property documents by choosing Property
attributes from the following arrays.
Seeded Property documents have an id < 0, for easy deletion.
*/
var N = 100
var street1s = [
'Main St.',
'Walnut',
'Pearl St.',
'Paseo del Prado',
'Dejvicka',
'Malirska',
'Capital of Texas Hwy',
'Old Main St.',
]
var street2s = [
'Unit #1',
'Apt #3A',
'26A',
'',
null,
'13',
'E'
]
var cities = [
'Boulder',
'Austin',
'Prague',
'Munich',
'San Francisco',
'Denver',
'Vail'
]
var states = [
'Colorado',
'Texas',
'Bohemia',
'California',
'New York',
'Alaska'
]
// generate properties
var properties = []
for(var i = 1;i <= N;i++) {
properties.push({
id : -i,
street1 : street1s[parseInt(Math.random() * street1s.length, 10)],
street2 : street2s[parseInt(Math.random() * street2s.length, 10)],
city : cities[parseInt(Math.random() * cities.length, 10)],
state : states[parseInt(Math.random() * states.length, 10)],
zip : parseInt(Math.random() * 90000, 10) + 10000
})
}
// insert randomly generated properties
db.getCollection('Property').insertMany(properties)
001.undo.addProperties.js
:
db.getCollection('Property').deleteMany({ id: { $lt: 0 } })
As you can see, the first file simply generates 100 Properties randomly by picking values from each array (street1s
, street2s
, cities
, states
), and inserts them into our bnb-book
DB hosted on our Mongo instance. Each property has a negative integer as an ID, for easy identification that this is just seed/garbage data.
The second file deletes all Property
objects with an id less than 0.
How do we run these files? Where does the db
variable come from? Let’s add a command to our server/package.json
file:
"db-seed": "mongo bnb-book scripts/database/seeds/*.undo.*.js && mongo bnb-book scripts/database/seeds/*.do.*.js",
So when we run npm run db-seed
, we’re piping any seeds/*.undo.*.js
files into the mongo
command line interface, and then seeds/*.do.*.js
files. This helps us keep our seed
operations idempotent. We should be able to delete/insert seed data easily and at will.
There’s nothing special about this pattern: we could make our seeding a little more granular and add commands
db-seed-do
anddb-seed-undo
but I like the idea of having a single command that will always result in predictable seed data after being run.
Our current GraphQL schema doesn’t provide much in the way pagination and search. Let’s change that. Update our schema.graphql
file:
scalar Date
type User {
id: ID!
email: String!
firstName: String
lastName: String
}
input UserInput {
email: String
firstName: String
lastName: String
}
type LocalAuth {
id: ID!
user: User!
password: String!
}
type Property {
id: ID!
owner: User!
rooms: [Room]
street1: String!
street2: String
city: String!
state: String!
}
input PropertyInput {
owner: UserInput
rooms: [RoomInput]
street1: String
street2: String
city: String
state: String
}
type Room {
id: ID!
name: String!
price: Float
description: String
image: File
}
input RoomInput {
name: String
price: Float
description: String
image: FileInput
}
type File {
id: ID!
url: String!
}
input FileInput {
url: String
}
type Booking {
id: ID!
room: Room!
email: String!
start: Date!
end: Date!
}
input SearchParameters {
searchText: String
sortAsc: Boolean
sortKey: String
first: Int
skip: Int
}
type Query {
fetchUser(id: ID!): User
fetchProperty(id: ID!): Property
listProperties(args: PropertyInput, search: SearchParameters) : [Property]
listRooms(args: RoomInput, search: SearchParameters) : [Room]
}
type Mutation {
createUser(input: UserInput): User
updateUser(id: ID!, input: UserInput): User
deleteUser(id: ID!): User
createBooking(roomId: ID!, email: String!, start: Date!, end: Date!): Booking
}