def test_split_identifier(self): self.assertEqual(split_identifier('some_table'), ('', 'some_table')) self.assertEqual(split_identifier('"some_table"'), ('', 'some_table')) self.assertEqual(split_identifier('namespace"."some_table'), ('namespace', 'some_table')) self.assertEqual(split_identifier('"namespace"."some_table"'), ('namespace', 'some_table'))
def test_split_identifier(self): self.assertEqual(split_identifier("some_table"), ("", "some_table")) self.assertEqual(split_identifier('"some_table"'), ("", "some_table")) self.assertEqual( split_identifier('namespace"."some_table'), ("namespace", "some_table") ) self.assertEqual( split_identifier('"namespace"."some_table"'), ("namespace", "some_table") )
def _create_index_name(self, table_name, column_names, suffix=""): """ Generate a unique name for an index/unique constraint. The name is divided into 3 parts: the table name, the column names, and a unique digest and suffix. """ _, table_name = split_identifier(table_name) hash_suffix_part = '%s%s' % (self._digest(table_name, *column_names), suffix) max_length = self.connection.ops.max_name_length() or 200 # If everything fits into max_length, use that name. index_name = '%s_%s_%s' % (table_name, '_'.join(column_names), hash_suffix_part) if len(index_name) <= max_length: return index_name # Shorten a long suffix. if len(hash_suffix_part) > max_length / 3: hash_suffix_part = hash_suffix_part[:max_length // 3] other_length = (max_length - len(hash_suffix_part)) // 2 - 1 index_name = '%s_%s_%s' % ( table_name[:other_length], '_'.join(column_names)[:other_length], hash_suffix_part, ) # Prepend D if needed to prevent the name from starting with an # underscore or a number (not permitted on Oracle). if index_name[0] == "_" or index_name[0].isdigit(): index_name = "D%s" % index_name[:-1] return index_name
def set_name_with_model(self, model): """ Generate a unique name for the index. The name is divided into 3 parts - table name (12 chars), field name (8 chars) and unique hash + suffix (10 chars). Each part is made to fit its size by truncating the excess length. """ _, table_name = split_identifier(model._meta.db_table) column_names = [model._meta.get_field(field_name).column for field_name, order in self.fields_orders] column_names_with_order = [ (('-%s' if order else '%s') % column_name) for column_name, (field_name, order) in zip(column_names, self.fields_orders) ] # The length of the parts of the name is based on the default max # length of 30 characters. hash_data = [table_name] + column_names_with_order + [self.suffix] self.name = '%s_%s_%s' % ( table_name[:11], column_names[0][:7], '%s_%s' % (names_digest(*hash_data, length=6), self.suffix), ) assert len(self.name) <= self.max_name_length, ( 'Index too long for multiple database support. Is self.suffix ' 'longer than 3 characters?' ) self.check_name()
def set_name_with_model(self, model): """ Generate a unique name for the index. The name is divided into 3 parts - table name (12 chars), field name (8 chars) and unique hash + suffix (10 chars). Each part is made to fit its size by truncating the excess length. """ _, table_name = split_identifier(model._meta.db_table) column_names = [model._meta.get_field(field_name).column for field_name, order in self.fields_orders] column_names_with_order = [ (('-%s' if order else '%s') % column_name) for column_name, (field_name, order) in zip(column_names, self.fields_orders) ] # The length of the parts of the name is based on the default max # length of 30 characters. hash_data = [table_name] + column_names_with_order + [self.suffix] self.name = '%s_%s_%s' % ( table_name[:11], column_names[0][:7], '%s_%s' % (names_digest(*hash_data, length=6), self.suffix), ) if len(self.name) > self.max_name_length: raise ValueError( 'Index too long for multiple database support. Is self.suffix ' 'longer than 3 characters?' ) if self.name[0] == '_' or self.name[0].isdigit(): self.name = 'D%s' % self.name[1:]
def set_name_with_model(self, model): """ Generate a unique name for the index. The name is divided into 3 parts - table name (12 chars), field name (8 chars) and unique hash + suffix (10 chars). Each part is made to fit its size by truncating the excess length. """ _, table_name = split_identifier(model._meta.db_table) column_names = [ model._meta.get_field(field_name).column for field_name, order in self.fields_orders ] column_names_with_order = [ (("-%s" if order else "%s") % column_name) for column_name, (field_name, order) in zip(column_names, self.fields_orders) ] # The length of the parts of the name is based on the default max # length of 30 characters. hash_data = [table_name] + column_names_with_order + [self.suffix] self.name = "%s_%s_%s" % ( table_name[:11], column_names[0][:7], "%s_%s" % (names_digest(*hash_data, length=6), self.suffix), ) assert len(self.name) <= self.max_name_length, ( "Index too long for multiple database support. Is self.suffix " "longer than 3 characters?") self.check_name()
def split_table_identifiers(db_table, format='') -> TableIdentifiers: namespace, table = split_identifier(db_table) groupdict = dict( namespace=namespace, table=table, table_name=table, ) if format: _, table_format = split_identifier(format) result = parse(table_format, table) if result: groupdict.update(result.named) return TableIdentifiers(**groupdict)
def _fk_constraint_name(self, model, field, suffix): def create_fk_name(*args, **kwargs): return self.quote_name(self._create_index_name(*args, **kwargs)) return ForeignKeyName( model._meta.db_table.split('[')[-1], [field.column], split_identifier(field.target_field.model._meta.db_table.split('[')[-1])[1], [field.target_field.column], suffix, create_fk_name, )
def normalize_table(db_table: str, format: str, exclude=[]): # Ignore excluded formats for fmt in exclude: result = parse(fmt, db_table) if result: return db_table namespace, table_name = split_identifier(db_table) namespace_format, table_format = split_identifier(format) # Add namespace from format when specified, but not included in db_table if namespace_format and not namespace: result = parse(table_format, table_name) formatted = table_name if not result: formatted = table_format.format(table_name=table_name) return '"{}"."{}"'.format(namespace_format, formatted) pattern = compile(format) result = pattern.parse(db_table) if not result: return format.format(table_name=db_table) return db_table
def _create_fk_sql(self, model, field, suffix): from_table = model._meta.db_table from_column = field.column _, to_table = split_identifier(field.target_field.model._meta.db_table) to_column = field.target_field.column def create_fk_name(*args, **kwargs): return self.quote_name(self._create_index_name(*args, **kwargs)) return Statement( self.sql_create_fk, table=Table(from_table, self.quote_name), name=ForeignKeyName(from_table, [from_column], to_table, [to_column], suffix, create_fk_name), column=Columns(from_table, [from_column], self.quote_name), to_table=Table(field.target_field.model._meta.db_table, self.quote_name), to_column=Columns(field.target_field.model._meta.db_table, [to_column], self.quote_name), deferrable=self.connection.ops.deferrable_sql(), )
def _create_fk_sql(self, model, field, suffix): from_table = model._meta.db_table from_column = field.column _, to_table = split_identifier(field.target_field.model._meta.db_table) to_column = field.target_field.column suffix = suffix % { "to_table": to_table, "to_column": to_column, } return self.sql_create_fk % { "table": self.quote_name(from_table), "name": self.quote_name(self._create_index_name(model, [from_column], suffix=suffix)), "column": self.quote_name(from_column), "to_table": self.quote_name(field.target_field.model._meta.db_table), "to_column": self.quote_name(to_column), "deferrable": self.connection.ops.deferrable_sql(), }
def _create_fk_sql(self, model, field, suffix): def create_fk_name(*args, **kwargs): return self.quote_name(self._create_index_name(*args, **kwargs)) table = Table(model._meta.db_table, self.quote_name) name = ForeignKeyName( model._meta.db_table, [field.column], split_identifier(field.target_field.model._meta.db_table)[1], [field.target_field.column], suffix, create_fk_name, ) column = Columns(model._meta.db_table, [field.column], self.quote_name) to_table = Table(field.target_field.model._meta.db_table, self.quote_name) to_column = Columns(field.target_field.model._meta.db_table, [field.target_field.column], self.quote_name) deferrable = self.connection.ops.deferrable_sql() table_name = model._meta.db_table to_table_name = field.target_field.model._meta.db_table if (table_name == to_table_name): return Statement( self.sql_create_fk, table=table, name=name, column=column, to_table=to_table, to_column=to_column, on_update="", deferrable=deferrable, ) else: return Statement( self.sql_create_fk, table=table, name=name, column=column, to_table=to_table, to_column=to_column, on_update="ON UPDATE CASCADE", deferrable=deferrable, )
def set_name_with_model(self, model): self.fields_orders = [(model._meta.pk.name, '')] _, table_name = split_identifier(model._meta.db_table) digest = names_digest(table_name, *self.fields, length=6) self.name = f"{table_name[:19]}_{digest}_{self.suffix}"
def trigger_name(self, model, trigger_type, prefix="tr"): table_name = split_identifier(model._meta.db_table)[1] return truncate_name("{}_{}_{}".format(prefix, table_name, trigger_type.name.lower()))