cloud-coffee-ts v1.0.0
CloudCoffee - Data Framework
cloud-coffee is a implementation agnostic database / client framework that intends to be a single source of truth when it comes to application state and how to access data.
the framework seeks to achieve the following objectives
- Create an extensible modular database framework that can support any given database implementation given the implementation follows the layed out specification
- Create a simple and easy to use forward facing API that is readable & powerful
- Any applications written with
cloud-coffeeshould be compatible with any database technology that supports the features defined in the specification. The specification seeks to be general enough to support this
Implementation Free
the cloud-coffee is mostly implementation free meaning it consists mostly of interface and type definitions in order to ensure the core part of API does not depend on any existing implementation. The functions that are implemented in the base package require little or no dependencies
Modular framework
At the time of writing cloud-coffee consists of 8 core modules that need to be implemented for the full functionality of the framework. These are
export interface Cloud {
auth : CloudAuth,
batcher : CloudBatcher
db : CloudDb
helper : CloudHelper
library : CloudLibrary
local : CloudLocal
runtime : CloudRuntime
server : CloudServer
}CloudAuth contains authentication functions
CloudBatcher functions that support atomic batching of database calls
CloudDb the core database API to read, write, delete data objects
CloudHelper a list of helper functions other modules can call into
CloudLibrary a companion to CloudDb to store file based resources like images, and other files
CloudLocal functions that can run on the local machine if not a web based system
CloudRuntime Factory pattern that handles the creation of runtime resources
CloudServer Server specific functions that depend of what server environment you are using
CloudCoffee.js
This file in the main entry point and forward facing API that contain a list of functions that can be called based on the Database implementation
Setup
The default export from 'index.js / CloudCoffee.js' is a setup function that is used to configure the runtime environment
Setup the implementation
import Setup from "cloud-coffee";
let myCloud : Cloud = {/* Provide a cloud implementation */}
await Setup(myCloud);Optional config
Setup() can take in an optional 2nd parameter with config options that can change the runtime behavior of the framework
Setup definition
export type CloudSetup = {
runtimeConfig : RuntimeConfig
runtime : CloudRuntime
}Custom Setup
import Setup from "cloud-coffee";
let myCloud : Cloud = {/* Provide a cloud implementation */}
let mySetup : CloudSetup = {/* Provide s setup config*/}
await Setup(myCloud, mySetup);once you await the setup you can immediately start using the database api and client functions
Account
The the time of writing cloud-coffee only supports a single email/password based auth provider (This may change when the interface / API is fleshed our further)
To create an account use the Account function
import { Account } from "cloud-coffee"
async function main(){
const uid = await Account("username@gmail", "password");
console.log(`New Account in as ${uid}`);
//TODO:ask for name and save to DB
}
main()Login
To Login use the Login function
import { Login } from "cloud-coffee"
async function main(){
const uid = await Login("username@gmail", "password");
console.log(`Logged in as ${uid}`)
}
main()User
use the User() string | null to retrieve the user id or null of the currently logged in user
import { User } from "cloud-coffee"
const uid = User();
if(uid)
console.log(`User is available :${uid}`);
else
console.log("User is null")Signout
use the Signout() : Promise<void> to log the user out
import { Signout } from "cloud-coffee"
await Signout()UserReady
use the UserReady() : Dispose to attach a listener to detect when the user as logged in or out.
If the callback can return null if user is not present. If user is logged out you must at least callback once with null
import { UserReady } from "cloud-coffee"
const dispose = UserReady(uid => {
if(uid){
//Database is ready to be used
}
})
dispose() //will detach the listenerset the users email by calling Email(currentPassword, newEmail)
Password
set the users password by calling Password(currentPassword, newPassword)
Verify
await Verify() will send a verification email
Present
if user is available ie User() != null
CloudDB
The database module was inspired by the google firebase API and the current implementation I have written is a firebase one, as such the specification borrows some ideas of how to structure data
Concepts
The functional language of CloudCoffee borrows words inspired by literature and library jargon as a way to conceptualist the actions you are preforming on the database
Page
a page is a path to a object / data resource. To access a page you provide the database scoped Url/Path to that resource. Exactly like firebase pages are denoted using an odd number of path segments for example '/users/837' is a user page
a volume is a collection of pages or objects at a specific Url/Path that can be accessed.
Example '/users/927/projects' is a path to the user bucket projects
Note the first segment of a path is always a volume
Page
to access a page with a callback use the 'Page' function. This will return a dispose function to detach the callback. You can type age page to return exactly what you want
import { CreateCaller, Page } from "cloud-coffee"
type Project = {
projectName : string
}
const local = CreateCaller("my-local-caller");
Page<Project>(local, "/users/983/projects/project-01", project => {
//TODO:do something with return
})Read
Page is a callback based, cloud-coffeesupports inline await for Paging data with Read which is basically the same signature as Page
import { CreateCaller, Read } from "cloud-coffee"
const local = CreateCaller("my-local-caller");
const data = await Read<Project>(local, "/users/983/projects/project-01");
if(data != null) {
//You data is available
}Volume
To read a list of data use the Volume function
import { CreateCaller, Volume } from "cloud-coffee"
const local = CreateCaller("my-local-caller");
Volume<Project>(local, "/users/983/projects", projects => {
//print projects in console //TODO
});List
List is the promise based version of Volume to await the data inline
import { CreateCaller, List } from "cloud-coffee"
const local = CreateCaller("my-local-caller");
const array = await List<Project>(local, "/users/75/projects");Publish
you can Publish (add) data with the Publish function. Just input which volume / path you want the data to be published too
import { CreateCaller, Publish } from "cloud-coffee"
const newProject : Project = {
projectName = "New API Imp"
}
const local = CreateCaller("my-local-caller");
const object = await Publish<Project>(local, "/users/983/projects", newProject);Publish returns a CloudObject<T> which is a virtual pointer to an object in the database
Amend
You can update / amend with the Amend function. This will update the object in the database only if the resource still exists. Specify which page to update
import { CreateCaller, Amend } from "cloud-coffee"
const local = CreateCaller("my-local-caller");
await Amend<Project>(local, "/users/983/projects/project-34", {
projectName : "Override new Project Name"
});Delist / Remove
You can delist a page / remove / delete by called the 'Delist(.., page)' function
import { CreateCaller, Delist } from "cloud-coffee"
const local = CreateCaller("my-local-caller");
await Delist<Project>(local, "/users/983/projects/project-deleteME");Write
You can set a database value even if it currently doesn't exist using Write function. However depending on the formatof an object the write call can behave different to Amend since amend only handles changes, Write can handle the Create state of an object which needs special consideration. This is due to the fact that cloud-coffee has a special data format called modular which is defined in the specification.
import { CreateCaller, Write } from "cloud-coffee"
const local = CreateCaller("my-local-caller");
const data = await Write<Project>(local, "/users/983/projects/write-empty", object, {
format : "regular"
});Write has a 4th optional param that defines a object format regular means the format is a 1:1 representation so the data is exactly the same as what was passed.
Note: All Db calls have an optional
params / optionstype end parameter that contains is passed to the function
4 years ago