[wip] webshpo blogpost
This commit is contained in:
parent
e83b959889
commit
6d0ffd9b35
|
@ -46,6 +46,9 @@
|
|||
pre-commit.text = config.pre-commit.installationScript;
|
||||
};
|
||||
packagesFrom = [config.devShells.ghc94];
|
||||
packages = [
|
||||
pkgs.static-web-server
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue