Skip to content
29 changes: 29 additions & 0 deletions src/FSharp.Data.DesignTime/Csv/CsvGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,35 @@ module internal CsvTypeBuilder =
for field in fields do
rowType.AddMember field.ProvidedProperty

// Add With* methods so users can create a modified copy of a row
// e.g. myRow.WithAmount(42.0) returns a new Row identical to myRow except Amount = 42.0
for targetIdx, targetField in List.indexed fields do
let methodName = "With" + targetField.ProvidedProperty.Name

let withMethod =
ProvidedMethod(
methodName,
[ ProvidedParameter(targetField.ProvidedParameter.Name, targetField.ProvidedProperty.PropertyType) ],
rowType,
invokeCode =
fun args ->
let row = args.[0]
let newVal = args.[1]

match fields with
| [ _ ] ->
// Single-column CSV: Row erases to the value itself
newVal
| _ ->
let tupleArgs =
fields
|> List.mapi (fun i _ -> if i = targetIdx then newVal else Expr.TupleGet(row, i))

Expr.NewTuple tupleArgs
)

rowType.AddMember withMethod

// The erased csv type will be parameterised by the tuple type
let csvErasedTypeWithRowErasedType =
typedefof<CsvFile<_>>.MakeGenericType(rowErasedType)
Expand Down
33 changes: 31 additions & 2 deletions src/FSharp.Data.DesignTime/Json/JsonGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,7 @@ module JsonTypeBuilder =

let name = makeUnique prop.Name

prop.Name,
(prop.Name, name),
[ ProvidedProperty(name, convertedType, getterCode = getter) ],
ProvidedParameter(
(if ctx.UseOriginalNames then
Expand All @@ -661,7 +661,8 @@ module JsonTypeBuilder =
replaceJDocWithJValue ctx convertedType
) ]

let names, properties, parameters = List.unzip3 members
let namePairs, properties, parameters = List.unzip3 members
let names = namePairs |> List.map fst
let properties = properties |> List.concat
objectTy.AddMembers properties

Expand All @@ -685,6 +686,34 @@ module JsonTypeBuilder =
let ctor = ProvidedConstructor(parameters, invokeCode = ctorCode)
objectTy.AddMember ctor

// Add With* methods: WithPropName(newValue) returns a new record with one field updated
for i, (rawName, displayName) in List.indexed namePairs do
let param = parameters.[i]
let cultureStr = ctx.CultureStr

let withMethod =
ProvidedMethod(
"With" + displayName,
[ ProvidedParameter(param.Name, param.ParameterType) ],
objectTy,
invokeCode =
fun args ->
let jDoc = args.[0]
let newVal = args.[1]
let newValObj = Expr.Coerce(newVal, typeof<obj>)

<@@
JsonRuntime.WithRecordProperty(
(%%jDoc: IJsonDocument),
rawName,
%%newValObj,
cultureStr
)
@@>
)

objectTy.AddMember withMethod

()

if ctx.GenerateConstructors then
Expand Down
25 changes: 25 additions & 0 deletions src/FSharp.Data.Json.Core/JsonRuntime.fs
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,31 @@ type JsonRuntime =

JsonDocument.Create(json, "")

// Returns a new JSON record document with one property replaced (or added if absent).
// Used by generated With* methods.
static member WithRecordProperty(doc: IJsonDocument, name: string, value: obj, cultureStr: string) =
let cultureInfo = TextRuntime.GetCulture cultureStr
let newPropValue = JsonRuntime.ToJsonValue cultureInfo value
let existingProps = JsonRuntime.GetRecordProperties(doc)
let mutable found = false

let updatedProps =
existingProps
|> Array.map (fun (k, v) ->
if k = name then
found <- true
k, newPropValue
else
k, v)

let finalProps =
if found then
updatedProps
else
Array.append updatedProps [| name, newPropValue |]

JsonDocument.Create(JsonValue.Record finalProps, "")

// Creates a JsonValue.Record, omitting null fields, and wraps it in a json document
static member CreateRecordOmitNulls(properties, cultureStr) =
let cultureInfo = TextRuntime.GetCulture cultureStr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,4 +246,52 @@ class CsvProvider+Row : float * float * decimal * int * int * int
member Wind: decimal with get
(let _,_,t3,_,_,_ = this in t3)

