aboutsummaryrefslogtreecommitdiff
path: root/logic/database.gd
diff options
context:
space:
mode:
authordam <dam@gudinoff>2022-04-06 22:52:14 +0000
committerdam <dam@gudinoff>2022-04-06 22:52:14 +0000
commit1fe674aec4bd6ce3fc666c8545dadb4f0614067d (patch)
tree949a5ff1380bf82edaf387a5b4e04d0a4bf9d46a /logic/database.gd
parent0f1adc3bb1f41b5dd3490f176a5eee2c17007923 (diff)
downloadsurgery-log-1fe674aec4bd6ce3fc666c8545dadb4f0614067d.tar.zst
surgery-log-1fe674aec4bd6ce3fc666c8545dadb4f0614067d.zip
Improved file operations for database and option sets.
Added confirmation dialogs when importing database and option sets files. Standardized the error print calls. Fixed capitalization on menu entries.
Diffstat (limited to 'logic/database.gd')
-rw-r--r--logic/database.gd145
1 files changed, 95 insertions, 50 deletions
diff --git a/logic/database.gd b/logic/database.gd
index 262a18a..8acf1b6 100644
--- a/logic/database.gd
+++ b/logic/database.gd
@@ -8,7 +8,7 @@ var db: Array
var selected_idx: int
var staged_idx: int
-onready var stage := get_node("/root/main/stage") as Stage
+onready var stage := get_node("/root/main/stage") # as Stage @DAM Commented to avoid cyclic dependency.
onready var delete_button := get_node("actions/delete") as Button
onready var edit_button := get_node("actions/edit") as Button
onready var add_button := get_node("actions/add") as Button
@@ -18,7 +18,6 @@ onready var dialog := get_node("/root/main/dialog") as Dialog
func _init():
selected_idx = -1
staged_idx = -1
- load_database()
func _ready():
@@ -32,10 +31,7 @@ func _ready():
stage.connect("save", self, "save_stage")
stage.connect("discard", self, "discard_stage")
- for it in db:
- self.add_item(get_entry_view(it))
-
- clear_selection()
+ load_database()
func get_entry_view(database_entry: Dictionary) -> String:
@@ -62,7 +58,7 @@ func delete_action():
if selected_idx < 0:
return
- dialog.setup("The entry with process ID '%s' will be deleted from the database." % db[selected_idx].process_id, "Delete", "No")
+ dialog.setup("The entry #%d with process ID '%s' will be deleted from the database." % [selected_idx+1, db[selected_idx].process_id], "Delete", "No")
dialog.connect("accepted", self, "delete_action_confirmed")
popup.open_popup("Delete entry?", dialog)
@@ -95,8 +91,8 @@ func add_action():
func save_stage(entry: Dictionary):
if DatabaseEntry.is_valid_entry(entry) == false:
- printerr("INVALID ENTRY RECEIVED")
- return # @DAM Deal with this.
+ printerr("Invalid entry detected.")
+ return
var next_selected_idx: int
if staged_idx >= 0:
@@ -125,7 +121,89 @@ func discard_stage():
grab_focus()
+func save_database(file_path: String = DATABASE_FILE_PATH):
+ match file_path.get_extension():
+ "json":
+ export_json(file_path, db)
+
+ "csv":
+ export_csv(file_path, db)
+
+ _:
+ printerr("Invalid database file extension: '%s'." % file_path.get_file())
+ return
+
+
+static func export_json(file_path: String, data: Array):
+ var database_file := {
+ "version": DATABASE_FILE_VERSION,
+ "database": data,
+ }
+ var indentation_char := "" if file_path == DATABASE_FILE_PATH else "\t"
+ var file_content := JSON.print(database_file, indentation_char)
+
+ var file := File.new()
+ file.open(file_path, File.WRITE)
+ file.store_string(file_content)
+ file.close()
+
+
+static func export_csv(file_path: String, data: Array):
+ var file := File.new()
+ file.open(file_path, File.WRITE)
+ var header := PoolStringArray(DatabaseEntry.ENTRY_PROTOTYPE.keys())
+ file.store_csv_line(header)
+ for it in data:
+ file.store_csv_line(it.values())
+ file.close()
+
+
func load_database(file_path: String = DATABASE_FILE_PATH):
+ match file_path.get_extension():
+ "json":
+ clear_database()
+ db = import_json(file_path)
+ if file_path != DATABASE_FILE_PATH:
+ sanitize_database(db)
+
+ "csv":
+ clear_database()
+ db = import_csv(file_path)
+
+ _:
+ printerr("Invalid database file extension: '%s'." % file_path.get_file())
+ return
+
+ for it in db:
+ # The JSON specification does not define integer or float types, but only a number type.
+ # Therefore, converting a Variant to JSON text will convert all numerical values to float types.
+ # Thus, we cast all integer values once we load them.
+ it["date_year"] = int(it["date_year"])
+ it["date_month"] = int(it["date_month"])
+ it["date_day"] = int(it["date_day"])
+
+ self.add_item(get_entry_view(it))
+
+
+static func sanitize_database(database: Array):
+ var blueprint := DatabaseEntry.ENTRY_PROTOTYPE
+
+ for entry in database:
+ # Delete extra keys.
+ var keys_to_delete: Array
+ for key in entry:
+ if blueprint.has(key) == false:
+ keys_to_delete.append(key)
+ for key in keys_to_delete:
+ entry.erase(key)
+
+ # Fix wrong value types.
+ for key in blueprint:
+ if entry.has(key) == false || typeof(entry[key]) != typeof(blueprint[key]):
+ entry[key] = blueprint[key]
+
+
+static func import_json(file_path: String) -> Array:
var file := File.new()
file.open(file_path, File.READ_WRITE)
var file_content = file.get_as_text()
@@ -133,43 +211,21 @@ func load_database(file_path: String = DATABASE_FILE_PATH):
var parse_result = JSON.parse(file_content)
if parse_result.error != OK || typeof(parse_result.result) != TYPE_DICTIONARY:
- push_error("Failed to parse database file: '%s'.")
- return
+ printerr("Failed to parse database file: '%s'.")
+ return []
if parse_result.result["version"] != DATABASE_FILE_VERSION:
- push_error("Invalid database file version '%s', expected '%s'." % DATABASE_FILE_VERSION)
- return
+ printerr("Invalid database file version '%s', expected '%s'." % DATABASE_FILE_VERSION)
+ return []
if typeof(parse_result.result["database"]) != TYPE_ARRAY:
- push_error("Failed to load database file contents.")
- return
-
- db = parse_result.result["database"]
-
- # The JSON specification does not define integer or float types, but only a number type.
- # Therefore, converting a Variant to JSON text will convert all numerical values to float types.
- # Thus, we cast all integer values once we load them.
- for it in db:
- it.date_year = int(it.date_year)
- it.date_month = int(it.date_month)
- it.date_day = int(it.date_day)
-
-
-func save_database(file_path: String = DATABASE_FILE_PATH):
- var database_file := {
- "version": DATABASE_FILE_VERSION,
- "database": db,
- }
- var indentation_char := "" if file_path == DATABASE_FILE_PATH else "\t"
- var file_content := JSON.print(database_file, indentation_char)
+ printerr("Failed to load database file contents.")
+ return []
- var file := File.new()
- file.open(file_path, File.WRITE)
- file.store_string(file_content)
- file.close()
+ return parse_result.result["database"]
-static func import_database(file_path: String) -> Array:
+static func import_csv(file_path: String) -> Array:
var result: Array
var file := File.new()
file.open(file_path, File.READ_WRITE)
@@ -196,17 +252,6 @@ static func import_database(file_path: String) -> Array:
return result
-static func export_database(file_path: String, database: Array = db):
- var file := File.new()
- file.open(file_path, File.WRITE)
- var header := PoolStringArray(DatabaseEntry.ENTRY_PROTOTYPE.keys())
- file.store_csv_line(header)
- for it in database:
- # @DAM This approach depends on the order the dictionary fields are created.
- file.store_csv_line(it.values())
- file.close()
-
-
func clear_database():
clear_selection()
self.clear()