Open isovector opened 1 year ago
I came up with a surprisingly nice workaround here:
data Discovery f = Discovery
{ d_docId :: Column f DocId
}
deriving stock Generic
deriving anyclass Rel8able
data Discovery' f = Discovery'
{ d_table :: Discovery f
, d_search :: Column f Tsvector
}
deriving stock Generic
deriving anyclass Rel8able
discoverySchema :: TableSchema (Discovery Name)
discoverySchema = TableSchema
{ name = "discovery"
, schema = Just "public"
, columns = Discovery
{ d_docId = "doc_id"
}
}
discoverySchema' :: TableSchema (Discovery' Name)
discoverySchema' = discoverySchema
{ columns = Discovery'
{ d_table = columns discoverySchema
, d_search = "search"
}
}
rel8 is impressively smart enough to do the right thing for nested tables like this! kudos to you all for such an amazing library!
Is the problem with unsafeDefault maybe a regression? #121 claims to have fixed the "DEFAULT is not allowed in this context" thing, but it looks like something changed since then. This pattern match in Rel8.Statement.Select:
ppRows :: Table Expr a => Query a -> Doc
ppRows query = case optimize primQuery of
-- Special case VALUES because we can't use DEFAULT inside a SELECT
Optimized (Opaleye.Product ((_, Opaleye.Values symbols rows) :| []) [])
| eqSymbols symbols (toList (T.exprs a)) ->
Opaleye.ppValues_ (map Opaleye.sqlExpr <$> toList rows)
_ -> ppSelect query
Seems to be going into the "_" branch. I think it needs to be something like this now:
ppRows :: Table Expr a => Query a -> Doc
ppRows query = case optimize primQuery of
-- Special case VALUES because we can't use DEFAULT inside a SELECT
Optimized (Opaleye.Values symbols rows)
| eqSymbols symbols (toList (T.exprs a)) ->
Opaleye.ppValues_ (map Opaleye.sqlExpr <$> toList rows)
_ -> ppSelect query
Making that change allows my insert statements with defaults to work. Not sure if that is actually correct; don't understand Opaleye's datatypes.
I have a testcase for this, but I'm having trouble getting the temporary postgres database to work. In the mean time, I have the unittest all hacked up to connect to an actual postgres database.
Set up test table:
peter@gtower:~/rel8$ psql
psql (12.12 (Ubuntu 12.12-0ubuntu0.20.04.1))
Type "help" for help.
peter=> create table test_table (column1 text default 'apples', column2 bool default false);
CREATE TABLE
This test fails on master (1); passes with the change to the pattern match (2); and fails I change "apples" to "oranges" (3).
testDefaultValues :: IO () -> TestTree
testDefaultValues = databasePropertyTest' "can insert default values" \transaction -> do
--rows <- forAll $ Gen.map (Range.linear 0 5) $ liftA2 (,) genTestTable genTestTable
transaction do
selected <- lift do
statement () $ Rel8.insert Rel8.Insert
{ into = testTableSchema
, rows = Rel8.values [ TestTable { testTableColumn1 = Rel8.unsafeDefault, testTableColumn2 = Rel8.unsafeDefault }]
, onConflict = Rel8.DoNothing
, returning = pure ()
}
statement () $ Rel8.select do
Rel8.each testTableSchema
sort selected === sort ([TestTable { testTableColumn1 = "apples", testTableColumn2 = False}])
-- cover 1 "Empty" $ null rows
-- cover 1 "Singleton" $ null $ drop 1 $ Map.keys rows
-- cover 1 ">1 row" $ not $ null $ drop 1 $ Map.keys rows
return ()
1:
2:
3:
(Note the signature of that test is different than the other tests because of the aforementioned hacks.)
Hi @peterwicksstringfield - I believe this is a recent regression in main
that I think @shane-circuithub is aware of. The last published release shouldn't have this problem though
When working with UPDATE statements, [...] I can use unsafeDefault to fill this in successfully (but it's a bit annoying!)
This doesn't work if the unsafeDefault
is going into a column that is a foreign key target referenced by some table: Postgres will complain that updating it to DEFAULT
would violate referential integrity.
I wonder if there's a way to change updates to use a type family context
in set :: _ -> _ -> Foo context
that wraps each constructor in a Maybe
and omits the SET
s for the Nothing
cases.
I've got a column in my database that is created via:
which I'd like to be able to query on. I've thus added it to my rel8 schema:
There are two problems with this:
1) When working with UPDATE statements, rel8 generates SQL like:
which postgres complains about; this must have value
DEFAULT
. I can useunsafeDefault
to fill this in successfully (but it's a bit annoying!)2) When working with INSERT statements, rel8 generates SQL like:
which also fails (
DEFAULT is not allowed in this context
), however, I can't figure out how to sidestep this problem; rel8 seems to insist on an explicit cast in inserts.Is there a better way of working with GENERATED ALWAYS columns? I'd like to be able to select this field, but have it ignored from all updates and inserts.