Skip to content

Commit

Permalink
Support discriminated union components being referenced from other pl…
Browse files Browse the repository at this point in the history
…aces

This adds and exposes `objSchema`s so that discriminated tagged unions and normal
objects can both refer to the same component.
  • Loading branch information
OwenGraves committed Aug 6, 2024
1 parent 18a5356 commit 21c4214
Show file tree
Hide file tree
Showing 15 changed files with 106 additions and 46 deletions.
2 changes: 1 addition & 1 deletion json-fleece-codegen-util/json-fleece-codegen-util.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack

name: json-fleece-codegen-util
version: 0.9.1.1
version: 0.10.0.0
description: Please see the README on GitHub at <https://github.com/githubuser/json-fleece-codegen-util#readme>
homepage: https://github.com/flipstone/json-fleece#readme
bug-reports: https://github.com/flipstone/json-fleece/issues
Expand Down
3 changes: 1 addition & 2 deletions json-fleece-codegen-util/package.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: json-fleece-codegen-util
version: 0.9.1.1
version: 0.10.0.0
github: "flipstone/json-fleece/json-fleece-codegen-util"
license: BSD3
author: "Author name here"
Expand Down Expand Up @@ -71,4 +71,3 @@ library:
- Fleece.CodeGenUtil.HaskellCode
- Fleece.CodeGenUtil.Executable
- Fleece.CodeGenUtil.Test

68 changes: 42 additions & 26 deletions json-fleece-codegen-util/src/Fleece/CodeGenUtil.hs
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,7 @@ anyJSONSchemaTypeInfo =
SchemaTypeInfo
{ schemaTypeExpr = HC.typeNameToCodeDefaultQualification (fleeceCoreType "AnyJSON")
, schemaTypeSchema = fleeceCoreVar "anyJSON"
, schemaTypeObjSchema = fleeceCoreVar "anyJSON"
}

generateFleeceCode :: CodeGenMap -> CodeGen Modules
Expand Down Expand Up @@ -1558,7 +1559,7 @@ generateFleeceTaggedUnion typeMap typeName tagProperty members = do
<> " "
<> HC.typeApplication (HC.stringLiteral tag)
<> " "
<> schemaTypeSchema typeInfo
<> schemaTypeObjSchema typeInfo

taggedUnionMemberLines =
map taggedUnionMemberLine taggedTypeInfos
Expand Down Expand Up @@ -1616,12 +1617,13 @@ determineDiscriminatorPropertyForObject refSet =
UnionMemberSource -> Nothing
TaggedUnionMemberSource property -> Just property
in
case Set.toList (Set.map toDiscriminator refSet) of
case catMaybes $ Set.toList (Set.map toDiscriminator refSet) of
[] -> pure Nothing
[oneDiscriminator] -> pure oneDiscriminator
[oneDiscriminator] -> pure $ Just oneDiscriminator
multiple ->
-- This limitation could probably be lifted with some additional care
codeGenError $
"Objects referenced from tagged unions must have consistent discriminator properties and cannot be referenced outside the union."
"Objects referenced from tagged unions must have consistent discriminator properties."
<> " Found the following discriminator properties: "
<> show multiple

Expand Down Expand Up @@ -1707,30 +1709,38 @@ generateFleeceObject typeMap references typeName rawCodeGenFields mbAdditionalPr
fleeceFields =
map fleeceField fields ++ fleeceAdditionalProps

fleeceSchema =
fleeceSchemas =
case mbDiscriminator of
Nothing ->
fleeceSchemaForType
typeName
( fleeceCoreVar "object" <> " " <> HC.dollar
: " " <> fleeceCoreVar "constructor" <> " " <> HC.typeNameToCode Nothing typeName
: map (HC.indent 4) fleeceFields
)
[ fleeceSchemaForType
typeName
( fleeceCoreVar "object" <> " " <> HC.dollar
: " " <> fleeceCoreVar "constructor" <> " " <> HC.typeNameToCode Nothing typeName
: map (HC.indent 4) fleeceFields
)
]
Just _ ->
fleeceObjectForType
typeName
( fleeceCoreVar "constructor" <> " " <> HC.typeNameToCode Nothing typeName
: map (HC.indent 2) fleeceFields
)
[ fleeceSchemaForType
typeName
[fleeceCoreVar "object" <> " " <> HC.varNameToCode Nothing (fleeceObjSchemaNameForType typeName)]
, fleeceObjectForType
typeName
( fleeceCoreVar "constructor" <> " " <> HC.typeNameToCode Nothing typeName
: map (HC.indent 2) fleeceFields
)
]

