cloud-coffee-ts
v1.0.0
Published
`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.
Downloads
1
Readme
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-coffee
should 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 listener
set 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-coffee
supports 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 format
of 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 / options
type end parameter that contains is passed to the function