コード例 #1
0
ファイル: meta_to_db_data.py プロジェクト: inqwell/inq
def meta_data_to_db_insert_text(info_and_data_list, db_type, db_statement_sep=None):
    """
    Convert a list of meta-data texts (along with table info objects) into a text containing insert
    statement for a given database.
    @param IN info_and_data_list List of TableInfo object and meta-data text pairs
    @param IN db_type            DB type (MySQL, Oracle, ...)
    @param IN db_statement_sep   Separator to use for the insert statements; default: ";"
    @return The insert statements as a string
    """

    if db_statement_sep is None:
        db_statement_sep = ";"

    # Get the DB-specific functions/classes
    try:
        xy_to_db_name_func = _name_func_by_db_type[db_type.lower()]
        meta_data_converter = _meta_data_converter_cls_by_db_type[db_type.lower()]()
    except KeyError:
        raise Exception("DB type not supported: '%s'" % db_type)
    
    # Identify the order of insertion
    info_and_data_by_table_name = dict([(item[0].name, item) for item in info_and_data_list])
    table_info_list = [item[0] for item in info_and_data_list]
    table_order = get_table_creation_order(table_info_list)

    # Process each table in the insertion order
    output_lines = []
    for table_name in table_order:
        table_info, meta_data_text = info_and_data_by_table_name[table_name]

        # Convert the meta-data in the data text
        db_data_text = meta_data_converter.meta_to_db_text(meta_data_text)

        # Get the DB table and column names
        db_table_name = xy_to_db_name_func(table_name)
        db_col_names = [xy_to_db_name_func(col_info.name) for col_info in table_info.columns]
        db_col_list_str = ", ".join(db_col_names)
        nb_col_names = len(db_col_names)

        # Process the data rows
        rows = db_data_text.splitlines()
        for row in rows:
            row = row.strip()
            if not row or row.startswith("//"):
                continue
            values = row.split("\t")
            if len(values) != nb_col_names:
                raise Exception("Incorrect number of values (%d expected):\n%s" % (nb_col_names,
                    values))
            insert_statement = "INSERT INTO %s (%s) VALUES (%s)%s" % (
                db_table_name,
                db_col_list_str,
                ", ".join(values),
                db_statement_sep)
            output_lines.append(insert_statement)

    return "\n".join(output_lines)
