Files
puzzle-quest/addons/godot_db_manager/core/database.gd
T
VAILLANT Jeremy e8edc134e1 Add addon database
2021-05-13 23:20:27 +02:00

324 lines
10 KiB
GDScript

"""
GDDatabase class
"""
class_name GDDatabase
extends Object
# database types
enum {
e_db_type_json = 0, # JSON database
e_db_type_binary = 1 # binary database - to be designed / implemented
}
# database type
var m_db_type : int = e_db_type_json
# the id of the database
var m_db_id : int = gddb_constants.c_invalid_id
# the name of the database
var m_db_name : String = ""
# tables in the database
var m_tables : Array = []
# the path of the database
var m_db_filepath : String = ""
# if the database is not saved, it is dirty
var m_is_dirty : bool = false
# sets the id of the database
func set_db_id(db_id : int) -> void :
m_db_id = db_id
# returns the database id
func get_db_id() -> int :
return m_db_id
# set the name of the database
# the name of the database should not contain special characters
func set_db_name(db_name : String) -> bool :
if(!gddb_globals.check_db_name(db_name)):
print("ERROR: GDDatabase::set_db_name(" + db_name + ") - the name of the database contains invalid characters")
return false
# print("GDDatabase::set_db_name(" + db_name + ")")
m_db_name = db_name
return true
# returns the name of the database
func get_db_name() -> String :
return m_db_name
# sets the database file path
func set_db_filepath(filepath : String) -> void :
m_db_filepath = filepath
# returns the path of the database
func get_db_filepath() -> String :
return m_db_filepath
# checks if a table with the name "table_name" can be added into database
func can_add_table(table_name : String, table_id : int = -1) -> bool :
# print("GDDatabase::can_add_table(" + table_name + ", " + str(table_id) + ")")
for idx in range(0, m_tables.size()):
if(m_tables[idx].get_table_name() == table_name):
if(m_tables[idx].get_table_id() == table_id):
continue
print("WARNING: GDDatabase::can_add_table(" + table_name + ", " + str(table_id) + ") - table already exists")
return false
return true
# adds a new table
# returns the table id; if already exists, it will fire an warning on output console and returns an invalid id
func add_table(table_name : String) -> int :
if(!can_add_table(table_name)):
print("WARNING: GDDatabase::add_table(" + table_name + ") - cannot add table")
return gddb_constants.c_invalid_id
# print("GDDatabase::add_table(" + table_name + ") to \"" + m_db_name + "\" database")
var table_id = generate_new_table_id()
var table = load(gddb_constants.c_addon_main_path + "core/db_table.gd").new()
table.set_table_id(table_id)
table.set_table_name(table_name)
table.set_parent_database(self)
m_tables.push_back(table)
return table_id
# edits a table name
func edit_table_name(table_name : String, table_id : int) -> bool :
if(!can_add_table(table_name, table_id)):
return false
for idx in range(0, m_tables.size()):
if(m_tables[idx].get_table_id() == table_id):
m_tables[idx].set_table_name(table_name)
break
return true
# deletes a table at index
func delete_table_at(idx : int) -> void :
if(idx < 0 || idx > m_tables.size() - 1):
print("GDDatabase::delete_table_at(" + str(idx) + ") - index out of bounds")
return
m_tables[idx].clear()
m_tables[idx].free()
m_tables.remove(idx)
# deletes a table by id
func delete_table_by_id(table_id: int) -> void :
for idx in range(0, m_tables.size()):
if(m_tables[idx].get_table_id() == table_id):
# print("GDDatabase::delete_table_by_id(" + str(table_id) + ")")
m_tables[idx].clear()
m_tables[idx].free()
m_tables.remove(idx)
return
print("ERROR: GDDatabase::delete_table_by_id(" + str(table_id) + ") - cannot erase table; id not found")
# deletes a table by name
func delete_table_by_name(table_name: String) -> void :
for idx in range(0, m_tables.size()):
if(m_tables[idx].get_table_name() == table_name):
# print("GDDatabase::delete_table_by_name(" + table_name + ")")
m_tables[idx].clear()
m_tables[idx].free()
m_tables.remove(idx)
return
print("ERROR: GDDatabase::delete_table_by_name(" + table_name + ") - cannot erase table; name not found")
# generates a new table id
func generate_new_table_id() -> int :
if(m_tables.size() == 0):
return 0
return m_tables[m_tables.size()-1].get_table_id() + 1
# returns the count of the tables in the database
func get_tables_count() -> int :
return m_tables.size()
# returns true if the table exists in the database, false otherwise
# this is equivalent with (get_table_by_name(table name) != null) function, but without firing the error in case the table doesn't exist
func is_table_exists(table_name : String) -> bool :
for idx in range(0, m_tables.size()):
if(m_tables[idx].get_table_name() == table_name):
return true
return false
# returns a table by an index or null if the index is invalid
func get_table_at(idx: int) -> Object :
if(idx < 0 || idx >= m_tables.size()):
print("ERROR: GDDatabase::get_table_at(" + str(idx) + ") - cannot obtain table with index")
return null
return m_tables[idx]
# returns a table by its id or null if a table with id doesn's exist
func get_table_by_id(table_id: int) -> Object :
for idx in range(0, m_tables.size()):
if(m_tables[idx].get_table_id() == table_id):
return m_tables[idx]
print("ERROR: GDDatabase::get_table_by_id(" + str(table_id) + ") - cannot obtain table with id")
return null
# returns a table by its name or null if the name of the table doesn's exist
func get_table_by_name(table_name: String) -> Object :
for idx in range(0, m_tables.size()):
if(m_tables[idx].get_table_name() == table_name):
return m_tables[idx]
print("ERROR: GDDatabase::get_table_by_id(" + table_name + ") - cannot obtain table with name")
return null
# deletes all the tables
func clear() -> void :
# print("GDDatabase::clear()")
m_db_name = ""
for idx in range(0, m_tables.size()):
m_tables[idx].clear()
m_tables.clear()
# sets the database dirty; it is not saved
func set_dirty(dirty : bool) -> void :
m_is_dirty = dirty
# returns true if a database is dirty (should be saved), false otherwise
func is_dirty() -> bool :
return m_is_dirty
# serialization
func save_db() -> void :
if(m_db_name.empty()):
print("ERROR: GDDatabase::save_db() - current database doesn't have a name")
return
if(m_db_filepath.empty()):
print("ERROR: GDDatabase::save_db() - current database doesn't have a path file")
return
# print("GDDatabase::save_db() - " + m_db_name + " to: " + m_db_filepath)
var text = "{"
text += "\n\t\"" + gddb_constants.c_gddb_signature + "\":\"" + gddb_constants.c_gddb_ver + "\","
text += "\n\t\"db_name\":\"" + m_db_name + "\","
text += "\n\t\"tables\":["
for idx in range(0, m_tables.size()):
text += "\n\t\t{"
text += "\n\t\t\t\"table_name\":\"" + m_tables[idx].get_table_name() + "\","
text += "\n\t\t\t\"props\":["
for jdx in range(0, m_tables[idx].get_props_count()):
var db_prop = m_tables[idx].get_prop_at(jdx)
text += "\n\t\t\t\t\t{"
text += "\"name\":\"" + str(db_prop.get_prop_name()) + "\","
var prop_type = db_prop.get_prop_type()
if(prop_type < gddb_types.e_prop_types_count):
text += "\"type\":\"" + str(prop_type) + "\","
else:
# print("GDDatabase::save_db() - prop_type: " + str(prop_type))
var table_id = prop_type - gddb_types.e_prop_types_count
var table = get_table_by_id(table_id)
if(null == table):
print("GDDatabase::save_db() - table not found with id: " + str(table_id))
text += "\"type\":\"" + "table" + "\","
text += "\"table_name\":\"" + table.get_table_name() + "\","
text += "\"auto_increment\":\"" + str(int(db_prop.has_autoincrement())) + "\""
text += "}"
if(jdx < m_tables[idx].get_props_count() - 1):
text += ","
text += "\n\t\t\t],"
text += "\n\t\t\t\"data\":["
for jdx in range(0, m_tables[idx].get_data_size()):
#var the_data = m_tables[idx].get_data_at(jdx)
#print("getting data at " + str(jdx) + " : " + the_data)
text += "\"" + m_tables[idx].get_data_at(jdx) + "\""
if(jdx < m_tables[idx].get_data_size() - 1):
text += ","
text += "]" # end of data
text += "\n\t\t}" # end of table
if(idx < m_tables.size() - 1):
text += ","
text += "\n\t]\n}"
var save_file = File.new()
save_file.open(m_db_filepath, File.WRITE)
save_file.store_string(text)
save_file.close()
set_dirty(false)
# deserialization
func load_db() -> int :
var file = File.new()
file.open(get_db_filepath(), File.READ)
var content = file.get_as_text()
file.close()
var dictionary = JSON.parse(content).result
# check the signature
if(!dictionary.has(gddb_constants.c_gddb_signature)):
print("GDDatabase::load_db() - invalid database file")
return gddb_types.e_db_invalid_file
var gddb_signature = dictionary[gddb_constants.c_gddb_signature]
if(gddb_signature != gddb_constants.c_gddb_ver):
print("GDDatabase::load_db() - invalid database version")
return gddb_types.e_db_invalid_ver
clear()
m_db_name = dictionary["db_name"]
var tables = dictionary["tables"]
for idx in range(0, tables.size()):
var table_id = add_table(tables[idx]["table_name"])
var table = get_table_by_id(table_id)
var props_count = tables[idx]["props"].size()
if(props_count == 0):
continue
for jdx in range(0, props_count):
var prop_type = tables[idx]["props"][jdx]["type"]
var prop_id = -1
if(prop_type == "table"):
var table_name = tables[idx]["props"][jdx]["table_name"]
prop_id = table.add_table_prop(tables[idx]["props"][jdx]["name"], table_name)
else:
prop_id = table.add_prop(prop_type.to_int(), tables[idx]["props"][jdx]["name"])
var prop = table.get_prop_by_id(prop_id)
var enable_autoincrement = tables[idx]["props"][jdx]["auto_increment"].to_int()
prop.enable_autoincrement(bool(enable_autoincrement))
var data_count = tables[idx]["data"].size()
#print("********* set data to db - begin")
for jdx in range(0, data_count / props_count):
var row_data = []
for kdx in range(0, props_count):
var cell_data = tables[idx]["data"][jdx * props_count + kdx]
# print("cell_data: " + cell_data)
row_data.push_back(cell_data)
#print("row_data: " + str(row_data))
table.add_row(row_data)
#print("********* set data to db - end")
# link custom data to tables
for idx in range(0, m_tables.size()):
m_tables[idx].link_tables_props()
return gddb_types.e_db_valid
# dumps the database
func dump() -> String :
var dump_text = "\nDatabase dump. id: " + str(m_db_id) + ", name: " + m_db_name + ", filepath: " + m_db_filepath
dump_text += "\n------------------------------------------------------------------------------------\n"
for idx in range(0, m_tables.size()):
dump_text += "\n" + m_tables[idx].dump()
return dump_text