🔥💎 firepry
A Firestore REPL that's actually just Pry.
About
It's nice to be able to drop into a SQL console when you need to wrangle some queries. There's no real "native" way to
do this for Firestore, so firepry
serves as way to drop into a Pry (Ruby) REPL with your Firestore DB loaded up as
the current context.
Why Pry/Ruby?
I'm probably biased because I've worked with Ruby/Rails quite a bit, but the DSL-ish nature of Ruby lends itself very well to being used as a Firestore DB REPL. Should be (hopefully) quick to learn for users of most languages.
Usage
Installation:
$ gem install firepry
Help text:
$ firepry -h
Usage: firepry [options]
-p, --project-id PROJECT-ID GCP project ID
-k, --keyfile KEYFILE GCP keyfile
-e, --endpoint ENDPOINT Firestore endpoint URL
A few different ways to start it:
$ firepry # if $FIRESTORE_CREDENTIALS is already set up in your environment
$ firepry -k gcloud-key.json # where `gcloud-key.json` is your GCP keyfile
$ firepry -p asdf -e localhost:5001 # if you're using a local emulator
To issue queries, etc...:
# Get doc by id
[1] firepry(db)> collection('users').doc('user_id_blahblahblah').get.data
# Get first doc in collection
[2] firepry(db)> collection('users').get.first.data
# Query collection
[3] firepry(db)> collection('users').where('follower_count', '>', 1_000_000).get
More info:
How it works
Here's all the code:
#! /usr/bin/env ruby
require 'dotenv/load'
require 'optparse'
require 'pry'
require 'google/cloud/firestore'
require 'firepry'
firestore_options = {}
OptionParser.new do |opts|
opts.banner = "firepry v#{FirePry::VERSION}\nUsage: firepry [options]"
opts.on('-v', '--version', 'Show version') { puts "firepry v#{FirePry::VERSION}"; exit }
opts.on('-p', '--project-id PROJECT-ID', 'GCP project ID') { |opt| firestore_options[:project_id] = opt }
opts.on('-k', '--keyfile KEYFILE', 'GCP keyfile') { |opt| firestore_options[:keyfile] = opt }
opts.on('-e', '--endpoint ENDPOINT', 'Firestore endpoint URL') { |opt| firestore_options[:endpoint] = opt }
end.parse!
@firestore = Google::Cloud::Firestore.new(**firestore_options)
def current_obj(obj)
obj == @firestore ? 'db' : obj
end
line = 0
Pry.start(
@firestore,
prompt: Pry::Prompt.new(
'firepry',
'the firepry prompt',
[proc { |obj, nest_level, _| "[#{line += 1}] firepry(#{current_obj(obj)})> " }]
)
)