functional-models
    Preparing search index...

    How to Use a Model in a Frontend and Backend

    The orm functionalities of functional-models makes it easy to use the same models in a frontend as well as a backend. All of this happens through the ModelFactory objects.

    We are going to create a system that has two models. Users and Vendors. We want to be able to reuse these models on a front end and a backend. The way we are going to do that is to change the ModelFactory that is used on the frontend versus the backend.

    Each model is broken out into its own file, and then at the end we have our implementations.

    /src/auth/types.ts

    export type User = Readonly<{
    email: string
    name: string
    }>

    /src/auth/models/users.ts

    import {
    EmailProperty,
    TextProperty,
    ormPropertyConfig,
    } from 'functional-models'
    import { User } from '../types'

    export const create = ({ Model }: ModelConstructorProps) => {
    return Model({
    pluralName: 'Users',
    namespace: 'my-namespace',
    properties: {
    email: EmailProperty(
    ormPropertyConfig({ required: true, unique: 'email' })
    ),
    name: TextProperty(),
    },
    primaryKeyName: 'email',
    })
    }

    /src/ecommerce/types.ts

    export type Vendor = Readonly<{
    id: string
    name: string
    website: string
    category: string
    primaryContact: ModelReference<User>
    }>

    /src/ecommerce/models/vendors.ts

    import {
    PrimaryKeyUuidProperty,
    TextProperty,
    ModelWithReferencesConstructorProps,
    ModelReferenceProperty,
    ormPropertyConfig,
    } from 'functional-models'
    import { create as createUsers } from '../../auth/models/users'

    export const create = ({
    Model,
    fetcher,
    }: ModelWithReferencesConstructorProps) => {
    return Model({
    pluralName: 'Vendors',
    namespace: 'my-namespace',
    properties: {
    id: PrimaryKeyUuidProperty(),
    name: TextProperty({ required: true }),
    website: TextProperty(ormPropertyConfig({ required: true })),
    category: TextProperty(ormPropertyConfig({ unique: 'category' })),
    // We are creating a reference to users.
    primaryContact: ModelReferenceProperty<User>(
    // We have to get the model instance for user.
    // If you have the users in a difference datastore
    // you would want to pass Users into the constructor.
    createUsers({ Model }),
    {
    required: true,
    // We need to pass a fetcher to a ModelReferenceProperty
    fetcher,
    }
    ),
    },
    // We want vendors to be unique by their name and category
    uniqueTogether: ['name', 'category'],
    })
    }

    Frontend: /frontend/src/models.ts

    import { Model, noFetch } from 'functional-models'
    import { auth, ecommerce } from 'our-library'
    const main = () => {
    // We need to create a Model, fetcher structure
    const input = { Model, fetcher: noFetch }
    // Pass it to the model constructors
    return {
    Users: auth.models.users.create(input),
    Vendors: ecommerce.models.vendors.create(input),
    }
    }

    Backend: /backend/src/models.ts

    import { Model, noFetch, createOrm } from 'functional-models'
    import { datastoreAdapter as mongoDatastore } from 'functional-models-orm-mongo'
    import { auth, ecommerce } from 'our-library'

    const main = () => {
    // Create our datastoreAdapter.
    const datastoreAdapter = mongoDatastore.create({})

    // Create an Orm
    const input = createOrm({ datastoreAdapter })

    // Pass it through just like the frontend
    return {
    Users: auth.models.users.create(input),
    Vendors: ecommerce.models.vendors.create(input),
    }
    }