diff options
Diffstat (limited to 'logic/database.gd')
| -rw-r--r-- | logic/database.gd | 145 |
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() |
