GithubHelp home page GithubHelp logo

gahabeen / biota Goto Github PK

View Code? Open in Web Editor NEW
54.0 5.0 2.0 4.12 MB

A simple database framework for Fauna

Home Page: https://gahabeen.github.io/biota

License: MIT License

TypeScript 50.16% JavaScript 49.84%
faunadb javascript fauna client driver database-framework query-builder framework database

biota's Introduction

Biota has been living for a while in a new dedicated Organization over there: https://github.com/biotajs

Developement is on hold before I find some time to make it available to the world :)

Gabin.


biota

A simple database framework to start your next project in 30s with FaunaDB

Feature requests npm npm GitHub npm bundle size

Find the raw documentation here.

import { Biota } from "biota";
// 4 lines to:
const db = new Biota({ secret: "<your-secret>" });

// - scaffold the whole database (inc. users collection for ex)
await db.foundation();

// - add todos collection
await db.collection("todos").scaffold();

// - add autocomplete-search on name field
await db.collection("todos").index({ field: "name", ngram: true });
// 4 lines to:
// - create a user & login
let asUser = await db.user().register("[email protected]", "password", {
  nickname: "Georgy",
});

// - create a todo
await asUser.documents("todos").insert({ name: "Remember to star this project" });

// - query a todo with $ngram (autocomplete behavior)
await asUser.documents("todos").find({ name: { $ngram: "star" } });
// output: [{ ref, ts, data: { name: "Remember to star this project" } }]

Current status

Finishing up design and tests of the main API (400+ methods).

