<commit_before>﻿namespace Rezoom.SQL.Compiler.SQLite
open System
open System.Collections.Generic
open System.Configuration
open System.Data
open System.Data.Common
open System.IO
open FSharp.Quotations
open Rezoom.SQL.Compiler
open Rezoom.SQL.Compiler.BackendUtilities
open Rezoom.SQL.Compiler.Translators
open Rezoom.SQL.Mapping
open Rezoom.SQL.Migrations
open Rezoom.SQL.Compiler.CoreParser

type private SQLiteLiteral() =
    inherit DefaultLiteralTranslator()
    override __.BooleanLiteral(t) =
        CommandText <| if t then "1" else "0"
    override __.DateTimeLiteral(dt) =
        CommandText <| "'" + dt.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffZ") + "'"

type private SQLiteExpression(statement : StatementTranslator, indexer) =
    inherit DefaultExprTranslator(statement, indexer)
    let literal = SQLiteLiteral()
    override __.Literal = upcast literal
    override __.TypeName(name) =
        (Seq.singleton << text) <|
            match name with
            | BooleanTypeName
            | IntegerTypeName Integer8
            | IntegerTypeName Integer16
            | IntegerTypeName Integer32
            | IntegerTypeName Integer64 -> "INTEGER"
            | FloatTypeName Float32
            | FloatTypeName Float64 -> "FLOAT"
            | DateTimeTypeName // store datetimes as UTC ISO8601 strings -- yyyy-MM-ddTHH:mm:ssZ
            | StringTypeName(_) -> "VARCHAR"
            | GuidTypeName
            | BinaryTypeName(_) -> "BLOB"
            | DecimalTypeName
            | DateTimeOffsetTypeName -> fail <| sprintf "Unsupported type ``%A``" name

type private SQLiteStatement(indexer : IParameterIndexer) as this =
    inherit DefaultStatementTranslator(Name("SQLITE"), indexer)
    let expr = SQLiteExpression(this :> StatementTranslator, indexer)
    override __.Expr = upcast expr
    override __.ColumnsNullableByDefault = true

module private SQLiteFunctions =
    open Rezoom.SQL.Compiler.FunctionDeclarations
    let private minmax name =
        { new FunctionType(Name(name), [| infect a'; vararg (infect a') |], a', idem = true) with
            override __.Aggregate(arg) =
                match arg with
                | ArgumentWildcard -> None
                | ArgumentList (_, exprs) ->
                    if exprs.Length = 1 then
                        Some { AllowWildcard = false; AllowDistinct = false }
                    else
                        None
        }
    let functions =
        let numeric ty = ty |> constrained NumericTypeClass
        [|  // core functions from https://www.sqlite.org/lang_corefunc.html
            proc "changes" [] int64
            func "char" [ vararg string ] string
            func "glob" [ infect string; infect string ] boolean
            func "hex" [ binary ] string
            func "ifnull" [ nullable a'; infect a' ] a'
            func "instr" [ infect (stringish a'); infect a' ] int64
            proc "last_insert_rowid" [] int64
            func "length" [ infect (stringish scalar) ] int64
            func "like" [ infect string; infect string; optional (infect string) ] boolean<commit_msg>Yell when attempting to do useful ALTER TABLE on SQLite.<commit_after>﻿namespace Rezoom.SQL.Compiler.SQLite
open System
open System.Collections.Generic
open System.Configuration
open System.Data
open System.Data.Common
open System.IO
open FSharp.Quotations
open Rezoom.SQL.Compiler
open Rezoom.SQL.Compiler.BackendUtilities
open Rezoom.SQL.Compiler.Translators
open Rezoom.SQL.Mapping
open Rezoom.SQL.Migrations
open Rezoom.SQL.Compiler.CoreParser

type private SQLiteLiteral() =
    inherit DefaultLiteralTranslator()
    override __.BooleanLiteral(t) =
        CommandText <| if t then "1" else "0"
    override __.DateTimeLiteral(dt) =
        CommandText <| "'" + dt.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffZ") + "'"

type private SQLiteExpression(statement : StatementTranslator, indexer) =
    inherit DefaultExprTranslator(statement, indexer)
    let literal = SQLiteLiteral()
    override __.Literal = upcast literal
    override __.TypeName(name) =
        (Seq.singleton << text) <|
            match name with
            | BooleanTypeName
            | IntegerTypeName Integer8
            | IntegerTypeName Integer16
            | IntegerTypeName Integer32
            | IntegerTypeName Integer64 -> "INTEGER"
            | FloatTypeName Float32
            | FloatTypeName Float64 -> "FLOAT"
            | DateTimeTypeName // store datetimes as UTC ISO8601 strings -- yyyy-MM-ddTHH:mm:ssZ
            | StringTypeName(_) -> "VARCHAR"
            | GuidTypeName
            | BinaryTypeName(_) -> "BLOB"
            | DecimalTypeName
            | DateTimeOffsetTypeName -> fail <| sprintf "Unsupported type ``%A``" name

type private SQLiteStatement(indexer : IParameterIndexer) as this =
    inherit DefaultStatementTranslator(Name("SQLITE"), indexer)
    let expr = SQLiteExpression(this :> StatementTranslator, indexer)
    override __.Expr = upcast expr
    override __.ColumnsNullableByDefault = true
    override __.AlterTable(alter) =
        match alter.Alteration with
        | RenameTo _
        | AddColumn _ ->
            base.AlterTable(alter)
        | _ ->
            fail <|
            Error.backendDoesNotSupportFeature
                "SQLite" "ALTER TABLE statements other than RENAME TO/ADD COLUMN"

module private SQLiteFunctions =
    open Rezoom.SQL.Compiler.FunctionDeclarations
    let private minmax name =
        { new FunctionType(Name(name), [| infect a'; vararg (infect a') |], a', idem = true) with
            override __.Aggregate(arg) =
                match arg with
                | ArgumentWildcard -> None
                | ArgumentList (_, exprs) ->
                    if exprs.Length = 1 then
                        Some { AllowWildcard = false; AllowDistinct = false }
                    else
                        None
        }
    let functions =
        let numeric ty = ty |> constrained NumericTypeClass
        [|  // core functions from https://www.sqlite.org/lang_corefunc.html
            proc "changes" [] int64
            func "char" [ vararg string ] string
            func "glob" [ infect string; infect string ] boolean
            func "hex" [ binary ] string
            func "ifnull" [ nullable a'; infect a' ] a'
            func "instr" [ infect (stringish a'); infect a' ] int64
            proc "last_insert_rowid" [] int64
            func "length" [ infect (stringish scalar) ] int64
            func "like" [ infect string; infect string; optional (infect string) ] boolean
{'fraction_non_alphanumeric': 0.09176542084472805, 'fraction_numerical': 0.007900334244910361, 'mean_word_length': 2.3501272264631043, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 23, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, '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': '5981255', 'n_tokens_mistral': 1828, 'n_tokens_neox': 1768, 'n_words': 487}