Skip to content
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

QuasiQuoter Improvements #1256

Merged
merged 35 commits into from
May 4, 2021
Merged

Conversation

parsonsmatt
Copy link
Collaborator

@parsonsmatt parsonsmatt commented Apr 27, 2021

This PR improves the QuasiQuoter. It no longer returns an EntityDef, instead it returns UnboundEntityDef. All of the compile-time type splicing responsibilities have been shifted over to mkPersist.

You can now refer to foreign keys defined outside of the module.

You can refer to entity IDs in an Id column (eg Id UserId now works).

  • Still need to fix the setting of foreign key references.

This PR also disables the MongoDB build. The reason is that breaking the cycle in the EmbedEntityDef is necessary, and is also quite difficult! It'd be nice to support MongoDB, but I'd rather just pause support for Mongo for now. Given that Persistent gets 4470 downlaods in the last 30 days and Mongo only has 115, I'm OK with temporarily dropping support.

I've added upper bounds constraints so folks won't be able to upgrade when this is released.

Consider this a call to action for additional maintainers for persistent-mongoDB!


Before submitting your PR, check that you've:

  • Documented new APIs with Haddock markup
  • Added @since declarations to the Haddock
  • Ran stylish-haskell on any changed files.
  • Adhered to the code style (see the .editorconfig file for details)

After submitting your PR:

  • Update the Changelog.md file with a link to your PR
  • Bumped the version number if there isn't an (unreleased) on the Changelog
  • Check that CI passes (or if it fails, for reasons unrelated to your change, like CI timeouts)

Fixes #1241

Fixes #1073

Fixes #994

Fixes #1042

FIxes #786

Fixes #1149

@parsonsmatt parsonsmatt added this to the 2.13 milestone Apr 27, 2021
@parsonsmatt parsonsmatt changed the base branch from master to persistent-2.13 April 27, 2021 23:53
@parsonsmatt parsonsmatt marked this pull request as draft April 28, 2021 00:07
@parsonsmatt
Copy link
Collaborator Author

Currently we're getting a test failure where all foo SomeTableId columns are determined to be SqlInt64 by the QuasiQuoter, and this isn't getting fixed in post.

I think a fix is to have an UnboundFieldDef on UnboundEntityDef, and these are spliced up nice and right in post. That should make the threading behavior more clear.

@parsonsmatt parsonsmatt marked this pull request as ready for review May 3, 2021 22:32
Copy link
Collaborator Author

@parsonsmatt parsonsmatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Massive change. Wish this were a smaller PR but I just kept smashing into problems and fixing things.

Very excited to get this in. Will make it a lot easier to work on the QQ and add features now that we're being more direct about what we can provide.

I need to write a blog post on this whole technique. It's pretty amazing. A two phase Template Haskell splicing setup is really quite brilliant. But I think it may be possible to get it to a single phase...

@@ -2,7 +2,7 @@ packages:
persistent
persistent-sqlite
persistent-test
persistent-mongoDB
-- persistent-mongoDB
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mongo DB is out of commission for now.

the embed entity def stuff is really hard to get right

i think it'll be easy to do when i've got, like, more intelligent multicolumn fields

but for right now i'm just disabling it

{-# LANGUAGE DerivingStrategies #-}
{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}

module Database.Persist.Sqlite.CompositeSpec where
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to pull out some stuff and better organize the test suite

import Init


-- mpsGeneric = False is due to a bug or at least lack of a feature in mkKeyTypeDec TH.hs
share [mkPersist persistSettings { mpsGeneric = False }, mkMigrate "compositeMigrate", mkDeleteCascade persistSettings { mpsGeneric = False }] [persistLowerCase|
share [mkPersist persistSettings { mpsGeneric = False }, mkMigrate "compositeMigrate"] [persistLowerCase|
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mkDeleteCascade is gone, replaced with the cascade on fields directly

@@ -640,72 +640,3 @@ specsWith runDb = describe "persistent" $ do
fieldComments nameField
`shouldBe`
Just "Fields should be documentable.\n"

describe "JsonEncoding" $ do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved into a specific test module closer to home

@@ -105,7 +115,7 @@ class ( PersistField (Key record), ToJSON (Key record), FromJSON (Key record)
-- | A meta operation to retrieve all the 'Unique' keys.
persistUniqueKeys :: record -> [Unique record]
-- | A lower level operation.
persistUniqueToFieldNames :: Unique record -> [(FieldNameHS, FieldNameDB)]
persistUniqueToFieldNames :: Unique record -> NonEmpty (FieldNameHS, FieldNameDB)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a great big change and it is so good

@@ -60,7 +58,7 @@ specsWith runDb = describe "tree" $ do
ConstraintNameHS "fkparent"
it "has the right DB constraint name" $ do
foreignConstraintNameDBName `shouldBe`
ConstraintNameDB "treesfkparent"
ConstraintNameDB "treefkparent"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i should figure out how to unbork that :\

entityColumnNames ent conn =
(if hasNaturalKey ent
then [] else [connEscapeFieldName conn . fieldDB $ getEntityId ent])
<> map (connEscapeFieldName conn . fieldDB) (getEntityFields ent)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was entirely equivalent? lol

--
-- @since 2.13.0.0
-> [UnboundEntityDef]
-> [UnboundEntityDef]
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fortunately a lot of the new lines are, like, comments and indentation and spacing t make it easier to read

-- look at every emFieldEmbed to see if it refers to an already seen EntityNameHS
-- so start with entityHaskell ent and accumulate embeddedHaskell em
breakEntDefCycle :: EntityDef -> EntityDef
breakEntDefCycle entDef =
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EmbedEntityDef no longer has a cycle

need to destroy embedding no-normal things

-- @since 2.5.3
parseReferences :: PersistSettings -> Text -> Q Exp
parseReferences ps s = lift $
map (mkEntityDefSqlTypeExp embedEntityMap entityMap) noCycleEnts
parseReferences ps s = lift $ parse ps s
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now, honestly,

it would be kinda cool to have this do something a little smarter than merely lift :: [UnboundEntityDef] -> Q Exp

would love to see QQuasi in something like ParsecT _ Q

Copy link
Member

@pbrisbin pbrisbin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish I had the domain knowledge to add a meaningful review here. The idea sounds great, and thanks for poking me for review. Maybe if you keep doing that, I will be able to add something meaningful some day :)

On the not meaningful side, I did just notice "Ran stylish-haskell on any changed files." in the checklist. I have a side-project that actually automates that, if you're interested: https://restyled.io. If you want any more details or help setting it up, let me know. It's all open source and in Haskell too.

@parsonsmatt
Copy link
Collaborator Author

@pbrisbin If you're still at Freckle, it'd be nice to know how these changes might affect y'all's codebase. I'll make an issue to get restyled working, that'd be great 😄

@pbrisbin
Copy link
Member

pbrisbin commented May 4, 2021

If you're still at Freckle, it'd be nice to know how these changes might affect y'all's codebase

Oh yeah, totally appreciate that. Can you maybe link me to a specific part that shows the "user"-facing changes? Will we have to modify our existing entity definitions? I got the sense this would open up some new things, but not require any actual migration to them yet, but that could be wrong.

@parsonsmatt
Copy link
Collaborator Author

Yeah, that should be the case. The biggest differences are:

  1. If you're writing your own thing that uses the QuasiQuoter, then the changes to that will be breaking. eg [peristLowerCase|...|] no longer spliced in a [EntityDef], it splices in a [UnboundEntityDef].
  2. If you're using embedded entities extensively, or in ways that aren't covered by the test suite, then this may break your code. I'm not terribly confident that the tests there cover all possible uses.

@pbrisbin
Copy link
Member

pbrisbin commented May 4, 2021

Cool, (2) won't impact us. For (1), all our definitions are of the form:

mkPersist sqlSettings [persistLowerCase|
Teacher sql=teachers
  -- ...
|]

So as long as mkPersist accepts whatever persistLowerCase will now splice in, we are unaffected.

@parsonsmatt parsonsmatt merged commit bac761a into persistent-2.13 May 4, 2021
@parsonsmatt parsonsmatt deleted the matt/forgiving-quasi-quoter branch May 4, 2021 22:11
parsonsmatt added a commit that referenced this pull request May 5, 2021
* Internalize SqlBackend (#1225)

* abstractification

* abstractification

* Internalize SqlBackend

* suppor tother sql dbs

* bounds

* asdf

* import data.monoid

* limitoffset and backendspecificoverrides

* use setter

* getConnUpsertSql

* formatting

* sigh

* clean warns

* cabal formatting

* merge resolve

* lol

* ok

* update changelogs

* one more [ci skip]

* Implicit ID Column Configuration (#1234)

* Implicit ID Column COnfiguration

* PersistSettings is internal

* start teasing out the module structure

* move around, factor out the Names module

* start enumerating types, make entitydef abstract

* entity def abstraction

* teasing out the EntityDef stuff

* builds

* testinggg

* it works

* it works

* tidy up

* sigh

* i hate you

* tidy

* wrote test for mysql, need to set maxlen sigh

* mysql test, need to be able to set maxlen

* support mysql lmfao

* whyyy

* Deprecate mpsGeneric (#1250)

* discoverEntities (#1253)

* discover entities

* remove fdescribe

* changelog

* yupo

* remove error

* Fix migrations (#1252)

* Better migrations

* why is the test failing

* Columns are present in entityFields now, but the generated code is broken.

* th specs work

* fixed mkColumns

* changelog entry

* fix mongo

* no idea why this is broken now

* why on earth did this work

* remove debug trace statements

* typo

* what no put that back in

* Check for existence of entities before generating them (#1255)

* wtf

* hmmm

* refactor and tidy

* are foreign fields never right ?!

* changelog

* fix comments

* dead code

* Implement config for customising the FK name (#1244)

* Implement config for customising the FK name

* Update changelog

* Tweak test description

* Tweaks/better use of types

* Review tweaks

* Some initial post-review changes

* Table name turned out to be EntityNameHS

* Do the same thing but for the constraint

* Expose more stuff

* Some refactoring / cleanup

* Fix changelog indentation

* Tidy code layout

* QuasiQuoter Improvements (#1256)

* QQ now returns UnboundEntityDef

* Relocate fixForeignKeysAll

* deprecate some stuff, reorganize some code

* ok, now we need to set sql types appropriately.

* dodgy instances are banned

* fuse away the EntityDefSqlTypeExp stuff

* refactor to top level

* fuse sqlTypeExp in there

* fix Key vs Id stuff

* still need to get the foreign key types right

* hmmm

* move to QuasiSpec

* clean up tests

* so close

* ok but what if i don't fix foreign keys

* wip

* oh man please

* getting closer...

* make some tests

* fix json and keyFromValueM

* slightly more graceful handling

* return dummy field for id, from persist values

* got some tests passing

* well sqlite works

* pg tests running

* what happened

* hmm mongo is trashed maybe

* bye mongo

* ok for real bye mongo, for now at least

* clean warns

* asdf

* drop GHC 8.2 support

* sigh

* lots of commments

* Merge branch 'master' into persistent-2.13 (#1261)

* Reexport PersistValue

* fix json for MigrationOnly

* Export onlyOneUniqueDef (fixes #1194)

* use onlyOneUniqueDef in persistent-postgresql

Co-authored-by: Dan Brooks <danbroooks@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants