120 lines
4.5 KiB
Forth
120 lines
4.5 KiB
Forth
open Giraffe
|
|
open Microsoft.AspNetCore.Http
|
|
open Microsoft.AspNetCore.Builder
|
|
open Microsoft.Extensions.DependencyInjection
|
|
open Microsoft.Extensions.Hosting
|
|
open Thoth.Json
|
|
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<QueryDSL> 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 () =
|
|
POST >=> route "query" >=> queryHandler
|
|
// [
|
|
//subRoute "/foo" [ GET [ route "/bar" (text "Aloha!") ] ]
|
|
// POST
|
|
// route "query" queryHandler
|
|
// RequestErrors.notFound "Not Found"
|
|
|
|
// ]
|
|
|
|
let configureApp (app: IApplicationBuilder) =
|
|
app.UseGiraffe queryHandler
|
|
|
|
let configureServices (services: IServiceCollection) =
|
|
services.AddGiraffe() |> ignore
|
|
|
|
[<EntryPoint>]
|
|
let main args =
|
|
Host.CreateDefaultBuilder(args)
|
|
.ConfigureWebHostDefaults(fun webBuilder ->
|
|
webBuilder
|
|
//.Configure(configureApp)
|
|
.ConfigureServices(configureServices)
|
|
|> ignore)
|
|
.Build()
|
|
.Run()
|
|
0
|
|
|