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

Use StandaloneDeriving and DerivingStrategies in persistent-template #1002

Merged
merged 12 commits into from
Jan 3, 2020

Conversation

MaxGabriel
Copy link
Member

@MaxGabriel MaxGabriel commented Jan 1, 2020

This PR uses StandaloneDeriving to avoid the handwritten instances that currently exist in persistent-template.

In addition, it uses deriving strategies to specify that GeneralizedNewtypeDeriving should be used to derive the instances. This fixes the long-standing issue that derivation would fail if DeriveAnyClass was enabled

I think this is working, but I'd ideally like to test in a larger project to make sure this doesn't massively increase compile times or break any derived instances.


Before submitting your PR, check that you've:

After submitting your PR:

  • Update the Changelog.md file with a link to your PR
  • Check that CI passes (or if it fails, for reasons unrelated to your change, like CI timeouts)

This PR uses StandaloneDeriving to avoid the handwritten instances that currently exist in persistent-template.

In addition, it uses deriving strategies to specify that GeneralizedNewtypeDeriving should be used to derive the instances. This fixes the long-standing issue that derivation would fail if DeriveAnyClass was enabled

* Closes #578
* Closes #738
* Closes #908
@MaxGabriel
Copy link
Member Author

Master:

time                 12.70 ms   (12.29 ms .. 13.16 ms)
                     0.994 R²   (0.990 R² .. 0.997 R²)
mean                 13.76 ms   (13.42 ms .. 14.22 ms)
std dev              1.062 ms   (727.8 μs .. 1.542 ms)
variance introduced by outliers: 37% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/1x10
time                 18.71 ms   (17.79 ms .. 19.94 ms)
                     0.988 R²   (0.975 R² .. 0.997 R²)
mean                 19.34 ms   (18.97 ms .. 19.73 ms)
std dev              935.1 μs   (691.0 μs .. 1.279 ms)
variance introduced by outliers: 17% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/10x10
time                 19.24 ms   (18.82 ms .. 19.70 ms)
                     0.997 R²   (0.994 R² .. 0.999 R²)
mean                 19.51 ms   (19.19 ms .. 19.90 ms)
std dev              856.3 μs   (610.5 μs .. 1.108 ms)
variance introduced by outliers: 17% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/100x10
time                 193.8 ms   (163.8 ms .. 220.1 ms)
                     0.986 R²   (0.970 R² .. 1.000 R²)
mean                 195.6 ms   (173.0 ms .. 209.0 ms)
std dev              23.12 ms   (10.11 ms .. 34.59 ms)
variance introduced by outliers: 31% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x1
time                 1.166 ms   (1.142 ms .. 1.187 ms)
                     0.997 R²   (0.996 R² .. 0.998 R²)
mean                 1.165 ms   (1.154 ms .. 1.180 ms)
std dev              46.05 μs   (39.05 μs .. 54.83 μs)
variance introduced by outliers: 28% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x10
time                 18.23 ms   (17.66 ms .. 18.63 ms)
                     0.995 R²   (0.989 R² .. 0.999 R²)
mean                 18.79 ms   (18.43 ms .. 19.10 ms)
std dev              771.6 μs   (594.1 μs .. 1.035 ms)
variance introduced by outliers: 13% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x100
time                 1.103 s    (493.5 ms .. 1.586 s)
                     0.952 R²   (0.920 R² .. 1.000 R²)
mean                 1.099 s    (927.5 ms .. 1.228 s)
std dev              165.6 ms   (76.29 ms .. 201.2 ms)
variance introduced by outliers: 46% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/20x10
time                 46.39 ms   (43.65 ms .. 49.01 ms)
                     0.994 R²   (0.988 R² .. 1.000 R²)
mean                 45.66 ms   (44.99 ms .. 46.69 ms)
std dev              1.624 ms   (977.6 μs .. 2.180 ms)

benchmarking mkPersist/Nullable/Increasing model count/40x10
time                 90.23 ms   (83.29 ms .. 96.43 ms)
                     0.991 R²   (0.977 R² .. 0.999 R²)
mean                 92.60 ms   (85.79 ms .. 98.62 ms)
std dev              10.08 ms   (6.225 ms .. 16.92 ms)
variance introduced by outliers: 32% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/60x10
time                 130.5 ms   (111.2 ms .. 147.0 ms)
                     0.981 R²   (0.952 R² .. 0.998 R²)
mean                 134.2 ms   (123.1 ms .. 141.0 ms)
std dev              12.86 ms   (7.084 ms .. 19.10 ms)
variance introduced by outliers: 24% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/80x10
time                 184.5 ms   (165.3 ms .. 201.0 ms)
                     0.994 R²   (0.987 R² .. 1.000 R²)
mean                 178.8 ms   (159.4 ms .. 187.4 ms)
std dev              17.68 ms   (4.917 ms .. 26.92 ms)
variance introduced by outliers: 30% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/100x10
time                 237.0 ms   (208.4 ms .. 265.0 ms)
                     0.993 R²   (0.983 R² .. 1.000 R²)
mean                 224.8 ms   (196.6 ms .. 236.6 ms)
std dev              23.89 ms   (5.411 ms .. 35.91 ms)
variance introduced by outliers: 31% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x20
time                 71.59 ms   (69.05 ms .. 73.43 ms)
                     0.998 R²   (0.997 R² .. 1.000 R²)
mean                 72.48 ms   (70.27 ms .. 74.29 ms)
std dev              3.576 ms   (2.302 ms .. 5.843 ms)
variance introduced by outliers: 16% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x40
time                 244.7 ms   (193.7 ms .. 296.0 ms)
                     0.987 R²   (0.980 R² .. 1.000 R²)
mean                 239.0 ms   (210.4 ms .. 252.4 ms)
std dev              25.37 ms   (7.045 ms .. 36.04 ms)
variance introduced by outliers: 19% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x60
time                 563.7 ms   (416.3 ms .. 636.2 ms)
                     0.991 R²   (0.981 R² .. 1.000 R²)
mean                 513.8 ms   (455.6 ms .. 546.4 ms)
std dev              56.68 ms   (4.633 ms .. 75.43 ms)
variance introduced by outliers: 23% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x80
time                 962.5 ms   (897.8 ms .. 1.114 s)
                     0.997 R²   (0.994 R² .. 1.000 R²)
mean                 870.5 ms   (733.6 ms .. 918.1 ms)
std dev              91.42 ms   (1.131 ms .. 109.9 ms)
variance introduced by outliers: 23% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x100
time                 1.522 s    (856.5 ms .. 1.832 s)
                     0.978 R²   (0.938 R² .. 1.000 R²)
mean                 1.385 s    (1.189 s .. 1.499 s)
std dev              191.9 ms   (74.02 ms .. 263.0 ms)
variance introduced by outliers: 24% (moderately inflated)

Branch:

benchmarking mkPersist/From File
time                 12.95 ms   (12.19 ms .. 13.84 ms)
                     0.978 R²   (0.962 R² .. 0.991 R²)
