-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dealing with GENERATED ALWAYS columns? #193
Comments
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. [nix-shell:~/rel8]$ cabal test
Resolving dependencies...
Build profile: -w ghc-9.2.4 -O1
In order, the following will be built (use -v for more details):
- rel8-1.4.0.0 (test:tests) (first run)
Preprocessing test suite 'tests' for rel8-1.4.0.0..
Building test suite 'tests' for rel8-1.4.0.0..
Running 1 test suites...
Test suite tests: RUNNING...
rel8
Can SELECT TestTable: FAIL
Exception: InitDbFailed {startErrorStdOut = "The files belonging to this database system will be owned by user \"peter\".This user must also own the server process.", startErrorStdErr = "", startErrorExitCode = ExitFailure 1}
Use -p '/Can SELECT TestTable/' to rerun this test only. 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: Linking /home/peter/rel8/dist-newstyle/build/x86_64-linux/ghc-8.10.7/rel8-1.4.0.0/t/tests/build/tests/tests ...
Running 1 test suites...
Test suite tests: RUNNING...
can insert default values: FAIL
✗ <interactive> failed at tests/Main.hs:926:27
after 1 test.
┏━━ tests/Main.hs ━━━
920 ┃ databasePropertyTest'
921 ┃ :: TestName
922 ┃ -> ((TestT Transaction () -> PropertyT IO ()) -> PropertyT IO ())
923 ┃ -> IO () -> TestTree
924 ┃ databasePropertyTest' testName f _getTestDatabase =
925 ┃ withResource (acquire "xxx" >>= either (maybe empty (fail . unpack . decodeUtf8)) pure) release $ \c ->
926 ┃ testProperty testName $ property do
927 ┃ connection <- lift c
928 ┃ f $ test . hoist \m -> do
929 ┃ e <- run (Hasql.transaction Hasql.Serializable Hasql.Write (m <* condemn)) connection
930 ┃ either throwIO pure e
┃ ^^^^^^^^^^^^^^^^^^^^^
┃ │ ━━━ Exception (QueryError) ━━━
┃ │ QueryError "INSERT INTO \"test_table\" (\"column1\",\n \"column2\")\nSELECT\nCAST(\"values_1\" AS text) as \"testTableColumn1\",\nCAST(\"values_2\" AS bool) as \"testTableColumn2\"\nFROM (SELECT \"column1\" as \"values_1\",\n \"column2\" as \"values_2\"\n FROM\n (VALUES\n (DEFAULT,DEFAULT)) as \"V\") as \"T1\"\nON CONFLICT DO NOTHING" [] (ResultError (ServerError "42601" "DEFAULT is not allowed in this context" Nothing Nothing (Just 285)))
This failure can be reproduced by running:
> recheck (Size 0) (Seed 14096366136193415544 13383493698543857611) <property>
Use '--pattern "$NF ~ /can insert default values/" --hedgehog-replay "Size 0 Seed 14096366136193415544 13383493698543857611"' to reproduce from the command-line.
1 out of 1 tests failed (0.02s)
Test suite tests: FAIL
Test suite logged to:
/home/peter/rel8/dist-newstyle/build/x86_64-linux/ghc-8.10.7/rel8-1.4.0.0/t/tests/test/rel8-1.4.0.0-tests.log
0 of 1 test suites (0 of 1 test cases) passed.
Error: cabal: Tests failed for test:tests from rel8-1.4.0.0. 2: Linking /home/peter/rel8/dist-newstyle/build/x86_64-linux/ghc-8.10.7/rel8-1.4.0.0/t/tests/build/tests/tests ...
Running 1 test suites...
Test suite tests: RUNNING...
Test suite tests: PASS
Test suite logged to:
/home/peter/rel8/dist-newstyle/build/x86_64-linux/ghc-8.10.7/rel8-1.4.0.0/t/tests/test/rel8-1.4.0.0-tests.log
1 of 1 test suites (1 of 1 test cases) passed. 3: Linking /home/peter/rel8/dist-newstyle/build/x86_64-linux/ghc-8.10.7/rel8-1.4.0.0/t/tests/build/tests/tests ...
Running 1 test suites...
Test suite tests: RUNNING...
can insert default values: FAIL
✗ <interactive> failed at tests/Main.hs:912:5
after 1 test.
┏━━ tests/Main.hs ━━━
896 ┃ testDefaultValues :: IO () -> TestTree
897 ┃ testDefaultValues = databasePropertyTest' "can insert default values" \transaction -> do
898 ┃ --rows <- forAll $ Gen.map (Range.linear 0 5) $ liftA2 (,) genTestTable genTestTable
899 ┃
900 ┃ transaction do
901 ┃ selected <- lift do
902 ┃ statement () $ Rel8.insert Rel8.Insert
903 ┃ { into = testTableSchema
904 ┃ , rows = Rel8.values [ TestTable { testTableColumn1 = Rel8.unsafeDefault, testTableColumn2 = Rel8.unsafeDefault }]
905 ┃ , onConflict = Rel8.DoNothing
906 ┃ , returning = pure ()
907 ┃ }
908 ┃
909 ┃ statement () $ Rel8.select do
910 ┃ Rel8.each testTableSchema
911 ┃
912 ┃ sort selected === sort ([TestTable { testTableColumn1 = "oranges", testTableColumn2 = False}])
┃ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
┃ │ ━━━ Failed (- lhs) (+ rhs) ━━━
┃ │ [
┃ │ TestTable {
┃ │ testTableColumn1 =
┃ │ - "apples"
┃ │ + "oranges"
┃ │ , testTableColumn2 =
┃ │ False
┃ │ }
┃ │ ]
913 ┃
914 ┃ -- cover 1 "Empty" $ null rows
915 ┃ -- cover 1 "Singleton" $ null $ drop 1 $ Map.keys rows
916 ┃ -- cover 1 ">1 row" $ not $ null $ drop 1 $ Map.keys rows
917 ┃
918 ┃ return ()
This failure can be reproduced by running:
> recheck (Size 0) (Seed 5067174663986397603 5596507757282192057) <property>
Use '--pattern "$NF ~ /can insert default values/" --hedgehog-replay "Size 0 Seed 5067174663986397603 5596507757282192057"' to reproduce from the command-line.
1 out of 1 tests failed (0.02s)
Test suite tests: FAIL
Test suite logged to:
/home/peter/rel8/dist-newstyle/build/x86_64-linux/ghc-8.10.7/rel8-1.4.0.0/t/tests/test/rel8-1.4.0.0-tests.log
0 of 1 test suites (0 of 1 test cases) passed.
Error: cabal: Tests failed for test:tests from rel8-1.4.0.0. (Note the signature of that test is different than the other tests because of the aforementioned hacks.) databasePropertyTest'
:: TestName
-> ((TestT Transaction () -> PropertyT IO ()) -> PropertyT IO ())
-> IO () -> TestTree
databasePropertyTest' testName f _getTestDatabase =
withResource (acquire "XXX" >>= either (maybe empty (fail . unpack . decodeUtf8)) pure) release $ \c ->
testProperty testName $ property do
connection <- lift c
f $ test . hoist \m -> do
e <- run (Hasql.transaction Hasql.Serializable Hasql.Write (m <* condemn)) connection
either throwIO pure e |
Hi @peterwicksstringfield - I believe this is a recent regression in |
This doesn't work if the |
I wonder if there's a way to change updates to use a type family |
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:
which postgres complains about; this must have value
DEFAULT
. I can useunsafeDefault
to fill this in successfully (but it's a bit annoying!)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.
The text was updated successfully, but these errors were encountered: