<commit_before>﻿module FSharp.QueryProvider.DataReader

open System.Collections
open Microsoft.FSharp.Reflection

type ReturnType = 
| Single
| SingleOrDefault
| Many
// | Group of GroupExpression

type ConstructionInfo = {
    ReturnType : ReturnType
    Type : System.Type
    TypeOrLambda : TypeOrLambdaConstructionInfo
}

and TypeOrLambdaConstructionInfo = 
| Type of TypeConstructionInfo
| Lambda of LambdaConstructionInfo

and TypeOrValueConstructionInfo = 
| Type of TypeConstructionInfo
| Value of int

and TypeConstructionInfo = {
    Type : System.Type
    ConstructorArgs : TypeOrValueConstructionInfo seq
    PropertySets : (TypeOrValueConstructionInfo * System.Reflection.PropertyInfo) seq
}

and LambdaConstructionInfo = {
    Lambda : System.Linq.Expressions.LambdaExpression
    Parameters : TypeOrValueConstructionInfo seq
}

let createTypeConstructionInfo t constructorArgs propertySets =
    {
        Type = t
        ConstructorArgs = constructorArgs
        PropertySets = propertySets
    }

let isValueType (t : System.Type) =
    t.IsValueType || t = typedefof<string>
let isOption (t : System.Type) = 
    t.IsGenericType &&
    t.GetGenericTypeDefinition() = typedefof<Option<_>>

let rec constructResult (reader : System.Data.IDataReader) (ctor : ConstructionInfo) : obj =
    
    match ctor.TypeOrLambda with
    | TypeOrLambdaConstructionInfo.Lambda l ->  
        let paramValues = 
            l.Parameters 
            |> Seq.map(fun p -> 
                match p with
                | Type typeCtor -> constructType reader typeCtor
                | Value i -> reader.GetValue i
            )
        l.Lambda.Compile().DynamicInvoke(paramValues |> Seq.toArray)
    | TypeOrLambdaConstructionInfo.Type typeCtor ->
        constructType reader typeCtor

and constructType reader typeCtor = 
    let getSingleIndex() = 
        match typeCtor.ConstructorArgs |> Seq.exactlyOne with
        | Type _ -> failwith "Shouldnt be Type"
        | Value i -> i

    let t = typeCtor.Type
    if t = typedefof<string> then
        reader.GetString (getSingleIndex()) :> obj
    else if t = typedefof<bool> then
        reader.GetBoolean (getSingleIndex()) :> obj
    else if t = typedefof<byte> then
        reader.GetByte (getSingleIndex()) :> obj
    //else if t = typedefof<sbyte> then
    else if t = typedefof<char> then
        reader.GetChar (getSingleIndex()) :> obj
    else if t = typedefof<System.DateTime> then
        reader.GetDateTime (getSingleIndex()) :> obj
    else if t = typedefof<decimal> then
        reader.GetDecimal (getSingleIndex()) :> obj
    else if t = typedefof<double> then
        reader.GetDouble (getSingleIndex()) :> obj
    else if t = typedefof<float> then
        reader.GetFloat (getSingleIndex()) :> obj
    else if t = typedefof<System.Guid> then
        reader.GetGuid (getSingleIndex()) :> obj
    else if t = typedefof<int16> then
        reader.GetInt16 (getSingleIndex()) :> obj
    else if t = typedefof<int32> then
        reader.GetInt32 (getSingleIndex()) :> obj
    else if t = typedefof<int64> then
        reader.GetInt64 (getSingleIndex()) :> obj
    else if isOption t then
        let value = reader.GetValue (getSingleIndex())
        if value <> null then
            t.GetMethod("Some").Invoke(null, [| value |])
        else
            None :> obj
    else
        let ctorArgs = 
            typeCtor.ConstructorArgs
            |> Seq.map(fun arg -> 
                match arg with 
                | Type t -> constructType reader t
                | Value i -> reader.GetValue i<commit_msg>Better getValue in datareader. Added char trimming.<commit_after>﻿module FSharp.QueryProvider.DataReader

open System.Collections
open Microsoft.FSharp.Reflection

type ReturnType = 
| Single
| SingleOrDefault
| Many
// | Group of GroupExpression

type ConstructionInfo = {
    ReturnType : ReturnType
    Type : System.Type
    TypeOrLambda : TypeOrLambdaConstructionInfo
}

and TypeOrLambdaConstructionInfo = 
| Type of TypeConstructionInfo
| Lambda of LambdaConstructionInfo

and TypeOrValueConstructionInfo = 
| Type of TypeConstructionInfo
| Value of int

and TypeConstructionInfo = {
    Type : System.Type
    ConstructorArgs : TypeOrValueConstructionInfo seq
    PropertySets : (TypeOrValueConstructionInfo * System.Reflection.PropertyInfo) seq
}

and LambdaConstructionInfo = {
    Lambda : System.Linq.Expressions.LambdaExpression
    Parameters : TypeOrValueConstructionInfo seq
}

let createTypeConstructionInfo t constructorArgs propertySets =
    {
        Type = t
        ConstructorArgs = constructorArgs
        PropertySets = propertySets
    }

let isValueType (t : System.Type) =
    t.IsValueType || t = typedefof<string>
let isOption (t : System.Type) = 
    t.IsGenericType &&
    t.GetGenericTypeDefinition() = typedefof<Option<_>>

let rec constructResult (reader : System.Data.IDataReader) (ctor : ConstructionInfo) : obj =
    
    match ctor.TypeOrLambda with
    | TypeOrLambdaConstructionInfo.Lambda l ->  
        let paramValues = 
            l.Parameters 
            |> Seq.map(fun p -> 
                match p with
                | Type typeCtor -> constructType reader typeCtor
                | Value i -> reader.GetValue i
            )
        l.Lambda.Compile().DynamicInvoke(paramValues |> Seq.toArray)
    | TypeOrLambdaConstructionInfo.Type typeCtor ->
        constructType reader typeCtor

and constructType reader typeCtor = 
    let getSingleIndex() = 
        match typeCtor.ConstructorArgs |> Seq.exactlyOne with
        | Type _ -> failwith "Shouldnt be Type"
        | Value i -> i

    let getValue i = 
        let typeName = reader.GetDataTypeName i
        let value = reader.GetValue i 
        if typeName = "char" then
            let str = value :?> string 
            str.TrimEnd() :> obj
        else
            value

    let t = typeCtor.Type
    if t = typedefof<string> ||
        t = typedefof<bool> ||
        t = typedefof<byte> ||
        t = typedefof<sbyte> ||
        t = typedefof<char> ||
        t = typedefof<System.DateTime> ||
        t = typedefof<decimal> ||
        t = typedefof<double> ||
        t = typedefof<float> ||
        t = typedefof<System.Guid> ||
        t = typedefof<int16> ||
        t = typedefof<int32> ||
        t = typedefof<int64> then
        getValue (getSingleIndex())
    else if isOption t then
        let value = reader.GetValue (getSingleIndex())
        if value <> null then
            t.GetMethod("Some").Invoke(null, [| value |])
        else
            None :> obj
    else
        let ctorArgs = 
            typeCtor.ConstructorArgs
            |> Seq.map(fun arg -> 
                match arg with 
                | Type t -> constructType reader t
                | Value i -> getValue i
{'fraction_non_alphanumeric': 0.08530666274452126, 'fraction_numerical': 0.002647448154140315, 'mean_word_length': 2.446528129751647, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7044097', 'n_tokens_mistral': 1956, 'n_tokens_neox': 1862, 'n_words': 508}