flyp-inc/etabase/2.0.0

Rerouted (renamed, needs approval). The GitHub user or repository was renamed. The tag is still there, at the new name. The Lamdera package server serves a copy recovered from https://github.com/Flyp-Inc/etabase.

What we checked: The repo moved to github.com/Flyp-Inc/etabase and tag 2.0.0 is there; its commit e27d168a55a5 is from 2024-08-30 11:03 UTC, after the version was published (2024-08-22 10:23 UTC); elm.json is byte-identical to package.elm-lang.org's; the exposed modules match docs.json; the zip's SHA-1 is not the published one and nothing else confirms its contents.

We could not verify this copy against what was published, so the Lamdera compiler asks before using it (y/n). Without a terminal, as in CI, it stops with an error unless approved:

  • lamdera make --auto-approve-package-rerouting approves rerouted versions for that run,
  • LAMDERA_AUTO_APPROVE_PACKAGE_REROUTING=1 does the same for every run in that environment,
  • LAMDERA_CACHE=off skips the Lamdera package server altogether: packages come from package.elm-lang.org and GitHub only, as with elm, and a rerouted version then fails to download.

Details · package.elm-lang.org's zip: https://github.com/flyp-inc/etabase/zipball/2.0.0/

Table

Represents a "table" semantic, where a "table" is a a dictionary of values that have a unique identity, and a "created at" timestamp.

In a traditional relational database management system, the database engine provides a unique identity and can generate timestamps; the Table type takes responsibility for mediating those operations.

Types

type Table a

Opaque type representing a "table".

Create a new Table.

type alias Row a =
{ id : Id a
, value : a
, createdAt : Posix
}

Represents a row created in a Table a.

type Id a

Represents a unique ID for a Row in a Table a.

Configuration

type Config a

Configuration details for a table.

Define a table's configuration.

This value returns an empty Config a, and can be "built" with other functions in this module whose type signature ends in Config a -> Config a.

type alias Spec a b =
{ index : Index a
, is : Predicate a b
}

A Spec a b is a record that contains:

  • An Index a, which makes lookups faster for a given column
  • A Predicate a b, which allows searching for a Row a in a Table a by some value b, which has the same type as the value indexed
type Index a

Represent an index for a table.

Internally, an index is:

  • A unique identifier (i.e., the index name)
  • A map between a property on an a and an Int

When you query a table, you query it by its indexes. This doesn't mean that you need to create an index for every column! The columns that you should create indexes for are the columns that will help you identify a record, or identify a group of records by some column that is a member of a smaller set compared to other columns.

Consider the following:

module User exposing (..)


import Table


type alias Record =
    { emailAddress : String
    , catchphrase : String
    , role : Role
    }


type Role
    = Admin
    | Member

If we need to run queries against User.Record to find all users that are Admin users, it would make sense to create an index on the .role column, because the Role type is a member of a set that only has two values - Admin or Member.

It wouldn't make much sense to create an index on the .catchphrase column - since that column is likely going to be unique for each user, anyway - so if we really needed to do a query against the .catchphrase column, we would have to consider every record separately, no matter what.

type Predicate a b

An opaque function that acts as an interface between the Index a values within a table's Config a, and the type of a column that has an Index a.

See usage at where_ for more information.

toSpec : String -> (a -> b) -> (b -> String) -> Spec a b

Create an Index a and Predicate a b by providing a unique name for the index, and a string representation of the indexed value.

toSpecId : String -> (a -> Id b) -> Spec a (Id b)

Convenience function to create a Spec a b where the b is an Id b - i.e., where you'd like to index or filter by a column in your table that is an Id b for some Table b.

toSpecBool : String -> (a -> Bool) -> Spec a Bool

Convenience function to create a Spec a b where the b is a Bool.

Add an Index a to a Table a.

Commands

insert : Config a -> Posix -> a -> Table a -> ( Row a, Table a )

Insert a record into a Table.

insertMany : Config a -> Posix -> List a -> Table a -> ( List (Row a), Table a )

Insert many records into a Table.

update : Config a -> Id a -> Posix -> a -> Table a -> Table a

Update a record in a Table.

The Table a type doesn't track "updated at", since it's assumed that if you care about that, you will wrap each column whose "updated at" time is meaningful, in a Col a.

update doesn't return a tuple of the updated record and the updated table; insert only returns a tuple because insert is responsible for creating the Id a value.

update is an expensive operation, because it rebuilds the indexes for a Table a; prefer data structures such that "things that change often" are defined as calls to insert, and "things that only change once in awhile" are handled by calls to update.

delete : Config a -> Posix -> Id a -> Table a -> Table a

Delete a record from a Table.

Queries

getById : Id a -> Table a -> Maybe (Row a)

Get a value by its id.

where_ : Predicate a b -> b -> Table a -> Table a

Query values in a table based on a Predicate a b.

filter : (a -> Bool) -> Table a -> Table a

Query values in a table based on a predicate derived from any column value.

This does not use any of a table's indexes. If you need to use filter, then consider either:

  • Creating an Index a so that you can have a Predicate a b to use with where_, or
  • Filtering the result set down as much as possible by where_ first, before applying filter
select : (Row a -> b) -> Table a -> List b

Select rows from a Table a.

This will operate on all rows in a given Table a, so it may be wise to use where_ and filter to narrow the Table to what you actually want before calling select.

JSON

Note: There is no encoder or decoder for Table a. Serializing and deserializing identity generation would be a tricky thing to have to do, so for now I am making the artistic choice to deal with it by not dealing with it at all.

idEncoder : Id a -> Value

Encoder for an Id a.

idDecoder : Decoder (Id a)

Decoder for an Id a.

rowEncoder : (a -> Value) -> Row a -> Value

Encoder for a Row a.

rowDecoder : Decoder a -> Decoder (Row a)

Decoder for a Row a.