[wip] webshpo blogpost

This commit is contained in:
mangoiv 2023-11-16 11:01:43 +01:00
parent e83b959889
commit 6d0ffd9b35
Signed by: mangoiv
SSH key fingerprint: SHA256:JlsRe4zkmS13EG6gMFNjv13Lw5rtoMPu3Lq69ZQTKF8
2 changed files with 65 additions and 0 deletions

View file

@ -46,6 +46,9 @@
pre-commit.text = config.pre-commit.installationScript;
};
packagesFrom = [config.devShells.ghc94];
packages = [
pkgs.static-web-server
];
};
};

View file

@ -110,3 +110,65 @@ It's really that simple, but with some glue it's really quite elegant.
`rel8` also offers a really nice eDSL to write sql expressions, that will remind a Haskell user of writing code in
the `List` Monad.
I really wanted to use it but in the end decided against it, already a trivial example made the compile times unbearably long.
After trying `rel8`, a friend suggested I should have a look at [`squeal-postgresql`](https://flora.pm/packages/@hackage/squeal-postgresql)
which is a deeply embedded `sql` domainspecific language, it allows you to write sql in Haskell code and even type it properly;
the library automatically takes care of marshalling which is type safe. It's really a beautiful way to write sql in a safe way.
A usual table looks like this:
```haskell
-- | constraints on the customer table
type CustomerConstraints = '["pk_customers" ::: PrimaryKey '["name"]]
-- | columns of the customer table
type CustomerColumns =
[ "name" ::: NoDef :=> NotNull PGtext
, "age" ::: NoDef :=> NotNull PGtext
]
```
It is marshalled in to any [record subtype](https://flora.pm/packages/@hackage/records-sop) of an equivalent normal Haskell ADT;
the postgres types (prefixed wit `PG`) are mapped into equivalent Haskell types,
`NotNull` is marshalled into just the field, `Null` into `Maybe`, `Def` and `NoDef` are
about having the possibility to insert a default value when creating a row of this type.
A usual query looks something like this:
```haskell
getExtrasForTourID
:: Query_ MySchema
(I Text)
Customer
getExtrasForTourID =
select
Star
( from (table (#webshop ! #customer))
& where_ (#name .== param @1)
& orderBy [Asc #age]
)
```
As you can see, it is very similar to how normal `sql` look, it is typed via the schema type that is defined in the type eDSL
shown above and a number of parameters (which are held in *some* record, in this case `I` which is a shorthand `Identity` type).
I had a lot of fun using this and even as someone who is not too versed in `sql`, this is really comfortable to work with
and gives me a lot of confidence in my queries being at least syntactically correct.
The big downside is that `GHC` has a problem compiling type families which `squeal` makes heavy use of, in fact, my `Persistance`
module takes by far the longest to compile, even compared to the entire remaining modules. In the current state of the project, while
compiling, it allocates 100GB of memory and takes 2.6 of the total 5.3 minutes to compile.
> if you want see what `GHC` does when compiling your projects, install
> [time-ghc-modules](https://github.com/codedownio/time-ghc-modules/tree/master), run `cabal clean`, then pass
> `--ghc-options "-ddump-to-file -ddump-timings"` to your `cabal build` command,
> running `time-ghc-modules` will generate a nice webpage giving an overview.
Some tips when working with squeal:
- turn off valid hole fits
- use `haskell-languagse-server`
- perhaps try to understand [`generics-sop`](https://flora.pm/packages/@hackage/generics-sop) or
[`sop-core`](https://flora.pm/packages/@hackage/sop-core) for that matter
- as with all typelevel programming in Haskell, as type inference basically vanishes, *first* write the type signatures, then write
the function body