Notably Polite Mariner

    @typeheim/orm-on-fire
    TypeScript icon, indicating that this package has built-in type declarations

    0.1.0 • Public • Published

    NPM Version Build Status Package License Discord

    ORMOnFire is a powerful Firestore ORM.

    Installation

    Install package

    # in backend
    yarn add firebase firebase-admin firebase-tools
    
    # in frontend
    yarn add firebase 
    
    yarn add @typeheim/orm-on-fire
    # or
    npm -i @typeheim/orm-on-fire

    Setup ORMOnFire driver:

    // sample for Node.JS
    FirebaseAdmin.initializeApp({
        credential: FirebaseAdmin.credential.cert('my.key.json'),
        databaseURL: "https://my-db.firebaseio.com",
    })
    OrmOnFire.driver = FirebaseAdmin.firestore()

    Easy entity declaration

    To define entity you need to use @Entity or @Agregate decorators for simple and nested collections. Note both decorators will transform class name to kebab case - lowercase and split words with hyphens, like UserFiles < => user-files.

    Then, each document field must be decorated with @Field, @MapField, @CreatedDateField, @UpdatedDateField or @DocRef(for document references) decorators. Sub-collections can be referenced by @CollectionRef decorator.

    import {
        Agregate,
        Entity,
        Collection,
        CollectionRef,
        ID,
        Field,
        CreatedDateField,
        UpdatedDateField,
        MapField
    } from '@typeheim/orm-on-fire'
    import { CreatedDateField } from './Entity'
    
    @Agregate()
    export class User {
        @ID() id: string
    
        @Field() firstName: string
    
        @Field() lastName: string
    
        @Field() status: string
    
        @CollectionRef(UserFile) files: Collection<UserFile>
    }
    
    @Entity({ collection: 'user-files' })
    export class UserFile {
        @ID() id: string
    
        @Field() name: string
    
        @MapField() properties: FileProperties
    
        @CreatedDateField() createdAt: Date
    
        @UpdatedDateField() createdAt: Date
    }
    
    class FileProperties {
        type: "image" | "doc"
    }

    Simple data fetching

    import { Collection } from '@typeheim/orm-on-fire'
    
    // with promise-like interface
    let markus = await Collection.of(User).one('markus').get()
    
    // with Rx interface
    Collection.of(User).one('tom').get().subscribe((tom: User) => {
        tom.files.forEach((file: UserFile) => {
            // some cool stuff
        })
    }) 

    Powerful filtering

    Using firestore operators

    import { Collection } from '@typeheim/orm-on-fire'
    const UsersCollection = Collection.of(User)
    
    // Search using regular Firesotre operators
    let activeUsers = await UsersCollection.all().filter(user => user.status.equal('active')).get()
    let notActiveUsers = await UsersCollection.all().filter(user => user.status.notEqual('active')).get()
    let adultUsers = await UsersCollection.all().filter(user => user.age.greaterThan(18)).get()

    Test index search

    To use text index search you first need to add text index hook Firebase function to your Firebase functions list for each colelction you want to be idndexed

    import { TextIndex } from '@typeheim/orm-on-fire'
    import * as functions from 'firebase-functions'
    import * as FirebaseAdmin from 'firebase-admin'
    
    FirebaseAdmin.initializeApp()
    
    export const generateUserIndex = TextIndex(functions, FirebaseAdmin).forCollection('users')
                                                         .fields(['name', 'text'])
                                                         .buildTrigger()

    Official functions deployment guide: Get started: write, test, and deploy your first functions

    Once you deploy hooks, you can use index search as below:

    // Note: text index search is case-insensitive 
    let usersStartsWithAlex = await UsersCollection.all().useIndex(user => user.firstName.startsWith('Alex')).get()
    let usersEndsWithLex = await UsersCollection.all().useIndex(user => user.firstName.endsWith('lex')).get()

    NOTE: for now text index won't work with collection group queries. Support coming in next releases.

    Filter scopes:

    Commonly used filer conditions can be organized in named filter scopes for easy code reuse:

    class UserScope {
        static active() {
            return (user: EntityFilter<User>) => {
                user.status.equal(1)
            }
        }
    }
    
    // fetch all active users
    let activeUsers = await UsersCollection.all().filter(UserScope.active()).get()

    Sub-collection queries:

    For nested collections you don't need to fetch each document separately and can access required collection under specific document ID:

    // fetch all PDF files from user suwth id "userId"
    let userFiles = await UsersCollection.one('userId').collecction(UserFile).filter(UserFile.pdf()).get()

    Group collection queries:

    ORMOnFire support easy declaration of collection groups the same way as for regular collections.

    // fetch all file attachments that exist in any collection and sub-collection
    let attechments = await Collection.groupOf(Attachment).all().filter(Attachment.file()).get()

    Install

    npm i @typeheim/orm-on-fire

    DownloadsWeekly Downloads

    23

    Version

    0.1.0

    License

    MIT

    Unpacked Size

    161 kB

    Total Files

    129

    Last publish

    Collaborators

    • prowwid