コード例 #2
0
ファイル: xml_to_django_model.py プロジェクト: inqwell/inq
def table_info_list_to_django_model_text(table_info_list, xy_to_db_name_func):
    """
    Convert a list of table info objects into a Django model text.
    @param IN table_info_list    List of table info objects
    @param IN xy_to_db_name_func Function taking a Xylinq name and returning its DB-compatible name
    @return The Django model text as a string
    """

    # Using """""" so that Perforce does not try any substitution here when committing this file
    result_lines = [
        """\"\"\"
Django model for Xylinq.

$Header"""""": $
$Author"""""": $
$DateTime"""""": $
$Change"""""": $
\"\"\"

from django.db import models""",
    ]

    table_info_by_name = dict([(table_info.name, table_info) for table_info in table_info_list])
    table_order = get_table_creation_order(table_info_list)
    for table_name in table_order:
        table_info = table_info_by_name[table_name]

        # Determine the field to use as primary key:
        # - the table's primary key if it is single-column
        # - the first single-column table's unique key otherwise
        # Also identify the other unique fields and the composite unique keys
        primary_field = None
        unique_fields = []
        unique_composites = []
        pk_col_names = table_info.primary_key.column_names
        if len(pk_col_names) == 1:
            primary_field = _get_field_name(pk_col_names[0])
        else:
            unique_composites.append([_get_field_name(col_name) for col_name in pk_col_names])
        for uk_info in table_info.unique_keys:
            uk_col_names = uk_info.column_names
            if len(uk_col_names) == 1:
                if primary_field is None:
                    primary_field = _get_field_name(uk_col_names[0])
                else:
                    unique_fields.append(_get_field_name(uk_col_names[0]))
            else:
                unique_composites.append([_get_field_name(col_name) for col_name in uk_col_names])
        if primary_field is None:
            raise Exception("Cannot find a single field to use as primary key for table %s" %
                table_name)

        # One-to-one and many-to-one fields
        # Map a field name to a (target class name, target field name) tuple
        one_to_one_fields = {}
        many_to_one_fields = {}
        for fk_info in table_info.foreign_keys:
            fk_col_names = fk_info.column_names
            if len(fk_col_names) == 1:
                field_name = _get_field_name(fk_col_names[0])
                target_cls_name = _get_class_name(fk_info.target_table_name)
                target_field_name = _get_field_name(fk_info.target_column_names[0])
                if field_name == primary_field or field_name in unique_fields:
                    one_to_one_fields[field_name] = (target_cls_name, target_field_name)
                else:
                    many_to_one_fields[field_name] = (target_cls_name, target_field_name)

        # Class header line
        cls_name = _get_class_name(table_name)
        result_lines.append("""
class %s(models.Model):""" % cls_name)

        # Meta class lines
        db_table_name = xy_to_db_name_func(table_name)
        result_lines.append("""    class Meta:
        db_table = u"%s\"""" % db_table_name)
        # The "managed" attribute is only supported by Django's dev version for now, so commenting
        # out the below line
        #result_lines.append("""        managed = False""")
        if unique_composites:
            result_lines.append("""        unique_together = (""")
            for composite in unique_composites:
                result_lines.append("""            ("%s"),""" % "\", \"".join(composite))
            result_lines.append("""        )""")

        # Fields lines
        for col_info in table_info.columns:
            col_name = col_info.name
            field_name = _get_field_name(col_name)
            db_col_name = xy_to_db_name_func(col_name)
            pk_str = field_name == primary_field and ", primary_key=True" or ""
            # NOTE:
            # The Django doc mentions the following about the "null" attribute:
            # "
            # Avoid using null on string-based fields such as CharField and TextField unless you
            # have an excellent reason. If a string-based field has null=True, that means it has
            # two possible values for "no data": NULL, and the empty string. In most cases, it's
            # redundant to have two possible values for "no data"; Django convention is to use
            # the empty string, not NULL.
            # "
            # However, I believe this is only relevant if we plan to enter data through Django's
            # admin site, which is not our case.
            # On top of that, some DBMS do not consider empty string and null as the same.
            # Here, we set the "null" attribute as it is in the DB independently of the type.
            if field_name == primary_field:
                null_str = ""
            else:
                null_str = ", null=%s" % (col_info.nullable and "True" or "False")

            if field_name in one_to_one_fields:
                target_cls_name, target_field_name = one_to_one_fields[field_name]
                if target_cls_name == cls_name:
                    target_cls_name = "\"self\""
                result_lines.append(
                    """    %s = models.OneToOneField(%s, to_field="%s", db_column="%s"%s%s)""" % (
                    field_name, target_cls_name, target_field_name, db_col_name, pk_str, null_str))
            elif field_name in many_to_one_fields:
                target_cls_name, target_field_name = many_to_one_fields[field_name]
                if target_cls_name == cls_name:
                    target_cls_name = "\"self\""
                result_lines.append(
                    """    %s = models.ForeignKey(%s, to_field="%s", db_column="%s"%s%s)""" % (
                    field_name, target_cls_name, target_field_name, db_col_name, pk_str, null_str))
            else:
                type_cls_name, type_attrs_str = _get_field_type(col_info)
                unique_str = field_name in unique_fields and ", unique=True" or ""
                result_lines.append(
                    """    %s = models.%s(%sdb_column="%s"%s%s%s)""" % (
                    field_name, type_cls_name, type_attrs_str, db_col_name, pk_str, unique_str,
                    null_str))

    return "\n".join(result_lines)