member WithDay: day:int -> CsvProvider+Row
(let t1,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_ = this in t3),
(let _,_,_,t4,_,_ = this in t4),
(let _,_,_,_,t5,_ = this in t5),
day

member WithMonth: month:int -> CsvProvider+Row
(let t1,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_ = this in t3),
(let _,_,_,t4,_,_ = this in t4),
month,
(let _,_,_,_,_,t6 = this in t6)

member WithOzone: ozone:float -> CsvProvider+Row
ozone,
(let _,t2,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_ = this in t3),
(let _,_,_,t4,_,_ = this in t4),
(let _,_,_,_,t5,_ = this in t5),
(let _,_,_,_,_,t6 = this in t6)

member WithSolar.R: solarR:float -> CsvProvider+Row
(let t1,_,_,_,_,_ = this in t1),
solarR,
(let _,_,t3,_,_,_ = this in t3),
(let _,_,_,t4,_,_ = this in t4),
(let _,_,_,_,t5,_ = this in t5),
(let _,_,_,_,_,t6 = this in t6)

member WithTemp: temp:int -> CsvProvider+Row
(let t1,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_ = this in t3),
temp,
(let _,_,_,_,t5,_ = this in t5),
(let _,_,_,_,_,t6 = this in t6)

member WithWind: wind:decimal -> CsvProvider+Row
(let t1,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_ = this in t2),
wind,
(let _,_,_,t4,_,_ = this in t4),
(let _,_,_,_,t5,_ = this in t5),
(let _,_,_,_,_,t6 = this in t6)


Original file line number Diff line number Diff line change
Expand Up @@ -406,4 +406,147 @@ class CsvProvider+Row : System.DateTime * string * string * string * string * st
member USD: string with get
(let _,t2,_,_,_,_,_,_,_,_,_ = this in t2)

member WithAUD: aud:string -> CsvProvider+Row
(let t1,_,_,_,_,_,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_,_,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_,_,_,_,_,_ = this in t3),
(let _,_,_,t4,_,_,_,_,_,_,_ = this in t4),
(let _,_,_,_,t5,_,_,_,_,_,_ = this in t5),
(let _,_,_,_,_,t6,_,_,_,_,_ = this in t6),
(let _,_,_,_,_,_,t7,_,_,_,_ = this in t7),
(let _,_,_,_,_,_,_,t8,_,_,_ = this in t8),
(let _,_,_,_,_,_,_,_,t9,_,_ = this in t9),
(let _,_,_,_,_,_,_,_,_,t10,_ = this in t10),
aud

member WithCAD: cad:string -> CsvProvider+Row
(let t1,_,_,_,_,_,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_,_,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_,_,_,_,_,_ = this in t3),
(let _,_,_,t4,_,_,_,_,_,_,_ = this in t4),
(let _,_,_,_,t5,_,_,_,_,_,_ = this in t5),
(let _,_,_,_,_,t6,_,_,_,_,_ = this in t6),
(let _,_,_,_,_,_,t7,_,_,_,_ = this in t7),
(let _,_,_,_,_,_,_,t8,_,_,_ = this in t8),
cad,
(let _,_,_,_,_,_,_,_,_,t10,_ = this in t10),
(let _,_,_,_,_,_,_,_,_,_,t11 = this in t11)

member WithCHF: chf:string -> CsvProvider+Row
(let t1,_,_,_,_,_,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_,_,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_,_,_,_,_,_ = this in t3),
(let _,_,_,t4,_,_,_,_,_,_,_ = this in t4),
(let _,_,_,_,t5,_,_,_,_,_,_ = this in t5),
(let _,_,_,_,_,t6,_,_,_,_,_ = this in t6),
chf,
(let _,_,_,_,_,_,_,t8,_,_,_ = this in t8),
(let _,_,_,_,_,_,_,_,t9,_,_ = this in t9),
(let _,_,_,_,_,_,_,_,_,t10,_ = this in t10),
(let _,_,_,_,_,_,_,_,_,_,t11 = this in t11)

