diff --git a/src/PSBoardDataBase.jl b/src/PSBoardDataBase.jl index 838b6f4..71bec98 100644 --- a/src/PSBoardDataBase.jl +++ b/src/PSBoardDataBase.jl @@ -14,6 +14,9 @@ include("create_table.jl") include("download_csv.jl") include("import_data.jl") +include("dispatch_checker.jl") +using .DispatchChecker + """ create_database_from_exported_csvs( dbpath::AbstractString; diff --git a/src/dispatch_checker.jl b/src/dispatch_checker.jl new file mode 100644 index 0000000..1d208f2 --- /dev/null +++ b/src/dispatch_checker.jl @@ -0,0 +1,134 @@ +module DispatchChecker + +using SQLite +using DBInterface +using DataFrames + +export DbConnection +export is_dispatchable + +mutable struct DbConnection + db::SQLite.DB + df_single_result::DataFrame + df_extra_results::DataFrame + function DbConnection(db::SQLite.DB) + df_single_results = + DBInterface.execute(db, sql"select * from qaqc_single_run_results") |> DataFrame + df_extra_results = + DBInterface.execute(db, sql"select * from qaqc_extra_run_results") |> DataFrame + new(db, df_single_results, df_extra_results) + end +end + +THRESHOLD_INSUFFICIENT_RESET_WITH_10 = 0.1 +THRESHOLD_RESET_FAILED_THOUGH_RECONFIG_DONE = 0.1 +THRESHOLD_ALWAYS_HIT_FLAG_TRUE = 0.1 +THRESHOLD_BCID_FAIL = 0.1 + +""" + is_dispatchable(conn::DbConnection, psbid::Int64) + +Test whether the PS Board with `psbid` is dispatchable from QAQC results in `conn`. +`conn` is type of [`DbConnection`](@ref). +Since the current implemented logic is somewhat simple, it returns `missing` if it cannot be decided. +""" +function is_dispatchable(conn::DbConnection, psbid::Int64) + single_results = filter(:psboard_id => ==(psbid), conn.df_single_result) + extra_results = filter(:psboard_id => ==(psbid), conn.df_extra_results) + + is_single_passed::Bool = nrow(single_results) == 1 && single_results.qaqc_result[1] == 1 + @debug "" is_single_passed single_results + is_extra_passed::Bool = + nrow(extra_results) == 1 && let + extra_result = Tables.rowtable(extra_results) |> first + f1 = + extra_results.insufficient_reset_with_10 > + extra_results.num_tests * THRESHOLD_INSUFFICIENT_RESET_WITH_10 + f2 = + extra_results.reset_failed_though_reconfig_done > + extra_results.num_tests * THRESHOLD_RESET_FAILED_THOUGH_RECONFIG_DONE + f3 = + extra_results.always_hit_flag_true > + extra_results.num_tests * THRESHOLD_ALWAYS_HIT_FLAG_TRUE + f4 = extra_results.bcid_fail > extra_results.num_tests * THRESHOLD_BCID_FAIL + f1 || f2 || f3 || f4 + end + @debug "" is_extra_passed extra_results + + if is_single_passed & is_extra_passed + return true + end + + # TODO: not yet implemented + @info "results" single_results select( + extra_results, + Not(:id, :num_tests, :dac_is_0, :bcid_fail_111, :bcid_fail_000, :low_efficiency), + ) + @debug "results(full)" extra_results + return missing +end + +function interactive_dispatch_checker(conn::DbConnection) + dispatch_list = Int64[] + + println("Type \"quit\" to exit") + for _ in 1:1000 + printstyled("PSBoard ID: ", bold = true) + psbid = let + rawin = readline() + if lowercase(rawin) == "quit" + printstyled("Quit\n", italic = true) + println() + break + end + m = match(r"^PS(\d+)", rawin) + if isnothing(m) + printstyled("Invalid input\n", color = :red) + continue + end + parse(Int64, m[1]) + end + isdispatchable = is_dispatchable(conn, psbid) + if ismissing(isdispatchable) + printstyled("Please determine [y/n]: ", underline = true, color = :cyan) + isdispatchable = let + rawin = readline() + @info "" rawin + if rawin == "y" || rawin == "Y" + true + elseif rawin == "n" || rawin == "N" + false + else + @warn "Invalid input falling back to \"no\"" + false + end + end + end + if isdispatchable + printstyled("Ok\n", bold = true, color = :green) + if psbid in dispatch_list + println("PSBoard ID $(psbid) is already in dispatch list") + else + push!(dispatch_list, psbid) + println("Added to dispatch list") + end + else + printstyled("No\n", bold = true, color = :red) + end + end + + printstyled("Finished\n") + join(dispatch_list, "\n") |> print + println() + printstyled("Paste the result\n", underline = true) + @info "Tips: You can use `join(ans, \"\\n\") |> clipboard` in REPL to copy the result to the clipboard" + + return dispatch_list +end + +function interactive_dispatch_checker(database_file::AbstractString) + conn = DbConnection(SQLite.DB(database_file)) + interactive_dispatch_checker(conn) +end + +end # module DispatchChecker