""" 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.is_empty()): print("ERROR: GDDatabase::save_db() - current database doesn't have a name") return if(m_db_filepath.is_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 test_json_conv = JSON.new() test_json_conv.parse(content).result var dictionary = test_json_conv.get_data() # 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