member WithDKK: dkk:string -> CsvProvider+Row
(let t1,_,_,_,_,_,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_,_,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_,_,_,_,_,_ = this in t3),
(let _,_,_,t4,_,_,_,_,_,_,_ = this in t4),
dkk,
(let _,_,_,_,_,t6,_,_,_,_,_ = this in t6),
(let _,_,_,_,_,_,t7,_,_,_,_ = this in t7),
(let _,_,_,_,_,_,_,t8,_,_,_ = this in t8),
(let _,_,_,_,_,_,_,_,t9,_,_ = this in t9),
(let _,_,_,_,_,_,_,_,_,t10,_ = this in t10),
(let _,_,_,_,_,_,_,_,_,_,t11 = this in t11)

member WithDato: dato:System.DateTime -> CsvProvider+Row
dato,
(let _,t2,_,_,_,_,_,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_,_,_,_,_,_ = this in t3),
(let _,_,_,t4,_,_,_,_,_,_,_ = this in t4),
(let _,_,_,_,t5,_,_,_,_,_,_ = this in t5),
(let _,_,_,_,_,t6,_,_,_,_,_ = this in t6),
(let _,_,_,_,_,_,t7,_,_,_,_ = this in t7),
(let _,_,_,_,_,_,_,t8,_,_,_ = this in t8),
(let _,_,_,_,_,_,_,_,t9,_,_ = this in t9),
(let _,_,_,_,_,_,_,_,_,t10,_ = this in t10),
(let _,_,_,_,_,_,_,_,_,_,t11 = this in t11)

member WithEUR: eur:string -> CsvProvider+Row
(let t1,_,_,_,_,_,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_,_,_,_,_,_ = this in t2),
eur,
(let _,_,_,t4,_,_,_,_,_,_,_ = this in t4),
(let _,_,_,_,t5,_,_,_,_,_,_ = this in t5),
(let _,_,_,_,_,t6,_,_,_,_,_ = this in t6),
(let _,_,_,_,_,_,t7,_,_,_,_ = this in t7),
(let _,_,_,_,_,_,_,t8,_,_,_ = this in t8),
(let _,_,_,_,_,_,_,_,t9,_,_ = this in t9),
(let _,_,_,_,_,_,_,_,_,t10,_ = this in t10),
(let _,_,_,_,_,_,_,_,_,_,t11 = this in t11)

member WithGBP: gbp:string -> CsvProvider+Row
(let t1,_,_,_,_,_,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_,_,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_,_,_,_,_,_ = this in t3),
(let _,_,_,t4,_,_,_,_,_,_,_ = this in t4),
(let _,_,_,_,t5,_,_,_,_,_,_ = this in t5),
gbp,
(let _,_,_,_,_,_,t7,_,_,_,_ = this in t7),
(let _,_,_,_,_,_,_,t8,_,_,_ = this in t8),
(let _,_,_,_,_,_,_,_,t9,_,_ = this in t9),
(let _,_,_,_,_,_,_,_,_,t10,_ = this in t10),
(let _,_,_,_,_,_,_,_,_,_,t11 = this in t11)

member WithISK: isk:string -> CsvProvider+Row
(let t1,_,_,_,_,_,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_,_,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_,_,_,_,_,_ = this in t3),
(let _,_,_,t4,_,_,_,_,_,_,_ = this in t4),
(let _,_,_,_,t5,_,_,_,_,_,_ = this in t5),
(let _,_,_,_,_,t6,_,_,_,_,_ = this in t6),
(let _,_,_,_,_,_,t7,_,_,_,_ = this in t7),
(let _,_,_,_,_,_,_,t8,_,_,_ = this in t8),
(let _,_,_,_,_,_,_,_,t9,_,_ = this in t9),
isk,
(let _,_,_,_,_,_,_,_,_,_,t11 = this in t11)

