Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow .insert(..., foreign_keys=()) to auto-detect table and primary key #25

Closed
simonw opened this issue May 29, 2019 · 4 comments
Closed
Labels
enhancement New feature or request

Comments

@simonw
Copy link
Owner

simonw commented May 29, 2019

The foreign_keys= argument currently takes a list of triples:

db["usages"].insert_all(
    usages_to_insert,
    foreign_keys=(
        ("line_id", "lines", "id"),
        ("definition_id", "definitions", "id"),
    ),
)

As of #16 we have a mechanism for detecting the primary key column (the third item in this triple) - we should use that here too, so foreign keys can be optionally defined as a list of pairs.

@simonw
Copy link
Owner Author

simonw commented Jun 13, 2019

Maybe foreign_keys could even optionally just be a list of columns - it could then attempt to detect the related tables based on some rules-of-thumb and raise an error if there's no obvious candidate.

Rules:

  • If the column name ends in _id, remove that suffix and look for a matching table.
  • Try for a table which is the column name without the _id suffix with an s appended to it
  • Try for a table that's the exact match for the column name

If none of these rules match, raise an error.

So the above example could be further simplified to:

db["usages"].insert_all(
    usages_to_insert,
    foreign_keys=["line_id", "definition_id"]
)

@simonw simonw changed the title Allow .insert(..., foreign_keys=()) to auto-detect primary keys Allow .insert(..., foreign_keys=()) to auto-detect table and primary key Jun 13, 2019
@simonw
Copy link
Owner Author

simonw commented Jun 13, 2019

If I'm going to do this then I should make the other_table and other_column arguments optional here too:

@click.argument("table")
@click.argument("column")
@click.argument("other_table")
@click.argument("other_column")
def add_foreign_key(path, table, column, other_table, other_column):
"""
Add a new foreign key constraint to an existing table. Example usage:
$ sqlite-utils add-foreign-key my.db books author_id authors id
WARNING: Could corrupt your database! Back up your database file first.
"""
db = sqlite_utils.Database(path)
try:
db[table].add_foreign_key(column, other_table, other_column)

@simonw
Copy link
Owner Author

simonw commented Jun 13, 2019

Still need to add this mechanism to .create_table() - this code here is all that needs to be modified - it needs to learn to deal with the alternative syntax for foreign keys and guess the missing data if necessary:

def create_table(
self, name, columns, pk=None, foreign_keys=None, column_order=None, hash_id=None
):
foreign_keys = foreign_keys or []
foreign_keys_by_name = {fk[0]: fk for fk in foreign_keys}

@simonw simonw added the enhancement New feature or request label Jun 13, 2019
@simonw
Copy link
Owner Author

simonw commented Jun 13, 2019

I'm going to reuse the ForeignKey named tuple here:

ForeignKey = namedtuple(
"ForeignKey", ("table", "column", "other_table", "other_column")
)

@simonw simonw closed this as completed in 07a10bd Jun 13, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant