Skip to content

Commit

Permalink
cleanup and easier setup / recreate
Browse files Browse the repository at this point in the history
  • Loading branch information
Brecht De Rooms committed Apr 23, 2020
1 parent 7f33a64 commit ca8ab78
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 33 deletions.
35 changes: 35 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
]
},
"devDependencies": {
"envfile": "^5.0.0",
"eslint": "^6.8.0",
"eslint-config-idiomatic": "^4.0.0",
"eslint-config-prettier": "^6.10.0",
Expand Down
90 changes: 70 additions & 20 deletions scripts/destroy.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
require('dotenv').config({ path: '.env.' + process.argv[2] })
const faunadb = require('faunadb')
const readline = require('readline-promise').default
const { handleSetupError } = require('../src/fauna/helpers/errors')

const { Map, Collections, Documents, Paginate, Lambda, Functions, Roles, Indexes, Delete, Var, Tokens } = faunadb.query
const {
Exists,
If,
Database,
Map,
Collections,
Documents,
Paginate,
Lambda,
Functions,
Roles,
Indexes,
Delete,
Var,
Tokens,
Let,
Get,
Select,
Equals,
Keys
} = faunadb.query

const keyQuestion = `----- Please provide the FaunaDB admin key) -----
An admin key is powerful, it should only be used for the setup script, not to run your application!
Expand All @@ -26,27 +47,56 @@ const main = async () => {
}

const deleteAll = async client => {
try {
const collections = await deleteAllCollections(client)
const functions = await deleteAllFunctions(client)
const roles = await deleteAllRoles(client)
const indexes = await deleteIndexes(client)
const tokens = await deleteTokens(client)
// We only delete tokens, not keys in order to keep the admin key.
// If this option is provided, the db will be created as a child db of the database
// that the above admin key belongs to. This is useful to destroy/recreate a database
// easily without having to wait for cache invalidation of collection/index names.
// In this case, we can just nuke the database completely.
const childDbName = process.env.REACT_APP_LOCAL___CHILD_DB_NAME
if (typeof childDbName !== 'undefined') {
// clean keys that are linked to this database
const deleted = await handleSetupError(
client.query(
Map(Paginate(Documents(Keys())), x =>
Let(
{
key: Get(x),
ref: Select(['ref'], Var('key')),
db: Select(['database'], Var('key'), 'none')
},
If(Equals(Var('db'), Database(childDbName)), Delete(Var('ref')), false)
)
)
),
'delete keys - delete keys linked to database'
)
console.log(deleted)
await handleSetupError(
client.query(If(Exists(Database(childDbName)), Delete(Database(childDbName)), false)),
'database - delete child database'
)
} else {
try {
const collections = await deleteAllCollections(client)
const functions = await deleteAllFunctions(client)
const roles = await deleteAllRoles(client)
const indexes = await deleteIndexes(client)
const tokens = await deleteTokens(client)
// We only delete tokens, not keys in order to keep the admin key.

console.log(`Deleted:
1. collections: ${collections.data.length}
2. functions: ${functions.data.length}
3. roles: ${roles.data.length},
4. indexes: ${indexes.data.length},
5. tokens: ${tokens.data.length}`)
console.log(`Deleted:
1. collections: ${collections.data.length}
2. functions: ${functions.data.length}
3. roles: ${roles.data.length},
4. indexes: ${indexes.data.length},
5. tokens: ${tokens.data.length}`)

console.log(
'\x1b[32m%s\x1b[0m',
`In case you want to recreate the database, please wait 60 seconds to invalidate collection/index name caches`
)
} catch (err) {
console.log('Error', err)
console.log(
'\x1b[32m',
`In case you want to recreate the database, please wait 60 seconds to invalidate collection/index name caches`
)
} catch (err) {
console.log('Error', err)
}
}
}

Expand Down
15 changes: 14 additions & 1 deletion scripts/populate.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { QueryManager } from '../src/fauna/query-manager'
require('dotenv').config({ path: '.env.' + process.argv[2] })
const { handleSetupError } = require('../src/fauna/helpers/errors')

const faunadb = require('faunadb')
const q = faunadb.query
const { CreateKey, Database } = q
// This script sets up some data. It's not idempotent so running it again will
// add duplicate fweets.
const readline = require('readline-promise').default
Expand All @@ -25,6 +27,7 @@ const main = async () => {
// In order to set up a database, we need a admin key, so let's ask the user for a key.

let adminKey = process.env.REACT_APP_LOCAL___ADMIN
const childDbName = process.env.REACT_APP_LOCAL___CHILD_DB_NAME

if (!adminKey) {
const interactiveSession = readline.createInterface({
Expand All @@ -38,6 +41,16 @@ const main = async () => {
console.log(explanation)
}

if (typeof childDbName !== 'undefined') {
const client = new faunadb.Client({ secret: adminKey })

const key = await handleSetupError(
client.query(CreateKey({ database: Database(childDbName), role: 'admin' })),
'Admin key - child db'
)
adminKey = key.secret
}

try {
// Let's create some users first
console.log('1. -- Creating three users')
Expand Down
47 changes: 38 additions & 9 deletions scripts/setup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
require('dotenv').config({ path: '.env.' + process.argv[2] })

var fs = require('fs')
const envfile = require('envfile')
const sourcePath = '.env.local'
const sourcePathExample = '.env.local.example'
// This script sets up the database to be used for this example application.
// Look at the code in src/fauna/setup/.. to see what is behind the magic

Expand All @@ -8,7 +11,7 @@ const { handleSetupError } = require('../src/fauna/helpers/errors')

const faunadb = require('faunadb')
const q = faunadb.query
const { CreateKey, Role } = q
const { CreateKey, Role, Exists, Database, CreateDatabase, If } = q
const readline = require('readline-promise').default

const keyQuestion = `----- 1. Please provide a FaunaDB admin key) -----
Expand All @@ -29,21 +32,39 @@ This script will (Do not worry! It will all do this for you):
`

const main = async () => {
// In order to set up a database, we need a admin key, so let's ask the user for a key.
// In order to set up a database, we need a admin key
let adminKey = process.env.REACT_APP_LOCAL___ADMIN

// If this option is provided, the db will be created as a child db of the database
// that the above admin key belongs to. This is useful to destroy/recreate a database
// easily without having to wait for cache invalidation of collection/index names.
const childDbName = process.env.REACT_APP_LOCAL___CHILD_DB_NAME

let serverKey = process.env.REACT_APP_LOCAL___ADMIN
if (!serverKey) {
// Ask the user for a key if it's not provided in the environment variables yet.
if (!adminKey) {
const interactiveSession = readline.createInterface({
input: process.stdin,
output: process.stdout
})
await interactiveSession.questionAsync(keyQuestion).then(key => {
serverKey = key
adminKey = key
interactiveSession.close()
})
console.log(explanation)
}
const client = new faunadb.Client({ secret: serverKey })
let client = new faunadb.Client({ secret: adminKey })

if (typeof childDbName !== 'undefined') {
await handleSetupError(
client.query(If(Exists(Database(childDbName)), false, CreateDatabase({ name: childDbName }))),
'database - create child database'
)
const key = await handleSetupError(
client.query(CreateKey({ database: Database(childDbName), role: 'admin' })),
'Admin key - child db'
)
client = new faunadb.Client({ secret: key.secret })
}

try {
await setupDatabase(client)
Expand All @@ -58,9 +79,17 @@ const main = async () => {
console.log(
'\x1b[32m',
`The client token to bootstrap your application.
replace it in your .env with the key REACT_APP_LOCAL___BOOTSTRAP_FAUNADB_KEY, react will load the .env vars
Don't forget to replace it if you rerun the setup!`
will be automatically installed in the .env.local with the key REACT_APP_LOCAL___BOOTSTRAP_FAUNADB_KEY, react will load the .env vars
Don't forget to restart your frontend!`
)
let json = null
try {
json = envfile.parseFileSync(sourcePath)
} catch (err) {
json = envfile.parseFileSync(sourcePathExample)
}
json.REACT_APP_LOCAL___BOOTSTRAP_FAUNADB_KEY = clientKey.secret
fs.writeFileSync(sourcePath, envfile.stringifySync(json))
console.log('\x1b[33m%s\x1b[0m', clientKey.secret)
}
} catch (err) {
Expand Down
1 change: 1 addition & 0 deletions src/fauna/queries/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ function RegisterAccountExample2(email, password) {
/* Register Example3 - we also want to create a user.
* However, we also want to create a user automatically when we create an account.
* We can use a Let to structure our query */
// eslint-disable-next-line no-unused-vars
function RegisterExample3(email, password, name, handle, icon, rateLimiting = true) {
const RegisterFQLStatement = Let(
{
Expand Down
6 changes: 5 additions & 1 deletion src/fauna/queries/fweets.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,15 @@ function comment(client, fweetRef, message) {

// We could get fweets via the collection, however than we have no control on the sorting
// So it's only here as an additional example.
// eslint-disable-next-line no-unused-vars
function GetFweetsExample1(client) {
return Paginate(Documents(Collection('fweets')))
}

// We can use an index to get the sorting as we want it.
// This query only gets the values contained in the index though.
// Let's expand on that in the next function and get all related information of a fweet.
// eslint-disable-next-line no-unused-vars
function GetFweetsExample2(client) {
return Paginate(Match(Index('all_fweets')))
}
Expand All @@ -307,6 +309,7 @@ function GetFweetsExample2(client) {
// this is abstracted in a function to make sure that everywhere where we want to return fweets
// (e.g. after creation/update etc) that we get them in the exact same way.
// We will also not call it immediately since we will store it as a User Defined Function (UDF) instead!
// eslint-disable-next-line no-unused-vars
function GetFweetsExample3(client) {
return GetFweetsWithUsersMapGetGeneric(
q.Map(
Expand All @@ -323,7 +326,7 @@ function GetFweetsExample3(client) {
* First of all, a 'Join' is always done on an index. Join essentially transforms the set you pass into it and replaces it with the data from the index so it's rather a 'traverse'.
* E.g. the example below returns the 'fweets' but no longer the account that is linked to it. This can be useful however, see the second example.
*/

// eslint-disable-next-line no-unused-vars
function GetFweetsWithUsersJoinExample1(client) {
return client
.query(Paginate(Join(Documents(Collection('accounts')), Index('fweets_by_author_simple'))))
Expand All @@ -340,6 +343,7 @@ function GetFweetsWithUsersJoinExample1(client) {
* and one Get is of course one read. This means that the below approach is a more cost effective way to get all fweets for a specific account.
* If a user would have 100s of fweets we could get these with two index reads instead of one index reads and 100s of gets.
*/
// eslint-disable-next-line no-unused-vars
function GetFweetsWithUsersJoinExample2(client, email) {
return client
.query(Paginate(Join(Match(Index('accounts_by_email'), email), Index('fweets_by_author_simple'))))
Expand Down
3 changes: 1 addition & 2 deletions src/fauna/queries/fweets.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import { setupDatabase, deleteAndCreateDatabase } from '../setup/database'

import { handle } from './../helpers/errors'
import { registerWithUser, login } from './auth'
import { getFweets, createFweet, getFweetsWithUsersMapGet, createFweetWithoutUDF } from './fweets'
import { getFweets, createFweet, createFweetWithoutUDF } from './fweets'
import { follow } from './followers'
import { search } from './search'

// About this spec:
// --------------------
Expand Down

0 comments on commit ca8ab78

Please sign in to comment.