-
Notifications
You must be signed in to change notification settings - Fork 6
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
Record fields list #117
base: master
Are you sure you want to change the base?
Record fields list #117
Changes from all commits
b96c747
2bc0614
66f0742
ec0124a
b5c9c94
48d9536
337c4e9
a0695d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -93,4 +93,8 @@ encodeOneType x = E.object | |
, ("guests", (E.list encodeGuest) x.guests) | ||
, ("userRequest", encodeUserRequest x.userRequest) | ||
, ("nonEmpty", (elmStreetEncodeNonEmpty encodeMyUnit) x.nonEmpty) | ||
, ("recordUnit", encodeRecordUnit x.recordUnit) | ||
] | ||
|
||
encodeRecordUnit : T.RecordUnit -> Value | ||
encodeRecordUnit x = list (\_ -> null) [] | ||
Comment on lines
+98
to
+100
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. decodeStrict @RecordUnit "[]"
Just RecordUnit |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -79,4 +79,5 @@ defaultOneType = | |
, example = Just (R.Ok Blocked) | ||
} | ||
, nonEmpty = (MyUnit (), [MyUnit ()]) | ||
, recordUnit = {} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -103,6 +103,7 @@ goldenOneTypeJson = | |
"tag": "MyUnit", | ||
"contents": [] | ||
} | ||
] | ||
], | ||
"recordUnit": [] | ||
} | ||
""" |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -163,7 +163,7 @@ __instance__ Elm (Id a) __where__ | |
elmNewtype :: forall a . Elm a => Text -> Text -> ElmDefinition | ||
elmNewtype typeName fieldName = DefRecord $ ElmRecord | ||
{ elmRecordName = typeName | ||
, elmRecordFields = ElmRecordField (elmRef @a) fieldName :| [] | ||
, elmRecordFields = ElmRecordField (elmRef @a) fieldName : [] | ||
, elmRecordIsNewtype = True | ||
} | ||
|
||
|
@@ -213,10 +213,14 @@ data GenericConstructor = GenericConstructor | |
2. All fields have names: record constructor. | ||
3. Not all fields have names: plain constructor. | ||
-} | ||
toElmConstructor :: GenericConstructor -> Either (NonEmpty ElmRecordField) ElmConstructor | ||
toElmConstructor :: GenericConstructor -> Either [ElmRecordField] ElmConstructor | ||
toElmConstructor GenericConstructor{..} = case genericConstructorFields of | ||
-- Even though elm supports records with no field {} we don't ever derive these | ||
-- Haskell records are in fact just type field accessors so there is ambiguity for zero fields constructors | ||
-- Usually it makes more sense to derive Single constructor type for the Elm side so that's what we do | ||
-- However it's possible to manually define instance of Elm class that would produce empty records (the other unit) type on Elm side | ||
Comment on lines
+218
to
+221
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Important comment |
||
[] -> Right $ ElmConstructor genericConstructorName [] | ||
f:fs -> case traverse toRecordField (f :| fs) of | ||
f:fs -> case traverse toRecordField (f : fs) of | ||
Nothing -> Right $ ElmConstructor genericConstructorName $ map fst genericConstructorFields | ||
Just fields -> Left fields | ||
where | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ import Elm.Ast (ElmConstructor (..), ElmDefinition (..), ElmPrim (..), ElmRecord | |
import Elm.Print.Common (arrow, mkQualified, qualifiedTypeWithVarsDoc, showDoc, wrapParens) | ||
|
||
import qualified Data.List.NonEmpty as NE | ||
import qualified Data.Maybe as Maybe | ||
import qualified Data.Text as T | ||
|
||
|
||
|
@@ -78,19 +79,31 @@ recordDecoderDoc :: ElmRecord -> Doc ann | |
recordDecoderDoc ElmRecord{..} = | ||
decoderDef elmRecordName [] | ||
<> line | ||
<> if elmRecordIsNewtype | ||
<> if isEmptyRecord | ||
then emptyRecordDecoder | ||
else if elmRecordIsNewtype | ||
Comment on lines
+82
to
+84
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not really excited about this. Any idea? |
||
then newtypeDecoder | ||
else recordDecoder | ||
where | ||
isEmptyRecord :: Bool | ||
isEmptyRecord = null elmRecordFields | ||
|
||
emptyRecordDecoder :: Doc ann | ||
emptyRecordDecoder = name <+> "D.succeed {}" | ||
|
||
newtypeDecoder :: Doc ann | ||
newtypeDecoder = name <+> "D.map" <+> qualifiedRecordName | ||
<+> wrapParens (typeRefDecoder $ elmRecordFieldType $ NE.head elmRecordFields) | ||
newtypeDecoder = | ||
case typeRefDecoder <$> elmRecordFieldType <$> Maybe.listToMaybe elmRecordFields of | ||
Just field -> | ||
name <+> "D.map" <+> qualifiedRecordName | ||
<+> wrapParens field | ||
Nothing -> emptyRecordDecoder | ||
|
||
recordDecoder :: Doc ann | ||
recordDecoder = nest 4 | ||
$ vsep | ||
$ (name <+> "D.succeed" <+> qualifiedRecordName) | ||
: map fieldDecode (toList elmRecordFields) | ||
: map fieldDecode elmRecordFields | ||
|
||
name :: Doc ann | ||
name = decoderName elmRecordName <+> equals | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,13 +27,14 @@ module Types | |
, UserRequest (..) | ||
) where | ||
|
||
import Data.Aeson (FromJSON (..), ToJSON (..), Value(..), object, (.=)) | ||
import Data.List.NonEmpty (NonEmpty(..)) | ||
import Data.Aeson (FromJSON (..), ToJSON (..), Value (..), object, (.=)) | ||
import Data.List.NonEmpty (NonEmpty (..)) | ||
import Data.Text (Text) | ||
import Data.Time.Calendar (fromGregorian) | ||
import Data.Time.Clock (UTCTime (..)) | ||
import Data.Word (Word32) | ||
import Elm (Elm (..), ElmStreet (..), elmNewtype, elmStreetParseJson, elmStreetToJson) | ||
import Elm (Elm (..), ElmDefinition (..), ElmRecord (..), ElmStreet (..), elmNewtype, | ||
elmStreetParseJson, elmStreetToJson) | ||
import GHC.Generics (Generic) | ||
|
||
|
||
|
@@ -45,7 +46,7 @@ data Prims = Prims | |
, primsFloat :: !Double | ||
, primsText :: !Text | ||
, primsTime :: !UTCTime | ||
, primsValue :: !Value | ||
, primsValue :: !Value | ||
, primsMaybe :: !(Maybe Word) | ||
, primsResult :: !(Either Int Text) | ||
, primsPair :: !(Char, Bool) | ||
|
@@ -150,12 +151,24 @@ instance FromJSON MyUnit where parseJSON = elmStreetParseJson | |
data MyResult | ||
= Ok | ||
| Err Text | ||
deriving (Generic, Eq, Show) | ||
deriving stock (Generic, Eq, Show) | ||
deriving anyclass (Elm) | ||
|
||
instance ToJSON MyResult where toJSON = elmStreetToJson | ||
instance FromJSON MyResult where parseJSON = elmStreetParseJson | ||
|
||
data RecordUnit = RecordUnit | ||
deriving stock (Generic, Eq, Show) | ||
deriving anyclass (FromJSON, ToJSON) | ||
|
||
instance Elm RecordUnit where | ||
toElmDefinition _ = DefRecord $ ElmRecord | ||
{ elmRecordName = "RecordUnit" | ||
, elmRecordFields = [] | ||
, elmRecordIsNewtype = False | ||
} | ||
|
||
Comment on lines
+160
to
+170
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. manual instance implementation of record with no fields. |
||
|
||
-- | All test types together in one type to play with. | ||
data OneType = OneType | ||
{ oneTypePrims :: !Prims | ||
|
@@ -171,6 +184,7 @@ data OneType = OneType | |
, oneTypeGuests :: ![Guest] | ||
, oneTypeUserRequest :: !UserRequest | ||
, oneTypeNonEmpty :: !(NonEmpty MyUnit) | ||
, oneTypeRecordUnit :: !RecordUnit | ||
} deriving (Generic, Eq, Show) | ||
deriving anyclass (Elm) | ||
|
||
|
@@ -192,6 +206,7 @@ type Types = | |
, Guest | ||
, UserRequest | ||
, OneType | ||
, RecordUnit | ||
] | ||
|
||
|
||
|
@@ -210,6 +225,7 @@ defaultOneType = OneType | |
, oneTypeGuests = [guestRegular, guestVisitor, guestBlocked] | ||
, oneTypeUserRequest = defaultUserRequest | ||
, oneTypeNonEmpty = MyUnit () :| [ MyUnit () ] | ||
, oneTypeRecordUnit = RecordUnit | ||
} | ||
where | ||
defaultPrims :: Prims | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in theory we can fail here unless json contents empty array. Not if there will be any advantage though.