member WithJPY: jpy:string -> CsvProvider+Row
(let t1,_,_,_,_,_,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_,_,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_,_,_,_,_,_ = this in t3),
(let _,_,_,t4,_,_,_,_,_,_,_ = this in t4),
(let _,_,_,_,t5,_,_,_,_,_,_ = this in t5),
(let _,_,_,_,_,t6,_,_,_,_,_ = this in t6),
(let _,_,_,_,_,_,t7,_,_,_,_ = this in t7),
jpy,
(let _,_,_,_,_,_,_,_,t9,_,_ = this in t9),
(let _,_,_,_,_,_,_,_,_,t10,_ = this in t10),
(let _,_,_,_,_,_,_,_,_,_,t11 = this in t11)

member WithSEK: sek:string -> CsvProvider+Row
(let t1,_,_,_,_,_,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_,_,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_,_,_,_,_,_ = this in t3),
sek,
(let _,_,_,_,t5,_,_,_,_,_,_ = this in t5),
(let _,_,_,_,_,t6,_,_,_,_,_ = this in t6),
(let _,_,_,_,_,_,t7,_,_,_,_ = this in t7),
(let _,_,_,_,_,_,_,t8,_,_,_ = this in t8),
(let _,_,_,_,_,_,_,_,t9,_,_ = this in t9),
(let _,_,_,_,_,_,_,_,_,t10,_ = this in t10),
(let _,_,_,_,_,_,_,_,_,_,t11 = this in t11)

member WithUSD: usd:string -> CsvProvider+Row
(let t1,_,_,_,_,_,_,_,_,_,_ = this in t1),
usd,
(let _,_,t3,_,_,_,_,_,_,_,_ = this in t3),
(let _,_,_,t4,_,_,_,_,_,_,_ = this in t4),
(let _,_,_,_,t5,_,_,_,_,_,_ = this in t5),
(let _,_,_,_,_,t6,_,_,_,_,_ = this in t6),
(let _,_,_,_,_,_,t7,_,_,_,_ = this in t7),
(let _,_,_,_,_,_,_,t8,_,_,_ = this in t8),
(let _,_,_,_,_,_,_,_,t9,_,_ = this in t9),
(let _,_,_,_,_,_,_,_,_,t10,_ = this in t10),
(let _,_,_,_,_,_,_,_,_,_,t11 = this in t11)


Original file line number Diff line number Diff line change
Expand Up @@ -232,4 +232,52 @@ class CsvProvider+Row : string * System.DateTimeOffset * System.Guid option * st
member Column6: string with get
(let _,_,_,_,_,t6 = this in t6)

member WithColumn1: column1:string -> CsvProvider+Row
column1,
(let _,t2,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_ = this in t3),
(let _,_,_,t4,_,_ = this in t4),
(let _,_,_,_,t5,_ = this in t5),
(let _,_,_,_,_,t6 = this in t6)

member WithColumn2: column2:System.DateTimeOffset -> CsvProvider+Row
(let t1,_,_,_,_,_ = this in t1),
column2,
(let _,_,t3,_,_,_ = this in t3),
(let _,_,_,t4,_,_ = this in t4),
(let _,_,_,_,t5,_ = this in t5),
(let _,_,_,_,_,t6 = this in t6)

member WithColumn3: column3:System.Guid option -> CsvProvider+Row
(let t1,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_ = this in t2),
column3,
(let _,_,_,t4,_,_ = this in t4),
(let _,_,_,_,t5,_ = this in t5),
(let _,_,_,_,_,t6 = this in t6)

member WithColumn4: column4:string -> CsvProvider+Row
(let t1,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_ = this in t3),
column4,
(let _,_,_,_,t5,_ = this in t5),
(let _,_,_,_,_,t6 = this in t6)

member WithColumn5: column5:string -> CsvProvider+Row
(let t1,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_ = this in t3),
(let _,_,_,t4,_,_ = this in t4),
column5,
(let _,_,_,_,_,t6 = this in t6)

member WithColumn6: column6:string -> CsvProvider+Row
(let t1,_,_,_,_,_ = this in t1),
(let _,t2,_,_,_,_ = this in t2),
(let _,_,t3,_,_,_ = this in t3),
(let _,_,_,t4,_,_ = this in t4),
(let _,_,_,_,t5,_ = this in t5),
column6


Loading
Loading