extraExports =
[]
case mbDiscriminator of
Nothing -> []
Just _ ->
[fleeceObjSchemaNameForType typeName]

body =
HC.declarations
HC.declarations $
[ recordDecl
, fleeceSchema
]
<> fleeceSchemas

pure (extraExports, body)

Expand Down Expand Up @@ -1814,25 +1824,24 @@ mkFleeceSchemaField typeMap moduleName codeGenField = do
data SchemaTypeInfo = SchemaTypeInfo
{ schemaTypeExpr :: HC.TypeExpression
, schemaTypeSchema :: HC.HaskellCode
, schemaTypeObjSchema :: HC.HaskellCode
}

primitiveSchemaTypeInfo :: HC.TypeName -> HC.HaskellCode -> SchemaTypeInfo
primitiveSchemaTypeInfo typeName schema =
SchemaTypeInfo
{ schemaTypeExpr = HC.typeNameToCodeDefaultQualification typeName
, schemaTypeSchema = schema
, schemaTypeObjSchema = schema
}

inferSchemaInfoForTypeName :: HC.TypeName -> CodeGen SchemaTypeInfo
inferSchemaInfoForTypeName typeName = do
let
schema =
fleeceSchemaNameForType typeName

inferSchemaInfoForTypeName typeName =
pure $
SchemaTypeInfo
{ schemaTypeExpr = HC.typeNameToCodeDefaultQualification typeName
, schemaTypeSchema = HC.varNameToCodeDefaultQualification schema
, schemaTypeSchema = HC.varNameToCodeDefaultQualification $ fleeceSchemaNameForType typeName
, schemaTypeObjSchema = HC.varNameToCodeDefaultQualification $ fleeceObjSchemaNameForType typeName
}

inferTypeForInputName :: CodeSection -> T.Text -> CodeGen (HC.ModuleName, HC.TypeName)
Expand All @@ -1853,6 +1862,13 @@ fleeceSchemaNameForType typeName =
(HC.typeNameSuggestedQualifier typeName)
(HC.typeNameText typeName <> "Schema")

fleeceObjSchemaNameForType :: HC.TypeName -> HC.VarName
fleeceObjSchemaNameForType typeName =
HC.toVarName
(HC.typeNameModule typeName)
(HC.typeNameSuggestedQualifier typeName)
(HC.typeNameText typeName <> "ObjSchema")

fleeceSchemaForType :: HC.TypeName -> [HC.HaskellCode] -> HC.HaskellCode
fleeceSchemaForType typeName bodyLines =
let
Expand All @@ -1878,7 +1894,7 @@ fleeceObjectForType :: HC.TypeName -> [HC.HaskellCode] -> HC.HaskellCode
fleeceObjectForType typeName bodyLines =
let
schemaName =
fleeceSchemaNameForType typeName
fleeceObjSchemaNameForType typeName

declType =
HC.typeAnnotate schemaName $
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module TestCases.Types.Bar
( Bar(..)
, barSchema
, barObjSchema
) where