コード例 #3
0
def table_info_list_to_django_model_text(table_info_list, xy_to_db_name_func):
    """
    Convert a list of table info objects into a Django model text.
    @param IN table_info_list    List of table info objects
    @param IN xy_to_db_name_func Function taking a Xylinq name and returning its DB-compatible name
    @return The Django model text as a string
    """

    # Using """""" so that Perforce does not try any substitution here when committing this file
    result_lines = [
        """\"\"\"
Django model for Xylinq.

$Header"""
        """: $
$Author"""
        """: $
$DateTime"""
        """: $
$Change"""
        """: $
\"\"\"

from django.db import models""",
    ]

    table_info_by_name = dict([(table_info.name, table_info)
                               for table_info in table_info_list])
    table_order = get_table_creation_order(table_info_list)
    for table_name in table_order:
        table_info = table_info_by_name[table_name]

        # Determine the field to use as primary key:
        # - the table's primary key if it is single-column
        # - the first single-column table's unique key otherwise
        # Also identify the other unique fields and the composite unique keys
        primary_field = None
        unique_fields = []
        unique_composites = []
        pk_col_names = table_info.primary_key.column_names
        if len(pk_col_names) == 1:
            primary_field = _get_field_name(pk_col_names[0])
        else:
            unique_composites.append(
                [_get_field_name(col_name) for col_name in pk_col_names])
        for uk_info in table_info.unique_keys:
            uk_col_names = uk_info.column_names
            if len(uk_col_names) == 1:
                if primary_field is None:
                    primary_field = _get_field_name(uk_col_names[0])
                else:
                    unique_fields.append(_get_field_name(uk_col_names[0]))
            else:
                unique_composites.append(
                    [_get_field_name(col_name) for col_name in uk_col_names])
        if primary_field is None:
            raise Exception(
                "Cannot find a single field to use as primary key for table %s"
                % table_name)

        # One-to-one and many-to-one fields
        # Map a field name to a (target class name, target field name) tuple
        one_to_one_fields = {}
        many_to_one_fields = {}
        for fk_info in table_info.foreign_keys:
            fk_col_names = fk_info.column_names
            if len(fk_col_names) == 1:
                field_name = _get_field_name(fk_col_names[0])
                target_cls_name = _get_class_name(fk_info.target_table_name)
                target_field_name = _get_field_name(
                    fk_info.target_column_names[0])
                if field_name == primary_field or field_name in unique_fields:
                    one_to_one_fields[field_name] = (target_cls_name,
                                                     target_field_name)
                else:
                    many_to_one_fields[field_name] = (target_cls_name,
                                                      target_field_name)

        # Class header line
        cls_name = _get_class_name(table_name)
        result_lines.append("""
class %s(models.Model):""" % cls_name)

        # Meta class lines
        db_table_name = xy_to_db_name_func(table_name)
        result_lines.append("""    class Meta:
        db_table = u"%s\"""" % db_table_name)
        # The "managed" attribute is only supported by Django's dev version for now, so commenting
        # out the below line
        #result_lines.append("""        managed = False""")
        if unique_composites:
            result_lines.append("""        unique_together = (""")
            for composite in unique_composites:
                result_lines.append("""            ("%s"),""" %
                                    "\", \"".join(composite))
            result_lines.append("""        )""")

        # Fields lines
        for col_info in table_info.columns:
            col_name = col_info.name
            field_name = _get_field_name(col_name)
            db_col_name = xy_to_db_name_func(col_name)
            pk_str = field_name == primary_field and ", primary_key=True" or ""
            # NOTE:
            # The Django doc mentions the following about the "null" attribute:
            # "
            # Avoid using null on string-based fields such as CharField and TextField unless you
            # have an excellent reason. If a string-based field has null=True, that means it has
            # two possible values for "no data": NULL, and the empty string. In most cases, it's
            # redundant to have two possible values for "no data"; Django convention is to use
            # the empty string, not NULL.
            # "
            # However, I believe this is only relevant if we plan to enter data through Django's
            # admin site, which is not our case.
            # On top of that, some DBMS do not consider empty string and null as the same.
            # Here, we set the "null" attribute as it is in the DB independently of the type.
            if field_name == primary_field:
                null_str = ""
            else:
                null_str = ", null=%s" % (col_info.nullable and "True"
                                          or "False")

            if field_name in one_to_one_fields:
                target_cls_name, target_field_name = one_to_one_fields[
                    field_name]
                if target_cls_name == cls_name:
                    target_cls_name = "\"self\""
                result_lines.append(
                    """    %s = models.OneToOneField(%s, to_field="%s", db_column="%s"%s%s)"""
                    % (field_name, target_cls_name, target_field_name,
                       db_col_name, pk_str, null_str))
            elif field_name in many_to_one_fields:
                target_cls_name, target_field_name = many_to_one_fields[
                    field_name]
                if target_cls_name == cls_name:
                    target_cls_name = "\"self\""
                result_lines.append(
                    """    %s = models.ForeignKey(%s, to_field="%s", db_column="%s"%s%s)"""
                    % (field_name, target_cls_name, target_field_name,
                       db_col_name, pk_str, null_str))
            else:
                type_cls_name, type_attrs_str = _get_field_type(col_info)
                unique_str = field_name in unique_fields and ", unique=True" or ""
                result_lines.append(
                    """    %s = models.%s(%sdb_column="%s"%s%s%s)""" %
                    (field_name, type_cls_name, type_attrs_str, db_col_name,
                     pk_str, unique_str, null_str))

    return "\n".join(result_lines)
