open Giraffe open System open System.IO open Microsoft.AspNetCore.Builder open Microsoft.AspNetCore.Cors.Infrastructure open Microsoft.AspNetCore.Hosting open Microsoft.Extensions.Hosting open Microsoft.Extensions.Logging open Microsoft.Extensions.DependencyInjection open Microsoft.AspNetCore.Http #if FABLE_COMPILER open Thoth.Json #else open Thoth.Json.Net #endif // Here you can write your code as usual type QueryFilter = | Equal of string * string | GreaterThan of string * float | LessThan of string * float type QueryDSL = { Select: string list Filters: QueryFilter list Sort: (string * string) list } // Field and direction let parseQuery (body: string) = // Example JSON parsing (using FSharp.Data or similar) // Example query JSON: // { "select": ["name", "age"], "filters": [{"field": "age", "op": "gt", "value": 30}], "sort": [["name", "asc"]] } try let query = Decode.Auto.fromString body // let parsed = FSharp.Data.JsonValue.Parse(body) //let selectFields = parsed.["select"].AsArray() |> Array.map string |> List.ofArray //let filters = // parsed.["filters"].AsArray() // |> Array.map (fun filter -> // match filter.["op"].AsString() with // | "eq" -> Equal(filter.["field"].AsString(), filter.["value"].AsString()) // | "gt" -> GreaterThan(filter.["field"].AsString(), filter.["value"].AsFloat()) // | "lt" -> LessThan(filter.["field"].AsString(), filter.["value"].AsFloat()) // | _ -> failwith "Unsupported filter") // |> List.ofArray //let sort = // parsed.["sort"].AsArray() // |> Array.map (fun s -> s.[0].AsString(), s.[1].AsString()) // |> List.ofArray //{ Select = selectFields; Filters = filters; Sort = sort } query with ex -> failwithf "Failed to parse query: %s" ex.Message let fetchData (queryDsl: QueryDSL) = // Mock database query (replace with actual DB logic) let mockData = [ Map.ofList [ "name", box "Alice"; "age", box 30 ] Map.ofList [ "name", box "Bob"; "age", box 25 ] Map.ofList [ "name", box "Charlie"; "age", box 35 ] ] // Filter and transform the data based on the DSL mockData |> List.filter (fun row -> queryDsl.Filters |> List.forall (function | Equal(field, num) -> Map.tryFind field row |> Option.map (fun value -> (string value) = num) |> Option.defaultValue false //row.GetType().GetProperty(field).GetValue(row) = value //| GreaterThan(field, num) -> row.[field] |> float > num | GreaterThan(field, num) -> Map.tryFind field row |> Option.bind (fun value -> match value with | :? float as v -> Some(v > num) | :? int as v -> Some(float v > num) | _ -> None) |> Option.defaultValue false | LessThan(field, num) -> Map.tryFind field row |> Option.bind (fun value -> match value with | :? float as v -> Some(v < num) | :? int as v -> Some(float v < num) | _ -> None) |> Option.defaultValue false)) |> List.map (fun row -> queryDsl.Select |> List.map (fun field -> field, row.[field]) |> dict) |> fun result -> result let queryHandler = fun (next: HttpFunc) (ctx: HttpContext) -> task { //let! body = ctx.ReadBodyAsStringAsync() let! body = ctx.ReadBodyBufferedFromRequestAsync() return! parseQuery body |> Result.map (fun queryDsl -> let data = fetchData queryDsl json data next ctx) |> Result.defaultWith (fun error -> json {| success = false; message = error |} next ctx) } let webApp = choose [ POST >=> choose [ route "/query" >=> queryHandler ] setStatusCode 404 >=> text "Not Found" ] // --------------------------------- // Error handler // --------------------------------- let errorHandler (ex: Exception) (logger: ILogger) = logger.LogError(ex, "An unhandled exception has occurred while executing the request.") clearResponse >=> setStatusCode 500 >=> text ex.Message // --------------------------------- // Config and Main // --------------------------------- let configureCors (builder: CorsPolicyBuilder) = builder.WithOrigins("http://localhost:5000", "https://localhost:5001").AllowAnyMethod().AllowAnyHeader() |> ignore let configureApp (app: IApplicationBuilder) = let env = app.ApplicationServices.GetService() (match env.IsDevelopment() with | true -> app.UseDeveloperExceptionPage() | false -> app.UseGiraffeErrorHandler(errorHandler).UseHttpsRedirection()) .UseCors(configureCors) .UseStaticFiles() .UseGiraffe(webApp) let configureServices (services: IServiceCollection) = services.AddCors() |> ignore services.AddGiraffe() |> ignore let configureLogging (builder: ILoggingBuilder) = builder.AddConsole().AddDebug() |> ignore [] let main args = let contentRoot = Directory.GetCurrentDirectory() let webRoot = Path.Combine(contentRoot, "WebRoot") Host .CreateDefaultBuilder(args) .ConfigureWebHostDefaults(fun webHostBuilder -> webHostBuilder //.UseContentRoot(contentRoot) //.UseWebRoot(webRoot) .Configure(Action configureApp) .ConfigureServices(configureServices) .ConfigureLogging(configureLogging) |> ignore) .Build() .Run() 0 //let configureApp (app: IApplicationBuilder) = // app.UseGiraffe queryHandler //let configureServices (services: IServiceCollection) = // services.AddGiraffe() |> ignore //[] //let main args = // Host.CreateDefaultBuilder(args) // .ConfigureWebHostDefaults(fun webBuilder -> // webBuilder //.Configure(configureApp) // .ConfigureServices(configureServices) // |> ignore) // .Build() // .Run() // 0