pypika icon indicating copy to clipboard operation
pypika copied to clipboard

SQLite Insert or Ignore

Open marcstreeter opened this issue 3 years ago • 1 comments

While looking into https://github.com/tortoise/tortoise-orm/issues/527 I came upon the question of where there is any way to do the SQLLite query

INSERT OR IGNORE INTO "foo" VALUES (1, 'm')

it seems like the SQLLiteQueryBuilder insert_or_replace is very similar to what is needed. In copying insert_or_replace it depends on the QueryBuilder's replace_sql method . Using this pattern I propose to add a insert_or_ignore method to the SQLLiteQueryBuilder like so

class SQLLiteQueryBuilder(QueryBuilder):
    QUERY_CLS = SQLLiteQuery

    def __init__(self, **kwargs: Any) -> None:
        # ... all the same just concatenating the below line
        self._insert_or_ignore = False

    @builder
    def insert_or_ignore(self, *terms: Any) -> "SQLLiteQueryBuilder":
        self._apply_terms(*terms)
        self._ignore = True  # not sure if this is good to change, seems like it's used elsewhere so maybe not this line
        self._insert_or_ignore = True

    def _ignore_sql(self, **kwargs: Any) -> str:
        prefix = "INSERT OR " if self._insert_or_ignore else ""
        return prefix + super()._ignore_sql(**kwargs)

and then the additional changes to the base QueryBuilder like so

  
class QueryBuilder(Selectable, Term):
   #  ...maybe somewhere close to the `def _replace_sql` I don't know
  def _ignore_sql(self, **kwargs: Any) -> str:
        return "IGNORE INTO {table}".format(
            table=self._insert_table.get_sql(**kwargs),
        )

this would then allow an interaction like so

from pypika import SQLLiteQuery
SQLLiteQuery.into("foo").insert_or_ignore(1, 'm')

and render out to

INSERT OR IGNORE INTO "foo" VALUES (1, 'm')

maybe this is already possible via other mechanisms, pypika is pretty sweet already so please correct me if I'm wrong.

considerations

seems like going this way is kind of wrong. Would it make more sense to override the .ignore method so that it could look like

SQLLiteQuery.into("foo").insert(1, 'm').ignore()

btw this call currently works but I don't think what it outputs is valid SQLLite syntax

INSERT IGNORE INTO "foo" VALUES (1, 'm')

marcstreeter avatar Aug 26 '21 18:08 marcstreeter

I think SQLLiteQuery.ignore() should output INSERT OR IGNORE. I just started using PyPika and immediately ran into this issue, it would be really nice to get it fixed. Thanks!

mchaput avatar Jan 24 '24 16:01 mchaput