コード例 #4
0
ファイル: meta_to_db_data.py プロジェクト: gilcesarf/inq
def meta_data_to_db_insert_text(info_and_data_list,
                                db_type,
                                db_statement_sep=None):
    """
    Convert a list of meta-data texts (along with table info objects) into a text containing insert
    statement for a given database.
    @param IN info_and_data_list List of TableInfo object and meta-data text pairs
    @param IN db_type            DB type (MySQL, Oracle, ...)
    @param IN db_statement_sep   Separator to use for the insert statements; default: ";"
    @return The insert statements as a string
    """

    if db_statement_sep is None:
        db_statement_sep = ";"

    # Get the DB-specific functions/classes
    try:
        xy_to_db_name_func = _name_func_by_db_type[db_type.lower()]
        meta_data_converter = _meta_data_converter_cls_by_db_type[
            db_type.lower()]()
    except KeyError:
        raise Exception("DB type not supported: '%s'" % db_type)

    # Identify the order of insertion
    info_and_data_by_table_name = dict([(item[0].name, item)
                                        for item in info_and_data_list])
    table_info_list = [item[0] for item in info_and_data_list]
    table_order = get_table_creation_order(table_info_list)

    # Process each table in the insertion order
    output_lines = []
    for table_name in table_order:
        table_info, meta_data_text = info_and_data_by_table_name[table_name]

        # Convert the meta-data in the data text
        db_data_text = meta_data_converter.meta_to_db_text(meta_data_text)

        # Get the DB table and column names
        db_table_name = xy_to_db_name_func(table_name)
        db_col_names = [
            xy_to_db_name_func(col_info.name)
            for col_info in table_info.columns
        ]
        db_col_list_str = ", ".join(db_col_names)
        nb_col_names = len(db_col_names)

        # Process the data rows
        rows = db_data_text.splitlines()
        for row in rows:
            row = row.strip()
            if not row or row.startswith("//"):
                continue
            values = row.split("\t")
            if len(values) != nb_col_names:
                raise Exception(
                    "Incorrect number of values (%d expected):\n%s" %
                    (nb_col_names, values))
            insert_statement = "INSERT INTO %s (%s) VALUES (%s)%s" % (
                db_table_name, db_col_list_str, ", ".join(values),
                db_statement_sep)
            output_lines.append(insert_statement)

    return "\n".join(output_lines)