Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/CommonProviderImplementation/ConversionsGenerator.fs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2011-2015, Tomas Petricek (http://tomasp.net), Gustavo Guerra (http://functionalflow.co.uk), and other contributors
// Copyright 2011-2015, Tomas Petricek (http://tomasp.net), Gustavo Guerra (http://functionalflow.co.uk), and other contributors
// Licensed under the Apache License, Version 2.0, see LICENSE.md in this project
//
// Conversions from string to various primitive types
Expand Down Expand Up @@ -68,6 +68,8 @@ let getBackConversionQuotation missingValuesStr cultureStr typ value : Expr<stri
/// Creates a function that takes Expr<string option> and converts it to
/// an expression of other type - the type is specified by `field`
let convertStringValue missingValuesStr cultureStr (field: PrimitiveInferedProperty) =
let fieldName = field.Name
let field = field.Value

let returnType =
match field.TypeWrapper with
Expand All @@ -92,7 +94,7 @@ let convertStringValue missingValuesStr cultureStr (field: PrimitiveInferedPrope
let varExpr = Expr.Cast<string option>(Expr.Var var)

let body =
typeof<TextRuntime>?GetNonOptionalValue field.RuntimeType (field.Name, convert varExpr, varExpr)
typeof<TextRuntime>?GetNonOptionalValue field.RuntimeType (fieldName, convert varExpr, varExpr)

Expr.Let(var, value, body)
| TypeWrapper.Option -> convert value
Expand Down
4 changes: 2 additions & 2 deletions src/CommonProviderImplementation/Helpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ open ProviderImplementation.ProvidedTypes
// ----------------------------------------------------------------------------------------------

[<AutoOpen>]
module internal PrimitiveInferedPropertyExtensions =
module internal PrimitiveInferedValueExtensions =

type PrimitiveInferedProperty with
type PrimitiveInferedValue with

member x.TypeWithMeasure =
match x.UnitOfMeasure with
Expand Down
49 changes: 31 additions & 18 deletions src/CommonRuntime/StructuralTypes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -192,16 +192,27 @@ type Bit = Bit

// ------------------------------------------------------------------------------------------------

/// Represents type information about a primitive property (used mainly in the CSV provider)
/// Represents a transformation of a type
[<RequireQualifiedAccess>]
type TypeWrapper =
/// No transformation will be made to the type
| None
/// The type T will be converter to type T option
| Option
/// The type T will be converter to type Nullable<T>
| Nullable
static member FromOption optional =
if optional then TypeWrapper.Option else TypeWrapper.None

/// Represents type information about a primitive value (used mainly in the CSV provider)
/// This type captures the type, unit of measure and handling of missing values (if we
/// infer that the value may be missing, we can generate option<T> or nullable<T>)
type PrimitiveInferedProperty =
{ Name: string
InferedType: Type
type PrimitiveInferedValue =
{ InferedType: Type
RuntimeType: Type
UnitOfMeasure: Type option
TypeWrapper: TypeWrapper }
static member Create(name, typ, typWrapper, unit) =
static member Create(typ, typWrapper, unit) =
let runtimeTyp =
if typ = typeof<Bit> then
typeof<bool>
Expand All @@ -210,21 +221,23 @@ type PrimitiveInferedProperty =
else
typ

{ Name = name
InferedType = typ
{ InferedType = typ
RuntimeType = runtimeTyp
UnitOfMeasure = unit
TypeWrapper = typWrapper }

static member Create(name, typ, optional, unit) =
PrimitiveInferedProperty.Create(name, typ, (if optional then TypeWrapper.Option else TypeWrapper.None), unit)
static member Create(typ, optional, unit) =
PrimitiveInferedValue.Create(typ, TypeWrapper.FromOption optional, unit)

/// Represents a transformation of a type
[<RequireQualifiedAccess>]
type TypeWrapper =
/// No transformation will be made to the type
| None
/// The type T will be converter to type T option
| Option
/// The type T will be converter to type Nullable<T>
| Nullable
/// Represents type information about a primitive property (used mainly in the CSV provider)
/// This type captures the type, unit of measure and handling of missing values (if we
/// infer that the value may be missing, we can generate option<T> or nullable<T>)
type PrimitiveInferedProperty =
{ Name: string
Value: PrimitiveInferedValue }
static member Create(name, typ, (typWrapper: TypeWrapper), unit) =
{ Name = name
Value = PrimitiveInferedValue.Create(typ, typWrapper, unit) }

static member Create(name, typ, optional, unit) =
PrimitiveInferedProperty.Create(name, typ, TypeWrapper.FromOption optional, unit)
20 changes: 14 additions & 6 deletions src/Csv/CsvInference.fs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ let internal parseHeaders headers numberOfColumns schema unitsOfMeasureProvider
match parseResult with
| SchemaParseResult.Name name -> makeUnique name, None
| SchemaParseResult.NameAndUnit (name, unit) ->
// store the original header because the inferred type might not support units of measure
// store the original header because the inferred type might not support units of measure.
// format: schemaDefinition \n schemaName
(makeUnique item) + "\n" + (makeUnique name), Some unit
| SchemaParseResult.Full prop ->
let prop = { prop with Name = makeUnique prop.Name }
Expand Down Expand Up @@ -367,6 +368,14 @@ let internal getFields preferOptionals inferedType schema =
match Array.get schema index with
| Some prop -> prop
| None ->
let schemaCompleteDefinition, schemaName =
let split = field.Name.Split('\n')

if split.Length > 1 then
split.[0], split.[1]
else
field.Name, field.Name

match field.Type with
| InferedType.Primitive (typ, unit, optional) ->

Expand Down Expand Up @@ -394,15 +403,14 @@ let internal getFields preferOptionals inferedType schema =
match unit with
| Some unit ->
if StructuralInference.supportsUnitsOfMeasure typ then
typ, Some unit, field.Name.Split('\n').[1]
typ, Some unit, schemaName
else
typ, None, field.Name.Split('\n').[0]
| _ -> typ, None, field.Name.Split('\n').[0]
typ, None, schemaCompleteDefinition
| _ -> typ, None, schemaCompleteDefinition

PrimitiveInferedProperty.Create(name, typ, typWrapper, unit)

| _ ->
PrimitiveInferedProperty.Create(field.Name.Split('\n').[0], typeof<string>, preferOptionals, None))
| _ -> PrimitiveInferedProperty.Create(schemaCompleteDefinition, typeof<string>, preferOptionals, None))

| _ -> failwithf "inferFields: Expected record type, got %A" inferedType

Expand Down
5 changes: 2 additions & 3 deletions src/Json/JsonConversionsGenerator.fs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ----------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------
// Conversions from string to various primitive types
// ----------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -48,10 +48,9 @@ type JsonConversionCallingType =

/// Creates a function that takes Expr<JsonValue option> and converts it to
/// an expression of other type - the type is specified by `field`
let convertJsonValue missingValuesStr cultureStr canPassAllConversionCallingTypes (field: PrimitiveInferedProperty) =
let convertJsonValue missingValuesStr cultureStr canPassAllConversionCallingTypes (field: PrimitiveInferedValue) =

assert (field.TypeWithMeasure = field.RuntimeType)
assert (field.Name = "")

let returnType =
match field.TypeWrapper with
Expand Down
2 changes: 1 addition & 1 deletion src/Json/JsonGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ module JsonTypeBuilder =
| InferedType.Primitive (inferedType, unit, optional) ->

let typ, conv, conversionCallingType =
PrimitiveInferedProperty.Create("", inferedType, optional, unit)
PrimitiveInferedValue.Create(inferedType, optional, unit)
|> convertJsonValue "" ctx.CultureStr canPassAllConversionCallingTypes

{ ConvertedType = typ
Expand Down
16 changes: 8 additions & 8 deletions tests/FSharp.Data.DesignTime.Tests/InferenceTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,8 @@ let ``Infers units of measure correctly``() =
||> CsvInference.getFields false
|> List.map (fun field ->
field.Name,
field.RuntimeType,
prettyTypeName field.TypeWithMeasure)
field.Value.RuntimeType,
prettyTypeName field.Value.TypeWithMeasure)

let propString = "String(metre)" , typeof<string> , "string"
let propFloat = "Float" , typeof<float> , "float<meter>"
Expand All @@ -319,9 +319,9 @@ let ``Inference schema override by column name``() =
||> CsvInference.getFields false
|> List.map (fun field ->
field.Name,
field.RuntimeType,
prettyTypeName field.TypeWithMeasure,
field.TypeWrapper)
field.Value.RuntimeType,
prettyTypeName field.Value.TypeWithMeasure,
field.Value.TypeWrapper)

let col1 = "A" , typeof<int> , "int<second>", TypeWrapper.None
let col2 = "B" , typeof<decimal>, "decimal" , TypeWrapper.Nullable
Expand All @@ -342,9 +342,9 @@ let ``Inference schema override by parameter``() =
||> CsvInference.getFields false
|> List.map (fun field ->
field.Name,
field.RuntimeType,
prettyTypeName field.TypeWithMeasure,
field.TypeWrapper)
field.Value.RuntimeType,
prettyTypeName field.Value.TypeWithMeasure,
field.Value.TypeWrapper)

let col1 = "Column1" , typeof<float>, "float" , TypeWrapper.None
let col2 = "Foo" , typeof<int> , "int" , TypeWrapper.None
Expand Down
2 changes: 1 addition & 1 deletion tests/FSharp.Data.Tests/CsvProvider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -635,5 +635,5 @@ let ``InferColumnTypes shall infer empty string as Double``() =
let csv = CsvFile.Load(Path.Combine(__SOURCE_DIRECTORY__, "Data/emptyMissingValue.csv"))
let types = csv.InferColumnTypes(2,[|""|],System.Globalization.CultureInfo.GetCultureInfo(""), null, false, false)
let expected = "Double"
let actual = types.[3].InferedType.Name
let actual = types.[3].Value.InferedType.Name
actual |> should equal expected
15 changes: 9 additions & 6 deletions tests/FSharp.Data.Tests/XmlProvider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1145,13 +1145,14 @@ type SimpleTypes = XmlProvider<Schema = SimpleTypesXsd>

open System.Xml.Schema

let isValid xmlSchemaSet =
let isValid xmlSchemaSet displayErrorMessage =
fun (xml: XElement) ->
try
XDocument(xml).Validate(xmlSchemaSet, validationEventHandler = null)
true
with :? XmlSchemaException as e ->
printfn "%s/n%O" e.Message xml
if displayErrorMessage then
printfn "%s/n%O" e.Message xml
false