import Fleece.Core ((#+), Object)
Expand All @@ -15,7 +16,11 @@ data Bar = Bar
}
deriving (Eq, Show)

barSchema :: FC.Fleece schema => Object schema Bar Bar
barSchema :: FC.Fleece schema => schema Bar
barSchema =
FC.object barObjSchema

barObjSchema :: FC.Fleece schema => Object schema Bar Bar
barObjSchema =
FC.constructor Bar
#+ FC.optional "barName" barName BarName.barNameSchema
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module TestCases.Types.Baz
( Baz(..)
, bazSchema
, bazObjSchema
) where

import Fleece.Core ((#+), Object)
Expand All @@ -15,7 +16,11 @@ data Baz = Baz
}
deriving (Eq, Show)

bazSchema :: FC.Fleece schema => Object schema Baz Baz
bazSchema :: FC.Fleece schema => schema Baz
bazSchema =
FC.object bazObjSchema

bazObjSchema :: FC.Fleece schema => Object schema Baz Baz
bazObjSchema =
FC.constructor Baz
#+ FC.optional "bazName" bazName BazName.bazNameSchema
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module TestCases.Types.Foo
( Foo(..)
, fooSchema
, fooObjSchema
) where

import Fleece.Core (Object)
Expand All @@ -12,6 +13,10 @@ import Prelude (Eq, Show)
data Foo = Foo
deriving (Eq, Show)

fooSchema :: FC.Fleece schema => Object schema Foo Foo
fooSchema :: FC.Fleece schema => schema Foo
fooSchema =
FC.object fooObjSchema

fooObjSchema :: FC.Fleece schema => Object schema Foo Foo
fooObjSchema =
FC.constructor Foo
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{-# LANGUAGE NoImplicitPrelude #-}

module TestCases.Types.ObjectWithDiscriminatedUnionRef
( ObjectWithDiscriminatedUnionRef(..)
, objectWithDiscriminatedUnionRefSchema
) where

import Fleece.Core ((#+))
import qualified Fleece.Core as FC
import Prelude (($), Eq, Maybe, Show)
import qualified TestCases.Types.Baz as Baz

data ObjectWithDiscriminatedUnionRef = ObjectWithDiscriminatedUnionRef
{ bazRef :: Maybe Baz.Baz
}
deriving (Eq, Show)

objectWithDiscriminatedUnionRefSchema :: FC.Fleece schema => schema ObjectWithDiscriminatedUnionRef
objectWithDiscriminatedUnionRefSchema =
FC.object $
FC.constructor ObjectWithDiscriminatedUnionRef
#+ FC.optional "bazRef" bazRef Baz.bazSchema
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ oneOfWithDiscriminatorSchema :: FC.Fleece schema => schema OneOfWithDiscriminato
oneOfWithDiscriminatorSchema =
FC.coerceSchema $
FC.taggedUnionNamed (FC.qualifiedName "TestCases.Types.OneOfWithDiscriminator" "OneOfWithDiscriminator") "type" $
FC.taggedUnionMember @"bar" Bar.barSchema
#@ FC.taggedUnionMember @"baz" Baz.bazSchema
#@ FC.taggedUnionMember @"foo" Foo.fooSchema
FC.taggedUnionMember @"bar" Bar.barObjSchema
#@ FC.taggedUnionMember @"baz" Baz.bazObjSchema
#@ FC.taggedUnionMember @"foo" Foo.fooObjSchema
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ oneOfWithDiscriminatorTypeObjectSchema :: FC.Fleece schema => schema OneOfWithDi
oneOfWithDiscriminatorTypeObjectSchema =
FC.coerceSchema $
FC.taggedUnionNamed (FC.qualifiedName "TestCases.Types.OneOfWithDiscriminatorTypeObject" "OneOfWithDiscriminatorTypeObject") "type" $
FC.taggedUnionMember @"bar" Bar.barSchema
#@ FC.taggedUnionMember @"baz" Baz.bazSchema
#@ FC.taggedUnionMember @"foo" Foo.fooSchema
FC.taggedUnionMember @"bar" Bar.barObjSchema
#@ FC.taggedUnionMember @"baz" Baz.bazObjSchema
#@ FC.taggedUnionMember @"foo" Foo.fooObjSchema
1 change: 1 addition & 0 deletions json-fleece-openapi3/examples/test-cases/test-cases.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ library
TestCases.Types.NameConflicts.Where
TestCases.Types.NullableBoolean
TestCases.Types.Num2SchemaStartingWithNumber
TestCases.Types.ObjectWithDiscriminatedUnionRef
TestCases.Types.OneOfWithDiscriminator
TestCases.Types.OneOfWithDiscriminatorTypeObject
TestCases.Types.OneOfWithNullable
Expand Down
6 changes: 6 additions & 0 deletions json-fleece-openapi3/examples/test-cases/test-cases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,12 @@ components:
bar: "#/components/schemas/Bar"
baz: "#/components/schemas/Baz"

ObjectWithDiscriminatedUnionRef:
type: object
properties:
bazRef:
$ref: "#/components/schemas/Baz"

Foo:
type: object
properties:
Expand Down
7 changes: 4 additions & 3 deletions json-fleece-openapi3/json-fleece-openapi3.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -2018,6 +2018,7 @@ extra-source-files:
examples/test-cases/TestCases/Types/NameConflicts/Where.hs
examples/test-cases/TestCases/Types/NullableBoolean.hs
examples/test-cases/TestCases/Types/Num2SchemaStartingWithNumber.hs
examples/test-cases/TestCases/Types/ObjectWithDiscriminatedUnionRef.hs
examples/test-cases/TestCases/Types/OneOfWithDiscriminator.hs
examples/test-cases/TestCases/Types/OneOfWithDiscriminatorTypeObject.hs
examples/test-cases/TestCases/Types/OneOfWithNullable.hs
Expand Down Expand Up @@ -2056,7 +2057,7 @@ library
, base >=4.7 && <5
, containers ==0.6.*
, insert-ordered-containers ==0.2.*
, json-fleece-codegen-util ==0.9.*
, json-fleece-codegen-util >=0.9 && <0.11
, mtl >=2.2 && <2.4
, non-empty-text ==0.2.*
, openapi3 ==3.2.*
Expand All @@ -2076,7 +2077,7 @@ executable fleece-openapi3
ghc-options: -rtsopts -threaded
build-depends:
base >=4.7 && <5
, json-fleece-codegen-util ==0.9.*
, json-fleece-codegen-util >=0.9 && <0.11
, json-fleece-openapi3
default-language: Haskell2010
if flag(strict)
Expand All @@ -2097,7 +2098,7 @@ test-suite json-fleece-openapi3-test
, bytestring ==0.11.*
, file-embed >=0.0.15 && <0.0.17
, hedgehog
, json-fleece-codegen-util ==0.9.*
, json-fleece-codegen-util >=0.9 && <0.11
, json-fleece-openapi3
, yaml ==0.11.*
default-language: Haskell2010
Expand Down
2 changes: 1 addition & 1 deletion json-fleece-openapi3/package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ when:

dependencies:
- base >= 4.7 && < 5
- json-fleece-codegen-util >= 0.9 && < 0.10
- json-fleece-codegen-util >= 0.9 && < 0.11

extra-source-files:
- examples/star-trek/codegen.dhall
Expand Down
6 changes: 3 additions & 3 deletions json-fleece-swagger2/json-fleece-swagger2.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ library
build-depends:
base >=4.7 && <5
, insert-ordered-containers ==0.2.*
, json-fleece-codegen-util >=0.6 && <0.10
, json-fleece-codegen-util >=0.6 && <0.11
, json-fleece-openapi3 ==0.4.*
, openapi3 ==3.2.*
, swagger2 ==2.8.*
Expand All @@ -105,7 +105,7 @@ executable fleece-swagger2
ghc-options: -rtsopts -threaded
build-depends:
base >=4.7 && <5
, json-fleece-codegen-util >=0.6 && <0.10
, json-fleece-codegen-util >=0.6 && <0.11
, json-fleece-swagger2
default-language: Haskell2010
if flag(strict)
Expand All @@ -127,7 +127,7 @@ test-suite json-fleece-swagger2-test
, bytestring ==0.11.*
, file-embed >=0.0.15 && <0.0.17
, hedgehog
, json-fleece-codegen-util >=0.6 && <0.10
, json-fleece-codegen-util >=0.6 && <0.11
, json-fleece-swagger2
default-language: Haskell2010
if flag(strict)
Expand Down
2 changes: 1 addition & 1 deletion json-fleece-swagger2/package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ description: Please see the README on GitHub at <https://github.com/gith

dependencies:
- base >= 4.7 && < 5
- json-fleece-codegen-util >= 0.6 && < 0.10
- json-fleece-codegen-util >= 0.6 && < 0.11

flags:
strict:
Expand Down

0 comments on commit 21c4214

Please sign in to comment.