Schemas



The hof supplied datamodel schemas

schema/dm

schema/dm

package dm

import (
	"github.com/hofstadter-io/hof/schema"
)

// This is a complete Value tracked as one
// useful for schemas, config, and NoSQL
Object: {
	schema.Hof// needed for reFerences
	#hof: datamodel: root: true

	TrackHistory

	// all fields will be tracked
}

// This is like object, but supports cue values
// (todo, should support full lattice)
Value: {
	Object
	#hof: datamodel: cue: true
}

// This is a general datamodel useful in many applications
// It can be expanded and enriched to cover more
// Useful for SQL, APIs, forms, and similar
Datamodel: {
	schema.DHof  // needed for references
	#hof: datamodel: root: true
}

// Schema for a snapshot, can include anything else
Snapshot: {
	Timestamp: string | *""
}

// convenience type for embedding history
History: [...Snapshot]

TrackHistory: {
	#hof: datamodel: history: true // needed for CUE compat
	"Snapshot": Snapshot
	"History":  History
}

schema/dm/fields

schema/dm/fields.Common

package fields

DataTypes: ID |
	UUID |
	CUID |
	Bool |
	String |
	Int |
	Float |
	Enum |
	Password |
	Email

ID: UUID & {Default: "" | *"uuid_generate_v4()"}

Field: {
	Name:   string
	Plural: string | *"\(Name)s"
	Type:   string
	Reln?:  string
}

UUID: Field & {
	Type:     "uuid"
	Nullable: bool | *false
	Unique:   bool | *true
	Default?: string
	Validation: {
		Format: "uuid"
	}
}

CUID: Field & {
	Type:     "cuid"
	Nullable: bool | *false
	Unique:   bool | *true
}

Bool: Field & {
	Type:     "bool"
	Default:  string | *"false"
	Nullable: bool | *false
}

String: Field & {
	Type:     "string"
	Length:   int | *64
	Unique:   bool | *false
	Nullable: bool | *false
	Default?: string
	Validation: {
		Max: int | *Length
	}
}

Int: Field & {
	Type:     "int"
	Nullable: bool | *false
	Default?: int
}

Float: Field & {
	Type:     "float"
	Nullable: bool | *false
	Default?: float
}

Enum: Field & {
	Type: "string"
	Vals: [...string]
	Nullable: bool | *false
	Default?: string
}

Password: String & {
	Bcrypt: true
}

Email: String & {
	Validation: {
		Format: "email"
	}
	Unique: true
}

Date: Field & {
	Type: "date"
}

Time: Field & {
	Type: "time"
}

Datetime: Field & {
	Type: "datetime"
}

schema/dm/sql

schema/dm/sql.Datamodel

package sql

import (
	"github.com/hofstadter-io/hof/schema"
	"github.com/hofstadter-io/hof/schema/dm"
)

Datamodel: {
	#hof: datamodel: root: true

	schema.Hof
	dm.TrackHistory

	// these are the models for the application
	// they can map onto database tables and apis
	Models: {
		#hof: datamodel: node:    true
		#hof: datamodel: ordered: true
		[N=string]: Model & {Name: N, #hof: metadata: name: N}
	}

	// OrderedModels: [...Model] will be
	// inject here for order stability
}

Model: M={
	schema.Hof
	dm.TrackHistory

	// for easy access
	Name:   M.#hof.metadata.name
	Plural: string | *"\(Name)s"

	// These are the fields of a model
	// they can map onto database columnts and form fields
	Fields: {
		#hof: datamodel: node:    true
		#hof: datamodel: ordered: true
		[N=string]: Field & {Name: N, #hof: metadata: name: N}
	}

	// OrderedFields: [...Fields] will be
	// inject here for order stability

	// if we want Relations as a separate value
	// we can process the fields to extract them
}

Field: {
	// schema.Hof
	// TODO, decide if these should be the default
	// #hof: datamodel: history: true // needed for CUE compat
	// History: dm.History

	Name: string
	Type: string

	// relation type, open to be flexible
	Relation?: {
		"Name": string | *Name
		Type:   "has-one" | "has-many" | "belongs-to" | "many-to-many"
		Other:  string // technically a cue path, but as a string
	}

	// what about {val, *val, []val, []*val}
	// we probably don't care about pointer here
	//   that is a language detail (code gen target)

	// we can enrich this for various types
	// in our app or other reusable datamodels
}

schema/dm/sql.Fields

package sql

import (
	"github.com/hofstadter-io/hof/schema/dm/fields"
)

CommonFields: {
	ID:        fields.UUID & {Default: string | *"uuid_generate_v4()"}
	CreatedAt: fields.Datetime
	UpdatedAt: fields.Datetime
}

SoftDelete: {
	DeletedAt: fields.Datetime
}

PrimaryKey: fields.UUID & {
	Default: string | *"uuid_generate_v4()"
	SQL: PrimaryKey: true
}

Varchar: F=fields.String & {
	SQL: Type: "character varying(\(F.Length))"
}

schema/dm/enrichers

Examples for language type enrichments

schema/dm/enrichers.Go

package go

import "github.com/hofstadter-io/hof/schema/dm"

FieldEnricher: {
	field: dm.Field

	output: field
	output: GoType: [
			if field.Type == "uuid" {"uuid.UUID"},
			if field.Type == "datetime" {"time.Time"},
			if field.Type == "float" {"float64"},
			field.Type,
	][0]
}

schema/dm/enrichers.Py

package py

import "github.com/hofstadter-io/hof/schema/dm"

FieldEnricher: {
	field: dm.Field

	output: field
	output: PyType: [
			if field.Type == "uuid" {"uuid.UUID"},
			if field.Type == "date" {"datetime.date"},
			if field.Type == "time" {"datetime.time"},
			if field.Type == "datetime" {"datetime.datetime"},
			if field.Type == "string" {"str"},
			field.Type,
	][0]
}