mean                 14.63 ms   (14.08 ms .. 15.50 ms)
std dev              1.730 ms   (1.207 ms .. 2.724 ms)
variance introduced by outliers: 60% (severely inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/1x10
time                 18.96 ms   (18.35 ms .. 19.60 ms)
                     0.996 R²   (0.992 R² .. 0.999 R²)
mean                 19.39 ms   (19.14 ms .. 19.69 ms)
std dev              694.3 μs   (541.6 μs .. 892.4 μs)
variance introduced by outliers: 13% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/10x10
time                 18.82 ms   (18.33 ms .. 19.28 ms)
                     0.996 R²   (0.992 R² .. 0.999 R²)
mean                 19.36 ms   (19.01 ms .. 19.77 ms)
std dev              892.6 μs   (668.3 μs .. 1.116 ms)
variance introduced by outliers: 17% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/100x10
time                 189.6 ms   (160.1 ms .. 214.7 ms)
                     0.986 R²   (0.969 R² .. 1.000 R²)
mean                 193.2 ms   (172.6 ms .. 206.8 ms)
std dev              22.83 ms   (11.03 ms .. 32.44 ms)
variance introduced by outliers: 31% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x1
time                 1.164 ms   (1.139 ms .. 1.187 ms)
                     0.997 R²   (0.996 R² .. 0.999 R²)
mean                 1.173 ms   (1.159 ms .. 1.189 ms)
std dev              46.93 μs   (39.85 μs .. 61.26 μs)
variance introduced by outliers: 30% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x10
time                 18.66 ms   (18.24 ms .. 19.12 ms)
                     0.997 R²   (0.994 R² .. 0.999 R²)
mean                 18.91 ms   (18.66 ms .. 19.28 ms)
std dev              691.4 μs   (457.8 μs .. 979.1 μs)
variance introduced by outliers: 13% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x100
time                 1.159 s    (739.7 ms .. 1.547 s)
                     0.976 R²   (0.974 R² .. 1.000 R²)
mean                 1.108 s    (950.5 ms .. 1.188 s)
std dev              148.8 ms   (58.84 ms .. 185.9 ms)
variance introduced by outliers: 24% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/20x10
time                 44.57 ms   (43.77 ms .. 45.35 ms)
                     0.999 R²   (0.997 R² .. 1.000 R²)
mean                 45.08 ms   (44.56 ms .. 45.61 ms)
std dev              1.113 ms   (838.3 μs .. 1.427 ms)

benchmarking mkPersist/Nullable/Increasing model count/40x10
time                 89.81 ms   (86.49 ms .. 93.01 ms)
                     0.998 R²   (0.995 R² .. 0.999 R²)
mean                 88.26 ms   (82.10 ms .. 90.84 ms)
std dev              6.558 ms   (1.787 ms .. 10.66 ms)
variance introduced by outliers: 19% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/60x10
time                 137.5 ms   (128.5 ms .. 142.8 ms)
                     0.995 R²   (0.983 R² .. 1.000 R²)
mean                 133.1 ms   (120.9 ms .. 138.8 ms)
std dev              11.93 ms   (5.084 ms .. 20.00 ms)
variance introduced by outliers: 23% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/80x10
time                 178.9 ms   (159.8 ms .. 197.5 ms)
                     0.993 R²   (0.980 R² .. 1.000 R²)
mean                 177.6 ms   (164.2 ms .. 185.7 ms)
std dev              15.02 ms   (6.807 ms .. 23.11 ms)
variance introduced by outliers: 16% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/100x10
time                 223.0 ms   (193.0 ms .. 247.9 ms)
                     0.990 R²   (0.974 R² .. 1.000 R²)
mean                 218.8 ms   (194.5 ms .. 231.5 ms)
std dev              22.35 ms   (7.868 ms .. 33.59 ms)
variance introduced by outliers: 31% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x20
time                 70.15 ms   (66.45 ms .. 73.03 ms)
                     0.996 R²   (0.994 R² .. 0.999 R²)
mean                 70.87 ms   (68.00 ms .. 73.60 ms)
std dev              4.989 ms   (3.188 ms .. 8.254 ms)
variance introduced by outliers: 17% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x40
time                 235.9 ms   (175.2 ms .. 296.0 ms)
                     0.983 R²   (0.968 R² .. 1.000 R²)
mean                 244.1 ms   (230.8 ms .. 258.9 ms)
std dev              18.35 ms   (8.635 ms .. 26.37 ms)
variance introduced by outliers: 18% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x60
time                 557.7 ms   (392.2 ms .. 630.4 ms)
                     0.989 R²   (0.974 R² .. 1.000 R²)
mean                 501.2 ms   (438.6 ms .. 537.0 ms)
std dev              61.61 ms   (19.25 ms .. 82.88 ms)
variance introduced by outliers: 23% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x80
time                 970.8 ms   (698.5 ms .. 1.108 s)
                     0.991 R²   (0.975 R² .. 1.000 R²)
mean                 864.5 ms   (757.6 ms .. 926.2 ms)
std dev              105.4 ms   (32.80 ms .. 142.4 ms)
variance introduced by outliers: 23% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x100
time                 1.469 s    (914.7 ms .. 1.772 s)
                     0.981 R²   (0.960 R² .. 1.000 R²)
mean                 1.353 s    (1.167 s .. 1.455 s)
std dev              177.8 ms   (42.14 ms .. 235.6 ms)
variance introduced by outliers: 24% (moderately inflated)

@@ -30,7 +30,6 @@ matrix:
compiler: ": #GHC HEAD"
addons: {apt: {packages: [cabal-install-head,ghc-head,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}

- env: BUILD=stack ARGS="--resolver lts-9 --stack-yaml stack_lts-10.yaml"
Copy link
Member Author

Choose a reason for hiding this comment

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

LTS 9 is GHC 8.0

Nothing
constrs
<$> mapM conT names
#endif
Copy link
Member Author

Choose a reason for hiding this comment

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

No longer necessary now that we're not supporting GHC 8.0

Copy link
Collaborator

@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.

This looks great! Thanks. I want to test this on the work codebase and see if compile-times increase for our database modules.

, List.intercalate "\n" (map show extensions)
, "\n\nPlease enable the extensions by copy/pasting these lines into the top of your file:\n\n"
, List.intercalate "\n" (map extensionToPragma extensions)
]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice!! :D

Copy link
Member Author

Choose a reason for hiding this comment

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

Glad you liked that :)

deriving newtype instance PersistField (BackendKey $(pure backendT)) => PersistField (Key $(pure recordType))
deriving newtype instance PersistFieldSql (BackendKey $(pure backendT)) => PersistFieldSql (Key $(pure recordType))
deriving newtype instance ToJSON (BackendKey $(pure backendT)) => ToJSON (Key $(pure recordType))
deriving newtype instance FromJSON (BackendKey $(pure backendT)) => FromJSON (Key $(pure recordType))
Copy link
Collaborator

Choose a reason for hiding this comment

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

yess

@parsonsmatt
Copy link
Collaborator

Compilation time actually went from ~5:00 to ~4:45 on a full build with this, so hell yeah!

I'm a little cautious on that version number though. This is going to be a breaking change for users of the library, and I'm not sure that a patch version bump is appropriate.

Copy link
Collaborator

@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.

Super excited to get this in and released with the bigger version bump!!

persistent-template/ChangeLog.md Outdated Show resolved Hide resolved
persistent-template/persistent-template.cabal Outdated Show resolved Hide resolved
MaxGabriel and others added 2 commits January 2, 2020 16:54
Co-Authored-By: Matt Parsons <parsonsmatt@gmail.com>
Co-Authored-By: Matt Parsons <parsonsmatt@gmail.com>
MaxGabriel added a commit that referenced this pull request Jan 3, 2020
(NB: this code is based on #1002. Will rebase once that's merged)

Currently this function is embedding the full `EntityDef` for every field of the entity. So, for a model with 20 fields, the code to parse a _single field_ embeds the definition of _all 20_ of those fields. This change fixes that.

Using the models in persistent-template/test/main.hs as an example, the old generated code to parse _a single field_ looks like this:

```
      fromPersistValues [x1_asSh, x2_asSi, x3_asSj, x4_asSk]
        = Person
            <$>
              (Database.Persist.TH.mapLeft
                 ((Database.Persist.TH.fieldError
                     (((((((((((EntityDef (HaskellName (pack "Person")))
                                 (DBName (pack "Person")))
                                ((((((((FieldDef (HaskellName (pack "Id"))) (DBName (pack "id")))
                                        ((FTTypeCon Nothing) (pack "PersonId")))
                                       SqlInt64)
                                      [])
                                     True)
                                    ((ForeignRef (HaskellName (pack "Person")))
                                       ((FTTypeCon (Just (pack "Data.Int"))) (pack "Int64"))))
                                   Nothing))
                               [pack "json"])
                              [(((((((FieldDef (HaskellName (pack "name")))
                                       (DBName (pack "name")))
                                      ((FTTypeCon Nothing) (pack "Text")))
                                     SqlString)
                                    [])
                                   True)
                                  NoReference)
                                 Nothing,
                               (((((((FieldDef (HaskellName (pack "age"))) (DBName (pack "age")))
                                      ((FTTypeCon Nothing) (pack "Int")))
                                     SqlInt64)
                                    [pack "Maybe"])
                                   True)
                                  NoReference)
                                 Nothing,
                               (((((((FieldDef (HaskellName (pack "foo"))) (DBName (pack "foo")))
                                      ((FTTypeCon Nothing) (pack "Foo")))
                                     SqlString)
                                    [])
                                   True)
                                  NoReference)
                                 Nothing,
                               (((((((FieldDef (HaskellName (pack "address")))
                                       (DBName (pack "address")))
                                      ((FTTypeCon Nothing) (pack "Address")))
                                     SqlString)
                                    [])
                                   True)
                                  (EmbedRef
                                     ((EmbedEntityDef (HaskellName (pack "Address")))
                                        [((EmbedFieldDef (DBName (pack "street"))) Nothing) Nothing,
                                         ((EmbedFieldDef (DBName (pack "city"))) Nothing) Nothing,
                                         ((EmbedFieldDef (DBName (pack "zip"))) Nothing) Nothing])))
                                 Nothing])
                             [])
                            [])
                           [pack "Show", pack "Eq"])
                          (containers-0.6.0.1:Data.Map.Internal.fromList []))
                         False)
                        Nothing))
                    ((((((((FieldDef (HaskellName (pack "name")))
                             (DBName (pack "name")))
                            ((FTTypeCon Nothing) (pack "Text")))
                           SqlString)
                          [])
                         True)
                        NoReference)
                       Nothing))
                 . fromPersistValue)
                x1_asSh
```

the new code to parse a single field looks like this:

```
      fromPersistValues [x1_asKP, x2_asKQ, x3_asKR, x4_asKS]
        = Person
            <$>
              (Database.Persist.TH.mapLeft
                 ((Database.Persist.TH.fieldError (pack "Person")) (pack "name"))
                 . fromPersistValue)
                x1_asKP
```

The generated code goes from 2560 to 1848 lines.

(The definition of those models for reference)

```
share [mkPersist sqlSettings { mpsGeneric = False }, mkDeleteCascade sqlSettings { mpsGeneric = False }] [persistUpperCase|
Person json
    name Text
    age Int Maybe
    foo Foo
    address Address
    deriving Show Eq
Address json
    street Text
    city Text
    zip Int Maybe
    deriving Show Eq
NoJson
    foo Text
    deriving Show Eq
|]

share [mkPersist sqlSettings { mpsGeneric = False, mpsGenerateLenses = True }] [persistLowerCase|
Lperson json
    name Text
    age Int Maybe
    address Laddress
    deriving Show Eq
Laddress json
    street Text
    city Text
    zip Int Maybe
    deriving Show Eq
|]
```

<hr>

Benchmarks show a radical improvement. This is master (+ the previous DerivingVia PR):

```
benchmarking mkPersist/From File
time                 11.75 ms   (11.13 ms .. 12.16 ms)
                     0.982 R²   (0.958 R² .. 0.997 R²)
mean                 12.87 ms   (12.49 ms .. 13.67 ms)
std dev              1.394 ms   (918.6 μs .. 2.229 ms)
variance introduced by outliers: 54% (severely inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/1x10
time                 18.31 ms   (17.98 ms .. 18.71 ms)
                     0.997 R²   (0.994 R² .. 0.999 R²)
mean                 18.59 ms   (18.34 ms .. 18.91 ms)
std dev              713.4 μs   (526.8 μs .. 955.5 μs)
variance introduced by outliers: 13% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/10x10
time                 18.21 ms   (17.94 ms .. 18.49 ms)
                     0.999 R²   (0.998 R² .. 1.000 R²)
mean                 18.42 ms   (18.26 ms .. 18.68 ms)
std dev              485.9 μs   (288.8 μs .. 838.4 μs)

benchmarking mkPersist/Non-Null Fields/Increasing model count/100x10
time                 186.2 ms   (159.5 ms .. 211.6 ms)
                     0.988 R²   (0.972 R² .. 1.000 R²)
mean                 186.3 ms   (167.4 ms .. 197.6 ms)
std dev              20.57 ms   (9.365 ms .. 32.12 ms)
variance introduced by outliers: 31% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x1
time                 1.101 ms   (1.091 ms .. 1.116 ms)
                     0.999 R²   (0.997 R² .. 1.000 R²)
mean                 1.101 ms   (1.093 ms .. 1.114 ms)
std dev              34.19 μs   (24.45 μs .. 53.26 μs)
variance introduced by outliers: 19% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x10
time                 19.13 ms   (18.45 ms .. 19.91 ms)
                     0.995 R²   (0.992 R² .. 0.999 R²)
mean                 18.09 ms   (17.71 ms .. 18.46 ms)
std dev              870.8 μs   (622.8 μs .. 1.206 ms)
variance introduced by outliers: 17% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x100
time                 1.140 s    (723.1 ms .. 1.522 s)
                     0.976 R²   (0.973 R² .. 1.000 R²)
mean                 1.093 s    (939.5 ms .. 1.197 s)
std dev              145.3 ms   (8.205 ms .. 181.4 ms)
variance introduced by outliers: 24% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/20x10
time                 43.58 ms   (42.79 ms .. 44.56 ms)
                     0.998 R²   (0.996 R² .. 1.000 R²)
mean                 43.98 ms   (43.34 ms .. 44.86 ms)
std dev              1.531 ms   (964.5 μs .. 2.408 ms)

benchmarking mkPersist/Nullable/Increasing model count/40x10
time                 89.01 ms   (85.38 ms .. 91.83 ms)
                     0.997 R²   (0.993 R² .. 0.999 R²)
mean                 87.92 ms   (81.29 ms .. 91.09 ms)
std dev              7.472 ms   (3.033 ms .. 12.94 ms)
variance introduced by outliers: 28% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/60x10
time                 116.4 ms   (105.6 ms .. 123.7 ms)
                     0.994 R²   (0.986 R² .. 0.999 R²)
mean                 126.8 ms   (121.4 ms .. 133.0 ms)
std dev              8.540 ms   (5.824 ms .. 11.83 ms)
variance introduced by outliers: 12% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/80x10
time                 197.2 ms   (164.6 ms .. 232.6 ms)
                     0.988 R²   (0.958 R² .. 1.000 R²)
mean                 189.6 ms   (176.6 ms .. 201.4 ms)
std dev              17.32 ms   (9.377 ms .. 25.86 ms)
variance introduced by outliers: 16% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/100x10
time                 262.8 ms   (225.6 ms .. 281.7 ms)
                     0.990 R²   (0.970 R² .. 1.000 R²)
mean                 248.4 ms   (234.2 ms .. 258.1 ms)
std dev              15.63 ms   (10.30 ms .. 19.52 ms)
variance introduced by outliers: 17% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x20
time                 90.77 ms   (81.84 ms .. 101.5 ms)
                     0.974 R²   (0.932 R² .. 0.997 R²)
mean                 73.75 ms   (66.31 ms .. 80.22 ms)
std dev              11.92 ms   (8.285 ms .. 18.59 ms)
variance introduced by outliers: 58% (severely inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x40
time                 258.2 ms   (202.5 ms .. 316.8 ms)
                     0.988 R²   (0.968 R² .. 1.000 R²)
mean                 235.6 ms   (193.4 ms .. 253.5 ms)
std dev              33.43 ms   (10.60 ms .. 49.19 ms)
variance introduced by outliers: 38% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x60
time                 542.3 ms   (431.4 ms .. 591.7 ms)
                     0.995 R²   (0.988 R² .. 1.000 R²)
mean                 528.9 ms   (499.9 ms .. 545.4 ms)
std dev              28.15 ms   (9.013 ms .. 37.98 ms)
variance introduced by outliers: 19% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x80
time                 908.0 ms   (814.3 ms .. 1.091 s)
                     0.995 R²   (0.990 R² .. 1.000 R²)
mean                 838.9 ms   (751.9 ms .. 886.1 ms)
std dev              85.02 ms   (3.280 ms .. 108.9 ms)
variance introduced by outliers: 23% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x100
time                 1.621 s    (1.129 s .. 1.879 s)
                     0.990 R²   (0.970 R² .. 1.000 R²)
mean                 1.405 s    (1.197 s .. 1.523 s)
std dev              202.9 ms   (57.30 ms .. 273.0 ms)
variance introduced by outliers: 24% (moderately inflated)
```

vs this branch:

```
benchmarking mkPersist/From File
time                 621.8 μs   (612.2 μs .. 633.9 μs)
                     0.996 R²   (0.994 R² .. 0.998 R²)
mean                 668.6 μs   (656.5 μs .. 683.9 μs)
std dev              46.55 μs   (37.19 μs .. 67.34 μs)
variance introduced by outliers: 59% (severely inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/1x10
time                 4.577 ms   (4.409 ms .. 4.833 ms)
                     0.983 R²   (0.965 R² .. 0.996 R²)
mean                 4.610 ms   (4.512 ms .. 4.726 ms)
std dev              324.7 μs   (239.5 μs .. 460.0 μs)
variance introduced by outliers: 44% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/10x10
time                 4.479 ms   (4.348 ms .. 4.628 ms)
                     0.994 R²   (0.991 R² .. 0.997 R²)
mean                 4.717 ms   (4.647 ms .. 4.768 ms)
std dev              188.8 μs   (143.7 μs .. 235.5 μs)
variance introduced by outliers: 20% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/100x10
time                 55.67 ms   (53.85 ms .. 57.68 ms)
                     0.995 R²   (0.986 R² .. 0.999 R²)
mean                 55.03 ms   (51.81 ms .. 56.67 ms)
std dev              4.023 ms   (2.152 ms .. 6.421 ms)
variance introduced by outliers: 23% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x1
time                 885.4 μs   (873.7 μs .. 898.4 μs)
                     0.998 R²   (0.997 R² .. 0.999 R²)
mean                 909.3 μs   (899.6 μs .. 923.9 μs)
std dev              40.42 μs   (29.71 μs .. 61.27 μs)
variance introduced by outliers: 36% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x10
time                 4.669 ms   (4.463 ms .. 4.850 ms)
                     0.991 R²   (0.985 R² .. 0.995 R²)
mean                 4.673 ms   (4.590 ms .. 4.754 ms)
std dev              264.4 μs   (226.1 μs .. 318.1 μs)
variance introduced by outliers: 34% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x100
time                 43.01 ms   (41.66 ms .. 44.14 ms)
                     0.997 R²   (0.992 R² .. 0.999 R²)
mean                 42.88 ms   (40.65 ms .. 44.22 ms)
std dev              3.305 ms   (1.574 ms .. 5.780 ms)
variance introduced by outliers: 27% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/20x10
time                 11.38 ms   (11.18 ms .. 11.68 ms)
                     0.995 R²   (0.985 R² .. 0.999 R²)
mean                 11.16 ms   (10.97 ms .. 11.41 ms)
std dev              603.2 μs   (391.3 μs .. 912.9 μs)
variance introduced by outliers: 26% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/40x10
time                 24.00 ms   (23.56 ms .. 24.38 ms)
                     0.999 R²   (0.997 R² .. 0.999 R²)
mean                 23.97 ms   (23.74 ms .. 24.24 ms)
std dev              538.8 μs   (409.6 μs .. 720.3 μs)

benchmarking mkPersist/Nullable/Increasing model count/60x10
time                 39.98 ms   (37.68 ms .. 43.16 ms)
                     0.988 R²   (0.976 R² .. 0.999 R²)
mean                 36.94 ms   (36.04 ms .. 38.32 ms)
std dev              2.173 ms   (1.135 ms .. 3.656 ms)
variance introduced by outliers: 19% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/80x10
time                 51.12 ms   (44.79 ms .. 57.38 ms)
                     0.969 R²   (0.915 R² .. 0.998 R²)
mean                 56.90 ms   (53.41 ms .. 60.70 ms)
std dev              6.589 ms   (4.712 ms .. 8.849 ms)
variance introduced by outliers: 40% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/100x10
time                 60.83 ms   (55.87 ms .. 65.23 ms)
                     0.991 R²   (0.983 R² .. 0.999 R²)
mean                 63.33 ms   (59.62 ms .. 65.63 ms)
std dev              5.272 ms   (2.846 ms .. 8.609 ms)
variance introduced by outliers: 24% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x20
time                 9.925 ms   (9.701 ms .. 10.16 ms)
                     0.995 R²   (0.991 R² .. 0.998 R²)
mean                 10.15 ms   (9.972 ms .. 10.31 ms)
std dev              460.9 μs   (371.1 μs .. 571.1 μs)
variance introduced by outliers: 19% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x40
time                 19.03 ms   (18.30 ms .. 19.67 ms)
                     0.994 R²   (0.988 R² .. 0.997 R²)
mean                 20.77 ms   (19.98 ms .. 22.18 ms)
std dev              2.346 ms   (1.350 ms .. 3.393 ms)
variance introduced by outliers: 51% (severely inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x60
time                 29.54 ms   (28.63 ms .. 30.63 ms)
                     0.996 R²   (0.993 R² .. 0.998 R²)
mean                 29.85 ms   (29.35 ms .. 30.35 ms)
std dev              1.064 ms   (835.8 μs .. 1.455 ms)
variance introduced by outliers: 11% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x80
time                 39.68 ms   (38.06 ms .. 41.69 ms)
                     0.993 R²   (0.985 R² .. 0.998 R²)
mean                 39.61 ms   (37.67 ms .. 40.74 ms)
std dev              3.070 ms   (1.579 ms .. 5.208 ms)
variance introduced by outliers: 25% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x100
time                 48.92 ms   (46.41 ms .. 50.57 ms)
                     0.996 R²   (0.993 R² .. 0.998 R²)
mean                 49.09 ms   (46.21 ms .. 50.95 ms)
std dev              4.472 ms   (2.372 ms .. 8.241 ms)
variance introduced by outliers: 29% (moderately inflated)
```
MaxGabriel added a commit to yesodweb/yesod-scaffold that referenced this pull request Jan 3, 2020
The upcoming version of persistent-template will require these yesodweb/persistent#1002
MaxGabriel added a commit to yesodweb/yesod that referenced this pull request Jan 3, 2020
…t persistent-template

The upcoming version of persistent-template will require these yesodweb/persistent#1002
@parsonsmatt parsonsmatt merged commit 31f6a3c into master Jan 3, 2020
parsonsmatt added a commit that referenced this pull request Jan 3, 2020
* persistent-tempalte: Use StandaloneDeriving and DerivingStrategies

This PR uses StandaloneDeriving to avoid the handwritten instances that currently exist in persistent-template.

In addition, it uses deriving strategies to specify that GeneralizedNewtypeDeriving should be used to derive the instances. This fixes the long-standing issue that derivation would fail if DeriveAnyClass was enabled

* Closes #578
* Closes #738
* Closes #908

* ..

* ..

* ..

* ..

* ..

* ..

* test fixes

* test fixes

* ..

* Update persistent-template/ChangeLog.md

Co-Authored-By: Matt Parsons <parsonsmatt@gmail.com>

* Update persistent-template/persistent-template.cabal

Co-Authored-By: Matt Parsons <parsonsmatt@gmail.com>

* Reduce code generated by fromPersistValues

(NB: this code is based on #1002. Will rebase once that's merged)

Currently this function is embedding the full `EntityDef` for every field of the entity. So, for a model with 20 fields, the code to parse a _single field_ embeds the definition of _all 20_ of those fields. This change fixes that.

Using the models in persistent-template/test/main.hs as an example, the old generated code to parse _a single field_ looks like this:

```
      fromPersistValues [x1_asSh, x2_asSi, x3_asSj, x4_asSk]
        = Person
            <$>
              (Database.Persist.TH.mapLeft
                 ((Database.Persist.TH.fieldError
                     (((((((((((EntityDef (HaskellName (pack "Person")))
                                 (DBName (pack "Person")))
                                ((((((((FieldDef (HaskellName (pack "Id"))) (DBName (pack "id")))
                                        ((FTTypeCon Nothing) (pack "PersonId")))
                                       SqlInt64)
                                      [])
                                     True)
                                    ((ForeignRef (HaskellName (pack "Person")))
                                       ((FTTypeCon (Just (pack "Data.Int"))) (pack "Int64"))))
                                   Nothing))
                               [pack "json"])
                              [(((((((FieldDef (HaskellName (pack "name")))
                                       (DBName (pack "name")))
                                      ((FTTypeCon Nothing) (pack "Text")))
                                     SqlString)
                                    [])
                                   True)
                                  NoReference)
                                 Nothing,
                               (((((((FieldDef (HaskellName (pack "age"))) (DBName (pack "age")))
                                      ((FTTypeCon Nothing) (pack "Int")))
                                     SqlInt64)
                                    [pack "Maybe"])
                                   True)
                                  NoReference)
                                 Nothing,
                               (((((((FieldDef (HaskellName (pack "foo"))) (DBName (pack "foo")))
                                      ((FTTypeCon Nothing) (pack "Foo")))
                                     SqlString)
                                    [])
                                   True)
                                  NoReference)
                                 Nothing,
                               (((((((FieldDef (HaskellName (pack "address")))
                                       (DBName (pack "address")))
                                      ((FTTypeCon Nothing) (pack "Address")))
                                     SqlString)
                                    [])
                                   True)
                                  (EmbedRef
                                     ((EmbedEntityDef (HaskellName (pack "Address")))
                                        [((EmbedFieldDef (DBName (pack "street"))) Nothing) Nothing,
                                         ((EmbedFieldDef (DBName (pack "city"))) Nothing) Nothing,
                                         ((EmbedFieldDef (DBName (pack "zip"))) Nothing) Nothing])))
                                 Nothing])
                             [])
                            [])
                           [pack "Show", pack "Eq"])
                          (containers-0.6.0.1:Data.Map.Internal.fromList []))
                         False)
                        Nothing))
                    ((((((((FieldDef (HaskellName (pack "name")))
                             (DBName (pack "name")))
                            ((FTTypeCon Nothing) (pack "Text")))
                           SqlString)
                          [])
                         True)
                        NoReference)
                       Nothing))
                 . fromPersistValue)
                x1_asSh
```

the new code to parse a single field looks like this:

```
      fromPersistValues [x1_asKP, x2_asKQ, x3_asKR, x4_asKS]
        = Person
            <$>
              (Database.Persist.TH.mapLeft
                 ((Database.Persist.TH.fieldError (pack "Person")) (pack "name"))
                 . fromPersistValue)
                x1_asKP
```

The generated code goes from 2560 to 1848 lines.

(The definition of those models for reference)

```
share [mkPersist sqlSettings { mpsGeneric = False }, mkDeleteCascade sqlSettings { mpsGeneric = False }] [persistUpperCase|
Person json
    name Text
    age Int Maybe
    foo Foo
    address Address
    deriving Show Eq
Address json
    street Text
    city Text
    zip Int Maybe
    deriving Show Eq
NoJson
    foo Text
    deriving Show Eq
|]

share [mkPersist sqlSettings { mpsGeneric = False, mpsGenerateLenses = True }] [persistLowerCase|
Lperson json
    name Text
    age Int Maybe
    address Laddress
    deriving Show Eq
Laddress json
    street Text
    city Text
    zip Int Maybe
    deriving Show Eq
|]
```

<hr>

Benchmarks show a radical improvement. This is master (+ the previous DerivingVia PR):

```
benchmarking mkPersist/From File
time                 11.75 ms   (11.13 ms .. 12.16 ms)
                     0.982 R²   (0.958 R² .. 0.997 R²)
mean                 12.87 ms   (12.49 ms .. 13.67 ms)
std dev              1.394 ms   (918.6 μs .. 2.229 ms)
variance introduced by outliers: 54% (severely inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/1x10
time                 18.31 ms   (17.98 ms .. 18.71 ms)
                     0.997 R²   (0.994 R² .. 0.999 R²)
mean                 18.59 ms   (18.34 ms .. 18.91 ms)
std dev              713.4 μs   (526.8 μs .. 955.5 μs)
variance introduced by outliers: 13% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/10x10
time                 18.21 ms   (17.94 ms .. 18.49 ms)
                     0.999 R²   (0.998 R² .. 1.000 R²)
mean                 18.42 ms   (18.26 ms .. 18.68 ms)
std dev              485.9 μs   (288.8 μs .. 838.4 μs)

benchmarking mkPersist/Non-Null Fields/Increasing model count/100x10
time                 186.2 ms   (159.5 ms .. 211.6 ms)
                     0.988 R²   (0.972 R² .. 1.000 R²)
mean                 186.3 ms   (167.4 ms .. 197.6 ms)
std dev              20.57 ms   (9.365 ms .. 32.12 ms)
variance introduced by outliers: 31% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x1
time                 1.101 ms   (1.091 ms .. 1.116 ms)
                     0.999 R²   (0.997 R² .. 1.000 R²)
mean                 1.101 ms   (1.093 ms .. 1.114 ms)
std dev              34.19 μs   (24.45 μs .. 53.26 μs)
variance introduced by outliers: 19% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x10
time                 19.13 ms   (18.45 ms .. 19.91 ms)
                     0.995 R²   (0.992 R² .. 0.999 R²)
mean                 18.09 ms   (17.71 ms .. 18.46 ms)
std dev              870.8 μs   (622.8 μs .. 1.206 ms)
variance introduced by outliers: 17% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x100
time                 1.140 s    (723.1 ms .. 1.522 s)
                     0.976 R²   (0.973 R² .. 1.000 R²)
mean                 1.093 s    (939.5 ms .. 1.197 s)
std dev              145.3 ms   (8.205 ms .. 181.4 ms)
variance introduced by outliers: 24% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/20x10
time                 43.58 ms   (42.79 ms .. 44.56 ms)
                     0.998 R²   (0.996 R² .. 1.000 R²)
mean                 43.98 ms   (43.34 ms .. 44.86 ms)
std dev              1.531 ms   (964.5 μs .. 2.408 ms)

benchmarking mkPersist/Nullable/Increasing model count/40x10
time                 89.01 ms   (85.38 ms .. 91.83 ms)
                     0.997 R²   (0.993 R² .. 0.999 R²)
mean                 87.92 ms   (81.29 ms .. 91.09 ms)
std dev              7.472 ms   (3.033 ms .. 12.94 ms)
variance introduced by outliers: 28% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/60x10
time                 116.4 ms   (105.6 ms .. 123.7 ms)
                     0.994 R²   (0.986 R² .. 0.999 R²)
mean                 126.8 ms   (121.4 ms .. 133.0 ms)
std dev              8.540 ms   (5.824 ms .. 11.83 ms)
variance introduced by outliers: 12% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/80x10
time                 197.2 ms   (164.6 ms .. 232.6 ms)
                     0.988 R²   (0.958 R² .. 1.000 R²)
mean                 189.6 ms   (176.6 ms .. 201.4 ms)
std dev              17.32 ms   (9.377 ms .. 25.86 ms)
variance introduced by outliers: 16% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/100x10
time                 262.8 ms   (225.6 ms .. 281.7 ms)
                     0.990 R²   (0.970 R² .. 1.000 R²)
mean                 248.4 ms   (234.2 ms .. 258.1 ms)
std dev              15.63 ms   (10.30 ms .. 19.52 ms)
variance introduced by outliers: 17% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x20
time                 90.77 ms   (81.84 ms .. 101.5 ms)
                     0.974 R²   (0.932 R² .. 0.997 R²)
mean                 73.75 ms   (66.31 ms .. 80.22 ms)
std dev              11.92 ms   (8.285 ms .. 18.59 ms)
variance introduced by outliers: 58% (severely inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x40
time                 258.2 ms   (202.5 ms .. 316.8 ms)
                     0.988 R²   (0.968 R² .. 1.000 R²)
mean                 235.6 ms   (193.4 ms .. 253.5 ms)
std dev              33.43 ms   (10.60 ms .. 49.19 ms)
variance introduced by outliers: 38% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x60
time                 542.3 ms   (431.4 ms .. 591.7 ms)
                     0.995 R²   (0.988 R² .. 1.000 R²)
mean                 528.9 ms   (499.9 ms .. 545.4 ms)
std dev              28.15 ms   (9.013 ms .. 37.98 ms)
variance introduced by outliers: 19% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x80
time                 908.0 ms   (814.3 ms .. 1.091 s)
                     0.995 R²   (0.990 R² .. 1.000 R²)
mean                 838.9 ms   (751.9 ms .. 886.1 ms)
std dev              85.02 ms   (3.280 ms .. 108.9 ms)
variance introduced by outliers: 23% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x100
time                 1.621 s    (1.129 s .. 1.879 s)
                     0.990 R²   (0.970 R² .. 1.000 R²)
mean                 1.405 s    (1.197 s .. 1.523 s)
std dev              202.9 ms   (57.30 ms .. 273.0 ms)
variance introduced by outliers: 24% (moderately inflated)
```

vs this branch:

```
benchmarking mkPersist/From File
time                 621.8 μs   (612.2 μs .. 633.9 μs)
                     0.996 R²   (0.994 R² .. 0.998 R²)
mean                 668.6 μs   (656.5 μs .. 683.9 μs)
std dev              46.55 μs   (37.19 μs .. 67.34 μs)
variance introduced by outliers: 59% (severely inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/1x10
time                 4.577 ms   (4.409 ms .. 4.833 ms)
                     0.983 R²   (0.965 R² .. 0.996 R²)
mean                 4.610 ms   (4.512 ms .. 4.726 ms)
std dev              324.7 μs   (239.5 μs .. 460.0 μs)
variance introduced by outliers: 44% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/10x10
time                 4.479 ms   (4.348 ms .. 4.628 ms)
                     0.994 R²   (0.991 R² .. 0.997 R²)
mean                 4.717 ms   (4.647 ms .. 4.768 ms)
std dev              188.8 μs   (143.7 μs .. 235.5 μs)
variance introduced by outliers: 20% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/100x10
time                 55.67 ms   (53.85 ms .. 57.68 ms)
                     0.995 R²   (0.986 R² .. 0.999 R²)
mean                 55.03 ms   (51.81 ms .. 56.67 ms)
std dev              4.023 ms   (2.152 ms .. 6.421 ms)
variance introduced by outliers: 23% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x1
time                 885.4 μs   (873.7 μs .. 898.4 μs)
                     0.998 R²   (0.997 R² .. 0.999 R²)
mean                 909.3 μs   (899.6 μs .. 923.9 μs)
std dev              40.42 μs   (29.71 μs .. 61.27 μs)
variance introduced by outliers: 36% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x10
time                 4.669 ms   (4.463 ms .. 4.850 ms)
                     0.991 R²   (0.985 R² .. 0.995 R²)
mean                 4.673 ms   (4.590 ms .. 4.754 ms)
std dev              264.4 μs   (226.1 μs .. 318.1 μs)
variance introduced by outliers: 34% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x100
time                 43.01 ms   (41.66 ms .. 44.14 ms)
                     0.997 R²   (0.992 R² .. 0.999 R²)
mean                 42.88 ms   (40.65 ms .. 44.22 ms)
std dev              3.305 ms   (1.574 ms .. 5.780 ms)
variance introduced by outliers: 27% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/20x10
time                 11.38 ms   (11.18 ms .. 11.68 ms)
                     0.995 R²   (0.985 R² .. 0.999 R²)
mean                 11.16 ms   (10.97 ms .. 11.41 ms)
std dev              603.2 μs   (391.3 μs .. 912.9 μs)
variance introduced by outliers: 26% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/40x10
time                 24.00 ms   (23.56 ms .. 24.38 ms)
                     0.999 R²   (0.997 R² .. 0.999 R²)
mean                 23.97 ms   (23.74 ms .. 24.24 ms)
std dev              538.8 μs   (409.6 μs .. 720.3 μs)

benchmarking mkPersist/Nullable/Increasing model count/60x10
time                 39.98 ms   (37.68 ms .. 43.16 ms)
                     0.988 R²   (0.976 R² .. 0.999 R²)
mean                 36.94 ms   (36.04 ms .. 38.32 ms)
std dev              2.173 ms   (1.135 ms .. 3.656 ms)
variance introduced by outliers: 19% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/80x10
time                 51.12 ms   (44.79 ms .. 57.38 ms)
                     0.969 R²   (0.915 R² .. 0.998 R²)
mean                 56.90 ms   (53.41 ms .. 60.70 ms)
std dev              6.589 ms   (4.712 ms .. 8.849 ms)
variance introduced by outliers: 40% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/100x10
time                 60.83 ms   (55.87 ms .. 65.23 ms)
                     0.991 R²   (0.983 R² .. 0.999 R²)
mean                 63.33 ms   (59.62 ms .. 65.63 ms)
std dev              5.272 ms   (2.846 ms .. 8.609 ms)
variance introduced by outliers: 24% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x20
time                 9.925 ms   (9.701 ms .. 10.16 ms)
                     0.995 R²   (0.991 R² .. 0.998 R²)
mean                 10.15 ms   (9.972 ms .. 10.31 ms)
std dev              460.9 μs   (371.1 μs .. 571.1 μs)
variance introduced by outliers: 19% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x40
time                 19.03 ms   (18.30 ms .. 19.67 ms)
                     0.994 R²   (0.988 R² .. 0.997 R²)
mean                 20.77 ms   (19.98 ms .. 22.18 ms)
std dev              2.346 ms   (1.350 ms .. 3.393 ms)
variance introduced by outliers: 51% (severely inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x60
time                 29.54 ms   (28.63 ms .. 30.63 ms)
                     0.996 R²   (0.993 R² .. 0.998 R²)
mean                 29.85 ms   (29.35 ms .. 30.35 ms)
std dev              1.064 ms   (835.8 μs .. 1.455 ms)
variance introduced by outliers: 11% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x80
time                 39.68 ms   (38.06 ms .. 41.69 ms)
                     0.993 R²   (0.985 R² .. 0.998 R²)
mean                 39.61 ms   (37.67 ms .. 40.74 ms)
std dev              3.070 ms   (1.579 ms .. 5.208 ms)
variance introduced by outliers: 25% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x100
time                 48.92 ms   (46.41 ms .. 50.57 ms)
                     0.996 R²   (0.993 R² .. 0.998 R²)
mean                 49.09 ms   (46.21 ms .. 50.95 ms)
std dev              4.472 ms   (2.372 ms .. 8.241 ms)
variance introduced by outliers: 29% (moderately inflated)
```

Co-authored-by: Matt Parsons <parsonsmatt@gmail.com>
merijn pushed a commit to merijn/persistent that referenced this pull request Jan 6, 2020
* persistent-tempalte: Use StandaloneDeriving and DerivingStrategies

This PR uses StandaloneDeriving to avoid the handwritten instances that currently exist in persistent-template.

In addition, it uses deriving strategies to specify that GeneralizedNewtypeDeriving should be used to derive the instances. This fixes the long-standing issue that derivation would fail if DeriveAnyClass was enabled

* Closes yesodweb#578
* Closes yesodweb#738
* Closes yesodweb#908

* ..

* ..

* ..

* ..

* ..

* ..

* test fixes

* test fixes

* ..

* Update persistent-template/ChangeLog.md

Co-Authored-By: Matt Parsons <parsonsmatt@gmail.com>

* Update persistent-template/persistent-template.cabal

Co-Authored-By: Matt Parsons <parsonsmatt@gmail.com>

* Reduce code generated by fromPersistValues

(NB: this code is based on yesodweb#1002. Will rebase once that's merged)

Currently this function is embedding the full `EntityDef` for every field of the entity. So, for a model with 20 fields, the code to parse a _single field_ embeds the definition of _all 20_ of those fields. This change fixes that.

Using the models in persistent-template/test/main.hs as an example, the old generated code to parse _a single field_ looks like this:

```
      fromPersistValues [x1_asSh, x2_asSi, x3_asSj, x4_asSk]
        = Person
            <$>
              (Database.Persist.TH.mapLeft
                 ((Database.Persist.TH.fieldError
                     (((((((((((EntityDef (HaskellName (pack "Person")))
                                 (DBName (pack "Person")))
                                ((((((((FieldDef (HaskellName (pack "Id"))) (DBName (pack "id")))
                                        ((FTTypeCon Nothing) (pack "PersonId")))
                                       SqlInt64)
                                      [])
                                     True)
                                    ((ForeignRef (HaskellName (pack "Person")))
                                       ((FTTypeCon (Just (pack "Data.Int"))) (pack "Int64"))))
                                   Nothing))
                               [pack "json"])
                              [(((((((FieldDef (HaskellName (pack "name")))
                                       (DBName (pack "name")))
                                      ((FTTypeCon Nothing) (pack "Text")))
                                     SqlString)
                                    [])
                                   True)
                                  NoReference)
                                 Nothing,
                               (((((((FieldDef (HaskellName (pack "age"))) (DBName (pack "age")))
                                      ((FTTypeCon Nothing) (pack "Int")))
                                     SqlInt64)
                                    [pack "Maybe"])
                                   True)
                                  NoReference)
                                 Nothing,
                               (((((((FieldDef (HaskellName (pack "foo"))) (DBName (pack "foo")))
                                      ((FTTypeCon Nothing) (pack "Foo")))
                                     SqlString)
                                    [])
                                   True)
                                  NoReference)
                                 Nothing,
                               (((((((FieldDef (HaskellName (pack "address")))
                                       (DBName (pack "address")))
                                      ((FTTypeCon Nothing) (pack "Address")))
                                     SqlString)
                                    [])
                                   True)
                                  (EmbedRef
                                     ((EmbedEntityDef (HaskellName (pack "Address")))
                                        [((EmbedFieldDef (DBName (pack "street"))) Nothing) Nothing,
                                         ((EmbedFieldDef (DBName (pack "city"))) Nothing) Nothing,
                                         ((EmbedFieldDef (DBName (pack "zip"))) Nothing) Nothing])))
                                 Nothing])
                             [])
                            [])
                           [pack "Show", pack "Eq"])
                          (containers-0.6.0.1:Data.Map.Internal.fromList []))
                         False)
                        Nothing))
                    ((((((((FieldDef (HaskellName (pack "name")))
                             (DBName (pack "name")))
                            ((FTTypeCon Nothing) (pack "Text")))
                           SqlString)
                          [])
                         True)
                        NoReference)
                       Nothing))
                 . fromPersistValue)
                x1_asSh
```

the new code to parse a single field looks like this:

```
      fromPersistValues [x1_asKP, x2_asKQ, x3_asKR, x4_asKS]
        = Person
            <$>
              (Database.Persist.TH.mapLeft
                 ((Database.Persist.TH.fieldError (pack "Person")) (pack "name"))
                 . fromPersistValue)
                x1_asKP
```

The generated code goes from 2560 to 1848 lines.

(The definition of those models for reference)

```
share [mkPersist sqlSettings { mpsGeneric = False }, mkDeleteCascade sqlSettings { mpsGeneric = False }] [persistUpperCase|
Person json
    name Text
    age Int Maybe
    foo Foo
    address Address
    deriving Show Eq
Address json
    street Text
    city Text
    zip Int Maybe
    deriving Show Eq
NoJson
    foo Text
    deriving Show Eq
|]

share [mkPersist sqlSettings { mpsGeneric = False, mpsGenerateLenses = True }] [persistLowerCase|
Lperson json
    name Text
    age Int Maybe
    address Laddress
    deriving Show Eq
Laddress json
    street Text
    city Text
    zip Int Maybe
    deriving Show Eq
|]
```

<hr>

Benchmarks show a radical improvement. This is master (+ the previous DerivingVia PR):

```
benchmarking mkPersist/From File
time                 11.75 ms   (11.13 ms .. 12.16 ms)
                     0.982 R²   (0.958 R² .. 0.997 R²)
mean                 12.87 ms   (12.49 ms .. 13.67 ms)
std dev              1.394 ms   (918.6 μs .. 2.229 ms)
variance introduced by outliers: 54% (severely inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/1x10
time                 18.31 ms   (17.98 ms .. 18.71 ms)
                     0.997 R²   (0.994 R² .. 0.999 R²)
mean                 18.59 ms   (18.34 ms .. 18.91 ms)
std dev              713.4 μs   (526.8 μs .. 955.5 μs)
variance introduced by outliers: 13% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/10x10
time                 18.21 ms   (17.94 ms .. 18.49 ms)
                     0.999 R²   (0.998 R² .. 1.000 R²)
mean                 18.42 ms   (18.26 ms .. 18.68 ms)
std dev              485.9 μs   (288.8 μs .. 838.4 μs)

benchmarking mkPersist/Non-Null Fields/Increasing model count/100x10
time                 186.2 ms   (159.5 ms .. 211.6 ms)
                     0.988 R²   (0.972 R² .. 1.000 R²)
mean                 186.3 ms   (167.4 ms .. 197.6 ms)
std dev              20.57 ms   (9.365 ms .. 32.12 ms)
variance introduced by outliers: 31% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x1
time                 1.101 ms   (1.091 ms .. 1.116 ms)
                     0.999 R²   (0.997 R² .. 1.000 R²)
mean                 1.101 ms   (1.093 ms .. 1.114 ms)
std dev              34.19 μs   (24.45 μs .. 53.26 μs)
variance introduced by outliers: 19% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x10
time                 19.13 ms   (18.45 ms .. 19.91 ms)
                     0.995 R²   (0.992 R² .. 0.999 R²)
mean                 18.09 ms   (17.71 ms .. 18.46 ms)
std dev              870.8 μs   (622.8 μs .. 1.206 ms)
variance introduced by outliers: 17% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x100
time                 1.140 s    (723.1 ms .. 1.522 s)
                     0.976 R²   (0.973 R² .. 1.000 R²)
mean                 1.093 s    (939.5 ms .. 1.197 s)
std dev              145.3 ms   (8.205 ms .. 181.4 ms)
variance introduced by outliers: 24% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/20x10
time                 43.58 ms   (42.79 ms .. 44.56 ms)
                     0.998 R²   (0.996 R² .. 1.000 R²)
mean                 43.98 ms   (43.34 ms .. 44.86 ms)
std dev              1.531 ms   (964.5 μs .. 2.408 ms)

benchmarking mkPersist/Nullable/Increasing model count/40x10
time                 89.01 ms   (85.38 ms .. 91.83 ms)
                     0.997 R²   (0.993 R² .. 0.999 R²)
mean                 87.92 ms   (81.29 ms .. 91.09 ms)
std dev              7.472 ms   (3.033 ms .. 12.94 ms)
variance introduced by outliers: 28% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/60x10
time                 116.4 ms   (105.6 ms .. 123.7 ms)
                     0.994 R²   (0.986 R² .. 0.999 R²)
mean                 126.8 ms   (121.4 ms .. 133.0 ms)
std dev              8.540 ms   (5.824 ms .. 11.83 ms)
variance introduced by outliers: 12% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/80x10
time                 197.2 ms   (164.6 ms .. 232.6 ms)
                     0.988 R²   (0.958 R² .. 1.000 R²)
mean                 189.6 ms   (176.6 ms .. 201.4 ms)
std dev              17.32 ms   (9.377 ms .. 25.86 ms)
variance introduced by outliers: 16% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/100x10
time                 262.8 ms   (225.6 ms .. 281.7 ms)
                     0.990 R²   (0.970 R² .. 1.000 R²)
mean                 248.4 ms   (234.2 ms .. 258.1 ms)
std dev              15.63 ms   (10.30 ms .. 19.52 ms)
variance introduced by outliers: 17% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x20
time                 90.77 ms   (81.84 ms .. 101.5 ms)
                     0.974 R²   (0.932 R² .. 0.997 R²)
mean                 73.75 ms   (66.31 ms .. 80.22 ms)
std dev              11.92 ms   (8.285 ms .. 18.59 ms)
variance introduced by outliers: 58% (severely inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x40
time                 258.2 ms   (202.5 ms .. 316.8 ms)
                     0.988 R²   (0.968 R² .. 1.000 R²)
mean                 235.6 ms   (193.4 ms .. 253.5 ms)
std dev              33.43 ms   (10.60 ms .. 49.19 ms)
variance introduced by outliers: 38% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x60
time                 542.3 ms   (431.4 ms .. 591.7 ms)
                     0.995 R²   (0.988 R² .. 1.000 R²)
mean                 528.9 ms   (499.9 ms .. 545.4 ms)
std dev              28.15 ms   (9.013 ms .. 37.98 ms)
variance introduced by outliers: 19% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x80
time                 908.0 ms   (814.3 ms .. 1.091 s)
                     0.995 R²   (0.990 R² .. 1.000 R²)
mean                 838.9 ms   (751.9 ms .. 886.1 ms)
std dev              85.02 ms   (3.280 ms .. 108.9 ms)
variance introduced by outliers: 23% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x100
time                 1.621 s    (1.129 s .. 1.879 s)
                     0.990 R²   (0.970 R² .. 1.000 R²)
mean                 1.405 s    (1.197 s .. 1.523 s)
std dev              202.9 ms   (57.30 ms .. 273.0 ms)
variance introduced by outliers: 24% (moderately inflated)
```

vs this branch:

```
benchmarking mkPersist/From File
time                 621.8 μs   (612.2 μs .. 633.9 μs)
                     0.996 R²   (0.994 R² .. 0.998 R²)
mean                 668.6 μs   (656.5 μs .. 683.9 μs)
std dev              46.55 μs   (37.19 μs .. 67.34 μs)
variance introduced by outliers: 59% (severely inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/1x10
time                 4.577 ms   (4.409 ms .. 4.833 ms)
                     0.983 R²   (0.965 R² .. 0.996 R²)
mean                 4.610 ms   (4.512 ms .. 4.726 ms)
std dev              324.7 μs   (239.5 μs .. 460.0 μs)
variance introduced by outliers: 44% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/10x10
time                 4.479 ms   (4.348 ms .. 4.628 ms)
                     0.994 R²   (0.991 R² .. 0.997 R²)
mean                 4.717 ms   (4.647 ms .. 4.768 ms)
std dev              188.8 μs   (143.7 μs .. 235.5 μs)
variance introduced by outliers: 20% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing model count/100x10
time                 55.67 ms   (53.85 ms .. 57.68 ms)
                     0.995 R²   (0.986 R² .. 0.999 R²)
mean                 55.03 ms   (51.81 ms .. 56.67 ms)
std dev              4.023 ms   (2.152 ms .. 6.421 ms)
variance introduced by outliers: 23% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x1
time                 885.4 μs   (873.7 μs .. 898.4 μs)
                     0.998 R²   (0.997 R² .. 0.999 R²)
mean                 909.3 μs   (899.6 μs .. 923.9 μs)
std dev              40.42 μs   (29.71 μs .. 61.27 μs)
variance introduced by outliers: 36% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x10
time                 4.669 ms   (4.463 ms .. 4.850 ms)
                     0.991 R²   (0.985 R² .. 0.995 R²)
mean                 4.673 ms   (4.590 ms .. 4.754 ms)
std dev              264.4 μs   (226.1 μs .. 318.1 μs)
variance introduced by outliers: 34% (moderately inflated)

benchmarking mkPersist/Non-Null Fields/Increasing field count/10x100
time                 43.01 ms   (41.66 ms .. 44.14 ms)
                     0.997 R²   (0.992 R² .. 0.999 R²)
mean                 42.88 ms   (40.65 ms .. 44.22 ms)
std dev              3.305 ms   (1.574 ms .. 5.780 ms)
variance introduced by outliers: 27% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/20x10
time                 11.38 ms   (11.18 ms .. 11.68 ms)
                     0.995 R²   (0.985 R² .. 0.999 R²)
mean                 11.16 ms   (10.97 ms .. 11.41 ms)
std dev              603.2 μs   (391.3 μs .. 912.9 μs)
variance introduced by outliers: 26% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/40x10
time                 24.00 ms   (23.56 ms .. 24.38 ms)
                     0.999 R²   (0.997 R² .. 0.999 R²)
mean                 23.97 ms   (23.74 ms .. 24.24 ms)
std dev              538.8 μs   (409.6 μs .. 720.3 μs)

benchmarking mkPersist/Nullable/Increasing model count/60x10
time                 39.98 ms   (37.68 ms .. 43.16 ms)
                     0.988 R²   (0.976 R² .. 0.999 R²)
mean                 36.94 ms   (36.04 ms .. 38.32 ms)
std dev              2.173 ms   (1.135 ms .. 3.656 ms)
variance introduced by outliers: 19% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/80x10
time                 51.12 ms   (44.79 ms .. 57.38 ms)
                     0.969 R²   (0.915 R² .. 0.998 R²)
mean                 56.90 ms   (53.41 ms .. 60.70 ms)
std dev              6.589 ms   (4.712 ms .. 8.849 ms)
variance introduced by outliers: 40% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing model count/100x10
time                 60.83 ms   (55.87 ms .. 65.23 ms)
                     0.991 R²   (0.983 R² .. 0.999 R²)
mean                 63.33 ms   (59.62 ms .. 65.63 ms)
std dev              5.272 ms   (2.846 ms .. 8.609 ms)
variance introduced by outliers: 24% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x20
time                 9.925 ms   (9.701 ms .. 10.16 ms)
                     0.995 R²   (0.991 R² .. 0.998 R²)
mean                 10.15 ms   (9.972 ms .. 10.31 ms)
std dev              460.9 μs   (371.1 μs .. 571.1 μs)
variance introduced by outliers: 19% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x40
time                 19.03 ms   (18.30 ms .. 19.67 ms)
                     0.994 R²   (0.988 R² .. 0.997 R²)
mean                 20.77 ms   (19.98 ms .. 22.18 ms)
std dev              2.346 ms   (1.350 ms .. 3.393 ms)
variance introduced by outliers: 51% (severely inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x60
time                 29.54 ms   (28.63 ms .. 30.63 ms)
                     0.996 R²   (0.993 R² .. 0.998 R²)
mean                 29.85 ms   (29.35 ms .. 30.35 ms)
std dev              1.064 ms   (835.8 μs .. 1.455 ms)
variance introduced by outliers: 11% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x80
time                 39.68 ms   (38.06 ms .. 41.69 ms)
                     0.993 R²   (0.985 R² .. 0.998 R²)
mean                 39.61 ms   (37.67 ms .. 40.74 ms)
std dev              3.070 ms   (1.579 ms .. 5.208 ms)
variance introduced by outliers: 25% (moderately inflated)

benchmarking mkPersist/Nullable/Increasing field count/10x100
time                 48.92 ms   (46.41 ms .. 50.57 ms)
                     0.996 R²   (0.993 R² .. 0.998 R²)
mean                 49.09 ms   (46.21 ms .. 50.95 ms)
std dev              4.472 ms   (2.372 ms .. 8.241 ms)
variance introduced by outliers: 29% (moderately inflated)
```

Co-authored-by: Matt Parsons <parsonsmatt@gmail.com>
@parsonsmatt parsonsmatt deleted the standaloneDerivingStrategies2 branch March 31, 2020 15:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants