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/
One of Lamdera's biggest value propositions is:
Elm on the frontend. Elm on the backend. Elm in-between. Elm in the shower! Elm at the store! Everything is Elm all the time always.
And that's really great, because you can store your user input from the frontend on the backend without having to deal with any pesky de/serialization.
But guess what: Your data... it forms a hierarchy, doesn't it? A relational hierarchy. You need a relational database. You need support for relational-database-type manoeuvres, such as "updated at" and "change data control" and "automatic identity".
You dust off Dict (or AssocList if you're feeling fancy) and you just sort of... fight through it. At the end, you have a half-baked, bug-ridden implementation of the worst parts of SQL.
Well, now, you don't have to deal with that anymore. You can just use flyp-inc/etabase.
Timestamps come from the runtime, so you'll need to do some Task.mapping to get the current timestamp. If you're already doing Lamdera anyway and you want a more holistic solution, check out flyp-inc/lamdera-extra.
Glad you asked!
module User exposing (..)
import Col
import Table
import Time
-- friendly type aliases
type alias Table =
Table.Table Record
type alias Row =
Table.Row Record
-- domain types
type alias Record =
{ emailAddress : String
, role : Col.Col Role
}
type Role
= Admin
| Member
-- table configuration
config : Table.Config Record
config =
Table.define
|> Table.withIndex specRole.index
|> Table.withIndex specEmailAddress.index
specRole : Table.Spec Record Role
specRole =
Table.toSpec "Role" (Col.value << .role) <|
\role ->
case role of
Admin ->
"Admin"
Member ->
"Member"
specEmailAddress : Table.Spec Record String
specEmailAddress =
Table.toSpec "EmailAddress" .emailAddress identity
-- creation, insertion
new : Time.Posix -> { emailAddress : String, role : Role } -> Record
new timestamp { emailAddress, role } =
{ emailAddress = emailAddress
, role = Col.init timestamp role
}
init : Table
init =
let
timeZero : Time.Posix
timeZero =
Time.millisToPosix 0
toRecord : String -> Record
toRecord emailAddress =
new timeZero { emailAddress = emailAddress, role = Admin }
in
Tuple.second <|
Table.consBatch config timeZero (List.map toRecord [ "[email protected]", "[email protected]" ]) Table.init
-- queries
findByEmailAddress : { emailAddress : String } -> Table -> Maybe Row
findByEmailAddress { emailAddress } table =
Table.where_ specEmailAddress.is emailAddress table
|> Table.select identity
|> List.head
getByRole : Role -> Table -> Table
getByRole role =
Table.where_ specRole.is role