mirror of
https://github.com/simonw/sqlite-utils.git
synced 2026-07-23 01:14:31 +02:00
Ability to add descending order indexes (#262)
* DescIndex(column) for descending index columns, refs #260 * Ability to add desc indexes using CLI, closes #260
This commit is contained in:
parent
b2302875c9
commit
51d01da30d
6 changed files with 69 additions and 4 deletions
|
|
@ -1033,6 +1033,14 @@ Use the ``--unique`` option to create a unique index.
|
|||
|
||||
Use ``--if-not-exists`` to avoid attempting to create the index if one with that name already exists.
|
||||
|
||||
To add an index on a column in descending order, prefix the column with a hyphen. Since this can be confused for a command-line option you need to construct that like this::
|
||||
|
||||
$ sqlite-utils create-index mydb.db mytable -- col1 -col2 col3
|
||||
|
||||
This will create an index on that table on ``(col1, col2 desc, col3)``.
|
||||
|
||||
If your column names are already prefixed with a hyphen you'll need to manually execute a ``CREATE INDEX`` SQL statement to add indexes to them rather than using this tool.
|
||||
|
||||
.. _cli_fts:
|
||||
|
||||
Configuring full-text search
|
||||
|
|
|
|||
|
|
@ -1866,6 +1866,17 @@ By default the index will be named ``idx_{table-name}_{columns}`` - if you want
|
|||
index_name="good_dogs_by_age"
|
||||
)
|
||||
|
||||
To create an index in descending order for a column, wrap the column name in ``db.DescIndex()`` like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from sqlite_utils.db import DescIndex
|
||||
|
||||
db["dogs"].create_index(
|
||||
["is_good_dog", DescIndex("age")],
|
||||
index_name="good_dogs_by_age"
|
||||
)
|
||||
|
||||
You can create a unique index by passing ``unique=True``:
|
||||
|
||||
.. code-block:: python
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ from datetime import datetime
|
|||
import hashlib
|
||||
import pathlib
|
||||
import sqlite_utils
|
||||
from sqlite_utils.db import AlterError
|
||||
from sqlite_utils.db import AlterError, DescIndex
|
||||
import textwrap
|
||||
import io
|
||||
import itertools
|
||||
|
|
@ -450,11 +450,21 @@ def index_foreign_keys(path, load_extension):
|
|||
)
|
||||
@load_extension_option
|
||||
def create_index(path, table, column, name, unique, if_not_exists, load_extension):
|
||||
"Add an index to the specified table covering the specified columns"
|
||||
"""
|
||||
Add an index to the specified table covering the specified columns.
|
||||
Use "sqlite-utils create-index mydb -- -column" to specify descending
|
||||
order for a column.
|
||||
"""
|
||||
db = sqlite_utils.Database(path)
|
||||
_load_extensions(db, load_extension)
|
||||
# Treat -prefix as descending for columns
|
||||
columns = []
|
||||
for col in column:
|
||||
if col.startswith("-"):
|
||||
col = DescIndex(col[1:])
|
||||
columns.append(col)
|
||||
db[table].create_index(
|
||||
column, index_name=name, unique=unique, if_not_exists=if_not_exists
|
||||
columns, index_name=name, unique=unique, if_not_exists=if_not_exists
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -144,6 +144,10 @@ class InvalidColumns(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class DescIndex(str):
|
||||
pass
|
||||
|
||||
|
||||
_COUNTS_TABLE_CREATE_SQL = """
|
||||
CREATE TABLE IF NOT EXISTS [{}](
|
||||
[table] TEXT PRIMARY KEY,
|
||||
|
|
@ -1156,6 +1160,13 @@ class Table(Queryable):
|
|||
index_name = "idx_{}_{}".format(
|
||||
self.name.replace(" ", "_"), "_".join(columns)
|
||||
)
|
||||
columns_sql = []
|
||||
for column in columns:
|
||||
if isinstance(column, DescIndex):
|
||||
fmt = "[{}] desc"
|
||||
else:
|
||||
fmt = "[{}]"
|
||||
columns_sql.append(fmt.format(column))
|
||||
sql = (
|
||||
textwrap.dedent(
|
||||
"""
|
||||
|
|
@ -1167,7 +1178,7 @@ class Table(Queryable):
|
|||
.format(
|
||||
index_name=index_name,
|
||||
table_name=self.name,
|
||||
columns=", ".join("[{}]".format(c) for c in columns),
|
||||
columns=", ".join(columns_sql),
|
||||
unique="UNIQUE " if unique else "",
|
||||
if_not_exists="IF NOT EXISTS " if if_not_exists else "",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -208,6 +208,17 @@ def test_create_index(db_path):
|
|||
)
|
||||
|
||||
|
||||
def test_create_index_desc(db_path):
|
||||
db = Database(db_path)
|
||||
assert [] == db["Gosh"].indexes
|
||||
result = CliRunner().invoke(cli.cli, ["create-index", db_path, "Gosh", "--", "-c1"])
|
||||
assert result.exit_code == 0
|
||||
assert (
|
||||
db.execute("select sql from sqlite_master where type='index'").fetchone()[0]
|
||||
== "CREATE INDEX [idx_Gosh_c1]\n ON [Gosh] ([c1] desc)"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"col_name,col_type,expected_schema",
|
||||
(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from sqlite_utils.db import (
|
||||
Index,
|
||||
Database,
|
||||
DescIndex,
|
||||
ForeignKey,
|
||||
AlterError,
|
||||
NoObviousTable,
|
||||
|
|
@ -739,6 +740,19 @@ def test_create_index_if_not_exists(fresh_db):
|
|||
dogs.create_index(["name"], if_not_exists=True)
|
||||
|
||||
|
||||
def test_create_index_desc(fresh_db):
|
||||
dogs = fresh_db["dogs"]
|
||||
dogs.insert({"name": "Cleo", "twitter": "cleopaws", "age": 3, "is good dog": True})
|
||||
assert [] == dogs.indexes
|
||||
dogs.create_index([DescIndex("age"), "name"])
|
||||
sql = fresh_db.execute(
|
||||
"select sql from sqlite_master where name='idx_dogs_age_name'"
|
||||
).fetchone()[0]
|
||||
assert sql == (
|
||||
"CREATE INDEX [idx_dogs_age_name]\n" " ON [dogs] ([age] desc, [name])"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"data_structure",
|
||||
(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue