redesign work with db (open connection only when action performed)

This commit is contained in:
2025-03-03 22:03:44 +03:00
parent 626d0ba5fb
commit 10e43fa10f
2 changed files with 63 additions and 59 deletions

120
app.R
View File

@@ -20,7 +20,7 @@ config <- config::get(file = "configs/config.yml")
folder_with_schemas <- fs::path("configs/schemas")
FILE_SCHEME <- fs::path(folder_with_schemas, "main.xlsx")
dbfile <- fs::path("data.sqlite")
DEBUG <- TRUE
DEBUG <- FALSE
# TEMP ! NEED TO HANDLE
rmarkdown::find_pandoc(dir = "/opt/homebrew/bin/")
@@ -53,16 +53,30 @@ inputs_tables_list <- SCHEME_MAIN %>%
# SETUP DB ==========================
con <- DBI::dbConnect(
drv = RSQLite::SQLite(),
dbname = dbfile,
)
#' @description Function to open connection to db, disigned to easy dubugging.
make_db_connection <- function(where = "") {
if (DEBUG) message("=== DB CONNECT ", where)
DBI::dbConnect(RSQLite::SQLite(), dbfile)
}
# Init DB (write dummy data to "main" table)
#' @description Function to close connection to db, disigned to easy dubugging and
#' hide warnings.
close_db_connection <- function(where = "") {
tryCatch(
expr = DBI::dbDisconnect(con),
error = function(e) print(e),
warning = function(w) if (DEBUG) message("=!= ALREADY DISCONNECTED ", where),
finally = if (DEBUG) message("=/= DB DISCONNECT ", where)
)
}
# establish connection
con <- make_db_connection()
# init DB (write dummy data to "main" table)
if (!"main" %in% dbListTables(con)) {
dummy_df <- get_dummy_df() %>%
mutate(id = "dummy")
dummy_df <- mutate(get_dummy_df(), id = "dummy")
# write dummy df into base, then delete dummy row
DBI::dbWriteTable(con, "main", dummy_df, append = TRUE)
@@ -83,7 +97,7 @@ if (identical(colnames(DBI::dbReadTable(con, "main")), names(inputs_simple_list)
if (length(names(inputs_simple_list)) == length(colnames(df_to_rewrite)) &&
length(form_base_difference) == 0 &&
length(base_form_difference) == 0) {
warning("changes in scheme file detected: pressuming here simply changed order")
warning("changes in scheme file detected: assuming order changed only")
}
if (length(names(inputs_simple_list)) == length(colnames(df_to_rewrite)) &&
@@ -101,6 +115,7 @@ if (identical(colnames(DBI::dbReadTable(con, "main")), names(inputs_simple_list)
df_to_rewrite <- df_to_rewrite %>%
mutate(!!sym(i) := get_empty_data(inputs_simple_list[i]))
}
# reorder due to scheme
df_to_rewrite <- df_to_rewrite %>%
select(all_of(names(inputs_simple_list)))
@@ -112,37 +127,18 @@ if (identical(colnames(DBI::dbReadTable(con, "main")), names(inputs_simple_list)
if (length(names(inputs_simple_list)) < length(colnames(df_to_rewrite))) {
stop("changes in scheme file detected: some of inputs form was deleted! it may cause data loss!")
}
# cleaning
rm(df_to_rewrite, form_base_difference)
}
# write dummies (for test purposes)
# purrr::map(
# .x = 1:300,
# .f = \(x) {
# dummy_df <- purrr::map2(
# .x = purrr::set_names(names(inputs_simple_list)),
# .y = inputs_simple_list,
# .f = \(x_id, y_type) {
# if (y_type %in% c("text", "select_one", "select_multiple")) return("dummy")
# if (y_type %in% c("radio")) return("dummy")
# if (y_type %in% c("date")) return(as.Date("1990-01-01"))
# if (y_type %in% c("number")) return(as.double(999))
# }
# ) %>%
# as_tibble() %>%
# mutate(id = glue::glue("test{x}"))
# dbWriteTable(con, "main", dummy_df, append = TRUE)
# dbExecute(con, "DELETE FROM main WHERE id = 'dummy'")
# }
# )
# close connection to prevent data loss
close_db_connection()
# INLINE TABLES =====================
# создаем для каждой таблицы объект
inline_tables <- map(
inline_tables <- purrr::map(
.x = purrr::set_names(inputs_tables_list),
.f = \(x_inline_table_name) {
@@ -181,8 +177,8 @@ create_forms <- function(form_id, form_label, form_type) {
condition <- filter(SCHEME_MAIN, form_id == {{form_id}}) %>% distinct(condition) %>% pull
choices <- filter(SCHEME_MAIN, form_id == {{form_id}}) %>% pull(choices)
# simple text input
if (form_type == "text") {
# simple text or number input
if (form_type %in% c("text", "number")) {
form <- shiny::textAreaInput(
inputId = form_id,
label = tags$span(style = "color: #444444; font-weight: 550;", form_label),
@@ -190,16 +186,6 @@ create_forms <- function(form_id, form_label, form_type) {
)
}
# simple number input
if (form_type == "number") {
form <- textAreaInput(
inputId = form_id,
label = tags$span(style = "color: #444444; font-weight: 550;", form_label),
rows = 1
)
}
# simple date input
if (form_type == "date") {
# supress warning while trying keep data form empty by default
@@ -223,7 +209,6 @@ create_forms <- function(form_id, form_label, form_type) {
choices = choices,
selected = NULL,
options = list(
# placeholder = "выберите из списка...",
create = FALSE,
onInitialize = I('function() { this.setValue(""); }')
)
@@ -239,7 +224,6 @@ create_forms <- function(form_id, form_label, form_type) {
selected = NULL,
multiple = TRUE,
options = list(
# placeholder = "множественный выбор",
create = FALSE,
onInitialize = I('function() { this.setValue(""); }')
)
@@ -271,7 +255,7 @@ create_forms <- function(form_id, form_label, form_type) {
form <- rHandsontableOutput(outputId = form_id)
}
# вложенная таблица
# description part
if (form_type == "description") {
form <- div(HTML(form_label), style = "color:Gray;font-size: 90%;")
}
@@ -312,8 +296,6 @@ make_cards_fn <- function(sub_group) {
# get pages list
pages_list <- unique(SCHEME_MAIN$part)
# TODO: replace with unique(SCHEME_MAIN$part)
# get all forms df
df_forms <- SCHEME_MAIN %>%
distinct(part, subgroup, form_id, form_label, form_type)
@@ -383,7 +365,7 @@ modal_clean_all <- modalDialog(
# окно для подвтерждения удаления
modal_overwrite <- modalDialog(
"Запись с данным id уже существует в базе",
"Запись с данным id уже существует в базе. Это действие перезапишет сохраненные ранее данные.",
title = "Перезаписать данные?",
footer = tagList(
actionButton("cancel_button", "Отмена"),
@@ -394,7 +376,7 @@ modal_overwrite <- modalDialog(
# окно для подвтерждения удаления
modal_load_patients <- modalDialog(
"Загрузить данные пациента",
"Загрузить данные",
uiOutput("load_menu"),
title = "Загрузить имеющиеся данные",
footer = tagList(
@@ -500,7 +482,6 @@ server <- function(input, output) {
# res_auth$admin
})
# CREATE RHANDSOME TABLES =====================
# записать массив пустых табличек в rhands_tables
purrr::walk(
@@ -617,6 +598,8 @@ server <- function(input, output) {
# сохранить простые данные;
observeEvent(input$save_data_button, {
req(input$id)
con <- make_db_connection("save_data_button")
on.exit(close_db_connection("save_data_button"), add = TRUE)
## MAIN
# собрать все значения по введенным данным;
@@ -639,10 +622,10 @@ server <- function(input, output) {
values$data <- setNames(result_df, names(inputs_simple_list)) %>%
as_tibble()
if (length(dbListTables(con)) == 0) {
if (length(DBI::dbListTables(con)) == 0) {
# если база пустая, то просто записываем данные
write_all_to_db()
} else if ("main" %in% dbListTables(con)) {
} else if ("main" %in% DBI::dbListTables(con)) {
# если главная таблица существует, то проверяем существование id
# GET DATA files
@@ -653,7 +636,7 @@ server <- function(input, output) {
", .con = con)
# получаем список записей с данным id
exist_main_df <- dbGetQuery(con, query)
exist_main_df <- DBI::dbGetQuery(con, query)
# проверка по наличию записей с данным ID в базе;
if (nrow(exist_main_df) == 0) {
@@ -667,13 +650,14 @@ server <- function(input, output) {
}
})
## get list of id's from db =====================
observeEvent(input$load_data_button, {
con <- make_db_connection("load_data_button")
on.exit(close_db_connection("load_data_button"))
if (length(dbListTables(con)) != 0 && "main" %in% dbListTables(con)) {
if (length(dbListTables(con)) != 0 && "main" %in% DBI::dbListTables(con)) {
# GET DATA files
ids <- dbGetQuery(con, "SELECT DISTINCT id FROM main") %>%
ids <- DBI::dbGetQuery(con, "SELECT DISTINCT id FROM main") %>%
pull
output$load_menu <- renderUI({
@@ -699,6 +683,8 @@ server <- function(input, output) {
## load data to input forms ==================================
observeEvent(input$read_data, {
con <- make_db_connection("read_data")
on.exit(close_db_connection("read_data"), add = TRUE)
# main df read
test_read_df <- read_df_from_db_by_id("main", con)
@@ -752,6 +738,9 @@ server <- function(input, output) {
output$downloadData <- downloadHandler(
filename = paste0("d2tra_", format(Sys.time(), "%Y%m%d_%H%M%S"), ".xlsx"),
content = function(file) {
con <- make_db_connection("downloadData")
on.exit(close_db_connection("downloadData"), add = TRUE)
# get all data
list_of_df <- purrr::map(
.x = purrr::set_names(c("main", inputs_tables_list)),
@@ -885,6 +874,9 @@ server <- function(input, output) {
## trigger saving function =============
observeEvent(input$data_save, {
con <- make_db_connection("saving data (from modal conf)")
on.exit(close_db_connection("saving data (from modal conf)"), add = TRUE)
# убираем плашку
removeModal()
@@ -902,6 +894,8 @@ server <- function(input, output) {
# FUNCTIONS ==============================
## write all inputs to db ================
write_all_to_db <- function() {
con <- make_db_connection("fn call `write_all_to_db()`")
# on.exit(close_db_connection("fn call `write_all_to_db()`"), add = TRUE)
# write main
write_df_to_db(values$data, "main", con)
@@ -949,6 +943,7 @@ server <- function(input, output) {
## helper function writing dbs ========
write_df_to_db <- function(df, table_name, con) {
# disconnecting on parent function
# delete exists data for this id
if (table_name %in% dbListTables(con)) {
@@ -962,6 +957,9 @@ server <- function(input, output) {
## reading tables from db by name and id ========
read_df_from_db_by_id <- function(table_name, con) {
# DBI::dbConnect(RSQLite::SQLite(), dbfile)
# on.exit(DBI::dbDisconnect(con), add = TRUE)
# check if this table exist
if (table_name %in% dbListTables(con)) {
# prepare query
@@ -977,6 +975,9 @@ server <- function(input, output) {
## reading tables from db all ========
read_df_from_db_all <- function(table_name, con) {
# DBI::dbConnect(RSQLite::SQLite(), dbfile)
# on.exit(DBI::dbDisconnect(con), add = TRUE)
# check if this table exist
if (table_name %in% dbListTables(con)) {
# prepare query
@@ -991,6 +992,9 @@ server <- function(input, output) {
## LOGGING ACTIONS
log_action_to_db <- function(action, pat_id = as.character(NA), con) {
# DBI::dbConnect(RSQLite::SQLite(), dbfile)
# on.exit(DBI::dbDisconnect(con), add = TRUE)
action_row <- tibble(
user = res_auth$user,
action = action,