def insert_record(table_name, attributes): RecordManager.set_file_dir('schema/tables/' + table_name + '/') metadata = load_metadata() position = RecordManager.insert(table_name, metadata.tables[table_name].fmt, tuple(attributes)) for index_name, index in metadata.tables[table_name].indexes.items(): file_path = RecordManager.file_dir + index_name + '.index' fmt = ''.join(metadata.tables[table_name].columns[column].fmt for column in index.columns) manager = IndexManager(file_path, fmt) key_pos = list(metadata.tables[table_name].columns.keys()).index( index.columns[0]) key_list = list() key_list.append(attributes[key_pos]) try: manager.insert( key_list, position) # index can be set on single attribute manager.dump_header() except ValueError: # duplicated key, the inserted record should be deleted RecordManager.delete(table_name, metadata.tables[table_name].fmt, with_index=True, record_offset=position) raise
def select_record_all(table_name): metadata = load_metadata() RecordManager.set_file_dir('schema/tables/' + table_name + '/') records = RecordManager.select(table_name, metadata.tables[table_name].fmt, with_index=False, conditions={}) return records
def _select_single_condition(table_name, condition): metadata = load_metadata() index_name = MinisqlFacade._has_index(condition[0], table_name) if index_name: print('select with index on ', condition[0]) attribute_name = condition[0] operator = condition[1] key_list = list() key_list.append(condition[2]) file_path = RecordManager.file_dir + index_name + '.index' # fmt = metadata.tables[table_name].columns[attribute_name].fmt manager = IndexManager(file_path, fmt) records = list() if operator == '=': try: itr = manager.find(key_list) it_key, value = next(itr) if it_key[0] == key_list[0]: records.append( RecordManager.select( table_name, metadata.tables[table_name].fmt, with_index=True, record_offset=value)) except StopIteration: pass elif operator == '>': for i in manager.find(key_list): if i[0][0] > key_list[0]: value = i[1] records.append( RecordManager.select( table_name, metadata.tables[table_name].fmt, with_index=True, record_offset=value)) elif operator == '<': for i in manager.iter_leaves(): if i[0][0] < key_list[0]: value = i[1] records.append( RecordManager.select( table_name, metadata.tables[table_name].fmt, with_index=True, record_offset=value)) else: break else: pass else: records = MinisqlFacade.select_record_conditionally_without_index( table_name, condition) return records
def delete_record_conditionally_without_index(table_name, condition): metadata = load_metadata() condition_convert = MinisqlFacade._convert_conditions( table_name, condition) records = RecordManager.select(table_name, metadata.tables[table_name].fmt, with_index=False, conditions=condition_convert) for record in records: MinisqlFacade._delete_stupid_index(record, table_name) RecordManager.delete(table_name, metadata.tables[table_name].fmt, with_index=False, conditions=condition_convert)
def delete_record_conditionally(table_name, conditions): RecordManager.set_file_dir('schema/tables/' + table_name + '/') metadata = load_metadata() if len(conditions) == 1: MinisqlFacade._delete_single_condition(table_name, conditions[0]) elif len(conditions) == 3: if conditions[1] == 'and': records = MinisqlFacade.select_record_conditionally( table_name, conditions) for record in records: for index_name, index in metadata.tables[ table_name].indexes.items(): file_path = RecordManager.file_dir + index_name + '.index' fmt = ''.join( metadata.tables[table_name].columns[column].fmt for column in index.columns) manager = IndexManager(file_path, fmt) pos = list( metadata.tables[table_name].columns.keys()).index( index.columns[0]) key_list = list() key_list.append(record[pos]) itr = manager.find(key_list) trash, value = next(itr) manager.delete(key_list) manager.dump_header() RecordManager.delete(table_name, metadata.tables[table_name].fmt, with_index=1, record_offset=value) # each tuple has its PRIMARY KEY index # actually only support single attribute index elif conditions[1] == 'or': MinisqlFacade._delete_single_condition(table_name, conditions[0]) MinisqlFacade._delete_single_condition(table_name, conditions[2]) else: pass # link the records outside else: pass
def select_record_conditionally_without_index( table_name, condition): # support only equivalent search metadata = load_metadata() condition_convert = MinisqlFacade._convert_conditions( table_name, condition) records = RecordManager.select(table_name, metadata.tables[table_name].fmt, with_index=False, conditions=condition_convert) return records
def delete_record_all(table_name): RecordManager.set_file_dir('schema/tables/' + table_name + '/') metadata = load_metadata() RecordManager.delete(table_name, metadata.tables[table_name].fmt, with_index=False, conditions={}) for index_name, index in metadata.tables[table_name].indexes.items(): file_path = RecordManager.file_dir + index_name + '.index' fmt = ''.join(metadata.tables[table_name].columns[column].fmt for column in index.columns) manager = IndexManager(file_path, fmt) try: for i in manager.iter_leaves(): key_list = list() key_list.append(i[0][0]) manager.delete(key_list) except RuntimeError: pass
def create_table(table_name, primary_key, columns): os.makedirs('schema/tables/' + table_name, exist_ok=True) metadata = load_metadata() # PK can be set on only one attribute columns_lst = [] for column in columns: # generate the fmt for this column if column[1][0] == 'char': fmt = str(column[1][1]) + 's' elif column[1][0] == 'int': fmt = str(column[1][1]) + 'i' else: fmt = str(column[1][1]) + 'd' columns_lst.append( Column(column[0], fmt, primary_key=(column[0] == primary_key), unique=column[2])) metadata.add_table(table_name, *columns_lst) RecordManager.set_file_dir('schema/tables/' + table_name + '/') RecordManager.init_table(table_name) metadata.dump()
def select_record_conditionally(table_name, conditions): RecordManager.set_file_dir('schema/tables/' + table_name + '/') records = list() if len(conditions) == 1: records += (MinisqlFacade._select_single_condition( table_name, conditions[0])) elif len(conditions) == 3: record_1 = MinisqlFacade._select_single_condition( table_name, conditions[0]) record_2 = MinisqlFacade._select_single_condition( table_name, conditions[2]) if conditions[1] == 'and': records = list(set(record_1).intersection(set(record_2))) elif conditions[1] == 'or': records = list(set(record_1).union(set(record_2))) else: pass # link the records outside else: pass return records
def create_index(table_name, index_name, column_name): RecordManager.set_file_dir('schema/tables/' + table_name + '/') offset = -1 metadata = load_metadata() metadata.add_index(table_name, index_name, column_name) records = RecordManager.select(table_name, metadata.tables[table_name].fmt, with_index=False, conditions={}) file_path = RecordManager.file_dir + index_name + '.index' table_target = metadata.tables[table_name] fmt = ''.join(table_target.columns[column].fmt for column in table_target.indexes[index_name].columns) manager = IndexManager(file_path, fmt) key_pos = list( metadata.tables[table_name].columns.keys()).index(column_name) for record in records: key_list = list() key_list.append(record[key_pos]) offset += 1 manager.insert(key_list, offset) metadata.dump() manager.dump_header()
def setUp(self): RecordManager.init_table('gg') RecordManager.init_table('ggg') RecordManager.init_table('foo3')
def setUp(self): RecordManager.init_table('foo') RecordManager.init_table('foo2')
def test_without_index(self): RecordManager.insert('foo3', 'i4sd', (1, 'abcd', 1.0)) RecordManager.insert('foo3', 'i4sd', (1, 'bcde', 1.0)) conditions = dict() conditions[0] = {'=': 1} self.assertEqual( RecordManager.select('foo3', 'i4sd', with_index=False, conditions=conditions), [(1, 'abcd', 1.0), (1, 'bcde', 1.0)]) RecordManager.delete('foo3', 'i4sd', with_index=False, conditions=conditions) self.assertEqual( RecordManager.select('foo3', 'i4sd', with_index=False, conditions=conditions), []) RecordManager.insert('foo3', 'i4sd', (1, 'abcd', 1.0)) RecordManager.insert('foo3', 'i4sd', (1, 'bcde', 1.0)) del conditions[0] conditions[1] = {'=': 'abcd'} RecordManager.update('foo3', 'i4sd', (2, 'cccc', 1.0), with_index=False, conditions=conditions) del conditions[1] conditions[2] = {'=': 1.0} self.assertEqual( RecordManager.select('foo3', 'i4sd', with_index=False, conditions=conditions), [(1, 'bcde', 1.0), (2, 'cccc', 1.0)])
def test_repeat_file(self): with self.assertRaises(RuntimeError): RecordManager.init_table('foo3') with self.assertRaises(RuntimeError): RecordManager.init_table('gg')
def test_records_with_string(self): RecordManager.insert('ggg', '<idi4s', (1, 2.0, 3, 'temps')) # todo: check the length of string in the given attributes ? self.assertEqual( RecordManager.select('ggg', '<idi4s', with_index=True, record_offset=0), (1, 2.0, 3, 'temp')) RecordManager.insert('ggg', '<idi4s', (1, 2.0, 3, 'no')) # less than maximum length self.assertEqual( RecordManager.select('ggg', '<idi4s', with_index=True, record_offset=1), (1, 2.0, 3, 'no')) RecordManager.update('ggg', '<idi4s', (1, 2.0, 3, 'nono'), with_index=True, record_offset=1) self.assertEqual( RecordManager.select('ggg', '<idi4s', with_index=True, record_offset=1), (1, 2.0, 3, 'nono')) RecordManager.delete('ggg', '<idi4s', with_index=True, record_offset=1) RecordManager.delete('ggg', '<idi4s', with_index=True, record_offset=0) with self.assertRaises(RuntimeError): RecordManager.select('ggg', '<idi4s', with_index=True, record_offset=0) RecordManager.update('ggg', '<idi4s', (1, 2.0, 3, 'nono'), with_index=True, record_offset=1)
def test_record_manager(self): RecordManager.insert('gg', '<idi', (1, 3.0, 4)) RecordManager.insert('gg', '<idi', (-1, 3.5, -1)) self.assertEqual( RecordManager.select('gg', '<idi', with_index=True, record_offset=1), (-1, 3.5, -1)) RecordManager.update('gg', '<idi', (1, 3.0, 4), with_index=True, record_offset=1) self.assertEqual( RecordManager.select('gg', '<idi', with_index=True, record_offset=1), (1, 3.0, 4)) RecordManager.delete('gg', '<idi', with_index=True, record_offset=1) with self.assertRaises(RuntimeError): RecordManager.select('gg', '<idi', with_index=True, record_offset=1) RecordManager.update('gg', '<idi', (1, 2.0, 3), with_index=True, record_offset=1)