πŸ™ƒ You're on preview release. Don't get scared though, the api is pretty stable but tests need to be added to be fool-proof. (Thus, as of yet, Biota isn't production ready)

❀️ Check the features and request the ones you would love to see in biota. (They arn't all listed yet!)

Found some errors? Let us know!

Getting Started

These instructions will take you through the few steps to get started playing with your Fauna database.

Prerequisites

You'll need to add biota either as a global or local (project) dependency.

yarn add biota // -G for global
// or
npm i biota // -G for global

Import

import { Biota } from "biota";
// or
const { Biota } = require("biota");

Instance

There are two ways to instantiate Biota.

  1. You can use a admin/server key (or any secret key) as a paremeter.
const db = new Biota({ secret: "<your-secret>"})
// example
await db.query( q.Create(...) )
  1. You can use the function .login(id, password) to log a user.
const db = new Biota()
const logged = await db.login("123", "super_password123")
// which is a shortcut for
const logged = await db.current.user.login("123", "super_password123")

// example
await logged.query( q.Create(...) )

Api

Even though you can query your database (same as you would do with the same fauna method query), the main power of Biota lives in its extended api.

⏳ Patience: It's coming.. :)

Helpers

const { q, factory, Page } = require('biota')
// q: export the query builder, same as fauna.query
q.If(..., true, false)
// factory: export the factory api (helpers that wrap FQL)
factory.database(ctx)(name).insert(options)

Running the tests

If you want to run the tests, you'll need to provide a FAUNA_KEY_TEST=<your-test-key> in a .env file.

⚠️ Careful: At the moment tests covering everything yet. PR welcomed πŸ˜‰

Built With

Contributing

Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository.

Authors

  • Gabin Desserprit instigator

See also the list of contributors who participated in this project. Join us 🍻

License

This project is licensed under the MIT License - see the LICENSE.md file for details

Acknowledgments

This lib wouldn't exist if I had not dug deep into Fauna FQL and got helped through the Fauna's slack community channel. In no order, I'ld like to thank, for their help and support, fauna's team (Brecht De Rooms, Ben Edwards, Marrony Neris, Leo Regnier, Summer, ,...) as well as other users like Eigil Sagafos πŸ™

biota's People

Contributors

gahabeen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

biota's Issues

Issue with pagination properties definition

Pagination object must be declared as an object from the start.
Hence its parameters must already exists to be set. But it's impossible to have after and before at the same time.
image

Add an Error Management System

My vision of Biota is to provide a better environment to use Fauna.
And a part of it is to have better error management.

What should be done:

  • create a list of common errors and assign them codes/messages
  • check for these errors everywhere it could fail in the functions
  • read these errors in the query proxy to display them properly

Project Sample Ideas

  • Magic Link (login/signup via email) service
  • Internationnalization (languages management) service
  • Profile Page (one page per person) service

Add a CLI

Idea being to at least do db.foundation() to boostrap a database through CLI.
A bit like when you create new front end projects.

Thus it could become part of the build of a project quite easily.

Revamp of the structure of the project

The project is basically split in 2 folders: factory and framework.
While the factory is where all the FQL magic happens, the framework is where you'll find the api you will consume using biota (it uses the factory as you may guess and so abstract the FQL).

Most of the changes happened on the factory side.

  • Everything was separated by operation (Insert, Update, Delete, etc) while it didn't really made any sense as we consume it in an ORM fashion. It's now object/subject focused.
  • Didn't like the hack I put in place to properly protect the actions made by a user. It required to use biota through a server, it does not anymore. You can run it in your browser and it should work as fine.
  • Both worlds were not enough separated. UDFunctions were set up in the Framework as well as quite of the FQL stuff.
  • Now the UDFunctions are being generated from the functions themselves πŸ’ͺ
  • Now the UDFunctions have the same signatures
  • Methods/UDFunctions share a context

Add custom resolvers

Summary

Goal is to be able to resolve data from a document with FQL.
It would not be merged with the data itslef but instead provided on the side in a resolved property. Main reason being that I don't want to mess-up with the editable properties with resolved ones.

Any number of resolvers could be provided per collection. They would get merge (with q.Merge) when pushed.

Basic example

A users collection has the fields profile.firstName and profile.lastName.
We would like to get the fullName for quick display.
We would create the following resolver object:

{
  fullName: Let(
    {
      firstName: Select(['profile', 'firstName'], Var('doc'), null),
      lastName: Select(['profile', 'firstName'], Var('doc'), null),
      list: Filter([Var('firstName'), Var('lastName')], Lambda(['item'], Not(IsNull(Var('item'))))),
    },
    Concat(Var('list'), ' ')
  ),
}

Which would end up being wrapped in a User-Defined Function:

Query(Lambda(["ctx", "inputs"], q.Let({ doc: Select("doc", "inputs", {})}, <RESOLVER_OBJECT>)))

Which when getting the following document:

{
  "profile": {
    "firstName": "Gabin",
    "lastName": "Desserprit"
  }
}

would return:

{
  "data": {
    "profile": {
      "firstName": "Gabin",
      "lastName": "Desserprit"
    }
  },
  "resolved": {
    "fullName": "Gabin Desserprit"
  },
 "context: { contextInformations },
 "errors": { errorInformations }
}

Motivation

Provide the ability to fetch processed content straight from Fauna, without any in-between server.

Add type tests with an adapted version of JSONSchema validator in FQL

Summary

Idea is to be able to validate inputs/ouputs like GraphQL would do.
It needs an adapted JSON Schema validator in plain FQL.
It would allow to test anything passed around in biota and make sure everything's stricly typed (and nothing goes south).
It would allow to set schemas for collections for example (again, like GraphQL does).

Basic example

Motivation

Flexible search-queries

Api
db.find(<searchQuery>)

Description
Takes a searchQuery (object) that lists as its keys the paths to search (in dot notation) with the search value as their value.

Current proposed operators are the following:

  • $and
  • $or
  • $nor

With specific field values:

  • $ngram: for autocomplete-like search (full-text search)

Add relations to collections

Summary

Goal is to be able to insure relations between documents in collections.

  1. one to one
  • adds a unique constraint
  • a field on one of the two collection refers to the other one
  • scaffolding of indexes to query against it
  1. one to many (also many to one)
  • a field on one of the two collection refers to the other one
  • scaffolding of indexes to query against it
  1. many to many
  • creation of a new collection name biota.relation.<relation-name>
  • scaffolding of indexes to query against it

Basic example

How the api would look like:

// one to one
db.relation('user_address').one("address").connects.one("user", "contact.address")
// where 'address' refers to the Collection("addresses")
// where 'user' refers to the Collection("users") and "contact.address" is the field to be looked up

// many to one
db.relation('question_answers').many("answers", "question").connects.one("question")
// where 'answers' refers to the Collection("answers") and "question" is the field to be looked up
// where 'question' refers to the Collection("questions")

// many to many
db.relation('participations').many("polls", "users").connects.many("users", "polls")
// where 'polls' refers to the Collection("polls") and "users" the users ref list (added in the relations obj)
// where 'users' refers to the Collection("users") and "polls" the polls ref list (added in the relations obj)

Motivation

Simplify the relations management between collections.

Add plans/subscriptions management

Summary

Integrate logic in order to:

  • give permissions based on a subscription a user has
  • keep track of usage to apply limitations (ex: max number of documents owned in a collection)

What it implies:

  • Plans are roles named biota.plan.<id>
  • Relation between a user (or any document) and plan is called a subscription
  • Relation is determined by a _membership.plan field on a document

Basic example

Plan definition:

// API is very similar to db.role() if not the same
db.plan('basic').insert()

// update permissions
db.plan("basic").privileges.set({
  resource: Collection('todos'),
  rights: {
    insert: ['owner']
  }
})

// expire in an hour
db.plan('basic').expireIn(3600)

// list plans
db.plans.findAll()

Motivation

Properly manage the user's permissions through a common model of plans/subscriptions.

Add unlogged (guest) access

Summary

Give access to a document via a unique token.
The access can only have a get right (read).
We can imagine giving permissions to the relations inside the document with the same read right.

Mechanisms could be:

  • create a session for this document
  • generate a session token (hence specific to the dixit document)

This way the token can have an easy expiration management system.

Basic example

db.document('emails', '123').share()

Motivation

It's a fairly common feature that lets you share some information with external users.

Add privileges to a resource in an easy fashion

Simply have to say for each operation who can perform it (regarding to the current Identity as well as the collection documents).

Api
db.role(role: RoleRef).privilege.set(privilege: FaunaRolePrivilege | BiotaRolePrivilege)

Here is so far what's available:

type FactoryRuleAuthor = 'self' | 'owner' | 'assignee' | 'admin';

interface FactoryRuleDefinition {
  immutablePaths?: string[];
  get?: FactoryRuleAuthor[] | boolean;
  getHistory?: FactoryRuleAuthor[] | boolean;
  getHistoryWhenDeleted?: FactoryRuleAuthor[] | boolean;
  getHistoryWhenExpired?: FactoryRuleAuthor[] | boolean;
  insert?: FactoryRuleAuthor[] | boolean;
  insertHistory?: FactoryRuleAuthor[] | boolean;
  update?: FactoryRuleAuthor[] | boolean;
  replace?: FactoryRuleAuthor[] | boolean;
  delete?: FactoryRuleAuthor[] | boolean;
  getWhenDeleted?: FactoryRuleAuthor[] | boolean;
  updateWhenDeleted?: FactoryRuleAuthor[] | boolean;
  replaceWhenDeleted?: FactoryRuleAuthor[] | boolean;
  forgetWhenDeleted?: FactoryRuleAuthor[] | boolean;
  expire?: FactoryRuleAuthor[] | boolean;
  getWhenExpired?: FactoryRuleAuthor[] | boolean;
  updateWhenExpired?: FactoryRuleAuthor[] | boolean;
  replaceWhenExpired?: FactoryRuleAuthor[] | boolean;
  forgetWhenExpired?: FactoryRuleAuthor[] | boolean;
  forget?: FactoryRuleAuthor[] | boolean;
  restore?: FactoryRuleAuthor[] | boolean;
  setOwner?: FactoryRuleAuthor[] | boolean;
  removeOwner?: FactoryRuleAuthor[] | boolean;
  setAssignee?: FactoryRuleAuthor[] | boolean;
  removeAssignee?: FactoryRuleAuthor[] | boolean;
  setRole?: FactoryRuleAuthor[] | boolean;
  removeRole?: FactoryRuleAuthor[] | boolean;
}

Privileges rights only works on specific updates

Meaning that to update a specific field like _auth.email, even if the user has the right to do it, he would need to do a specific update (operation) for it and so cannot be merge within another operation.

Not sure if that's wanted behavior or not yet.

Add public rights

You can now give public access to resources with biota.

export type FactoryRuleAuthor = 'public' | 'self' | 'owner' | 'assignee' | 'admin';
export interface FactoryRuleDefinition<T = FactoryRuleAuthor[] | boolean> {
  immutablePaths?: string[];
  exists?: T;
  get?: T;
  getHistory?: T;
  getHistoryWhenDeleted?: T;
  getHistoryWhenExpired?: T;
  insert?: T;
  insertHistory?: T;
  update?: T;
  replace?: T;
  delete?: T;
  getWhenDeleted?: T;
  updateWhenDeleted?: T;
  replaceWhenDeleted?: T;
  forgetWhenDeleted?: T;
  expire?: T;
  getWhenExpired?: T;
  updateWhenExpired?: T;
  replaceWhenExpired?: T;
  forgetWhenExpired?: T;
  forget?: T;
  restore?: T;
  remember?: T;
  setOwner?: T;
  removeOwner?: T;
  setPublic?: T;
  removePublic?: T;
  setAssignee?: T;
  removeAssignee?: T;
  setRole?: T;
  removeRole?: T;
  setAuthEmail?: T;
  removeAuthEmail?: T;
  setAuthAccount?: T;
  removeAuthAccount?: T;
}

Bundle size optimisations?

Hi,

Thanks for creating this project, this will make getting started with Fauna easier for me as I am just starting with it.

  1. I noticed the present not minified bundle size is around 800KB. My use case is to access fauna from Cloudflare Workers which has a limit of 1MB(not gzip size, just minified version) source code size. So using this library I hit this limit quickly.
  2. Even when using in browsers the present gzip size is around 60KB.

To optimize bundle size, maybe the library can be split into various modules/packages so they are not bundled together and users can import what they need. At the present tree-shaking is not supported as it bundled as commonjs. If possible please enable tree shaking.

I can take a look at enabling tree shaking support if you are okay with it?

Add backup strategies

It could do:

  • save current configuration
  • save all data in new database environement
  • restore a previous state

Biota can now be used only client side

Careful though, you might want to use it also on a server side anyway for example for the following subjects:

  • email validation
  • password recovery (change)
  • oauth2 provider authentication (Google, Github, etc)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.