[<Test>]
Expand Down Expand Up @@ -1187,7 +1188,7 @@ let ``simple types are formatted properly``() =
double = System.Double.PositiveInfinity)

let schema = SimpleTypes.GetSchema()
let isValid = isValid schema
let isValid = isValid schema true
isValid simpleValues.XElement |> should equal true
isValid minValues.XElement |> should equal true
isValid maxValues.XElement |> should equal true
Expand All @@ -1205,15 +1206,17 @@ let ``time is omitted when zero``() =
decimal = 0M,
double = System.Double.NaN)

let isValid = isValid schema
let isValidWithMsg = isValid schema true
// Don't display the error message each time when we expect to see it:
let isValidWithoutMsg = isValid schema false

let validXml = System.DateTime(2018, 8, 29) |> simpleValues
isValid validXml.XElement |> should equal true
isValidWithMsg validXml.XElement |> should equal true
validXml.XElement.Attribute(XName.Get "date").Value
|> should equal "2018-08-29"

let invalidXml = System.DateTime(2018, 8, 29, 5, 30, 56) |> simpleValues
isValid invalidXml.XElement |> should equal false
isValidWithoutMsg invalidXml.XElement |> should equal false
invalidXml.XElement.Attribute(XName.Get "date").Value
|> should equal "2018-08-29T05:30:56.0000000"

Expand Down