Skip to content

Commit

Permalink
Python FT.DROPINDEX command (valkey-io#2437)
Browse files Browse the repository at this point in the history
* Python [FT.DROPINDEX] Added command

---------

Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
  • Loading branch information
prateek-kumar-improving authored and avifenesh committed Oct 21, 2024
1 parent 5b468f2 commit 0670a6e
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 48 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#### Changes
* Python: Python FT.DROPINDEX command ([#2437](https://github.com/valkey-io/valkey-glide/pull/2437))
* Python: Python: Added FT.CREATE command([#2413](https://github.com/valkey-io/valkey-glide/pull/2413))
* Python: Add JSON.ARRLEN command ([#2403](https://github.com/valkey-io/valkey-glide/pull/2403))
* Python: Add JSON.CLEAR command ([#2418](https://github.com/valkey-io/valkey-glide/pull/2418))
Expand Down
30 changes: 26 additions & 4 deletions python/python/glide/async_commands/server_modules/ft.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from typing import List, Optional, cast

from glide.async_commands.server_modules.ft_constants import (
from glide.async_commands.server_modules.ft_options.ft_constants import (
CommandNames,
FtCreateKeywords,
)
Expand All @@ -30,10 +30,10 @@ async def create(
client (TGlideClient): The client to execute the command.
indexName (TEncodable): The index name for the index to be created
schema (List[Field]): The fields of the index schema, specifying the fields and their types.
options (Optional[FtCreateOptions]): Optional arguments for the [FT.CREATE] command.
options (Optional[FtCreateOptions]): Optional arguments for the FT.CREATE command. See `FtCreateOptions`.
Returns:
If the index is successfully created, returns "OK".
TOK: A simple "OK" response.
Examples:
>>> from glide.async_commands.server_modules import ft
Expand All @@ -44,7 +44,7 @@ async def create(
>>> prefixes.append("blog:post:")
>>> index = "idx"
>>> result = await ft.create(glide_client, index, schema, FtCreateOptions(DataType.HASH, prefixes))
b'OK' # Indicates successful creation of index named 'idx'
'OK' # Indicates successful creation of index named 'idx'
"""
args: List[TEncodable] = [CommandNames.FT_CREATE, indexName]
if options:
Expand All @@ -54,3 +54,25 @@ async def create(
for field in schema:
args.extend(field.toArgs())
return cast(TOK, await client.custom_command(args))


async def dropindex(client: TGlideClient, indexName: TEncodable) -> TOK:
"""
Drops an index. The index definition and associated content are deleted. Keys are unaffected.
Args:
client (TGlideClient): The client to execute the command.
indexName (TEncodable): The index name for the index to be dropped.
Returns:
TOK: A simple "OK" response.
Examples:
For the following example to work, an index named 'idx' must be already created. If not created, you will get an error.
>>> from glide.async_commands.server_modules import ft
>>> indexName = "idx"
>>> result = await ft.dropindex(glide_client, indexName)
'OK' # Indicates successful deletion/dropping of index named 'idx'
"""
args: List[TEncodable] = [CommandNames.FT_DROPINDEX, indexName]
return cast(TOK, await client.custom_command(args))
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ class CommandNames:
"""

FT_CREATE = "FT.CREATE"
FT_DROPINDEX = "FT.DROPINDEX"


class FtCreateKeywords:
"""
Keywords used in the [FT.CREATE] command statment.
Keywords used in the FT.CREATE command statment.
"""

SCHEMA = "SCHEMA"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from enum import Enum
from typing import List, Optional

from glide.async_commands.server_modules.ft_constants import FtCreateKeywords
from glide.async_commands.server_modules.ft_options.ft_constants import FtCreateKeywords
from glide.constants import TEncodable


Expand Down Expand Up @@ -85,15 +85,15 @@ def __init__(
self,
name: TEncodable,
type: FieldType,
alias: Optional[str] = None,
alias: Optional[TEncodable] = None,
):
"""
Initialize a new field instance.
Args:
name (TEncodable): The name of the field.
type (FieldType): The type of the field.
alias (Optional[str]): An alias for the field.
type (FieldType): The type of the field. See `FieldType`.
alias (Optional[TEncodable]): An alias for the field.
"""
self.name = name
self.type = type
Expand All @@ -119,13 +119,13 @@ class TextField(Field):
Class for defining text fields in a schema.
"""

def __init__(self, name: TEncodable, alias: Optional[str] = None):
def __init__(self, name: TEncodable, alias: Optional[TEncodable] = None):
"""
Initialize a new TextField instance.
Args:
name (TEncodable): The name of the text field.
alias (Optional[str]): An alias for the field.
alias (Optional[TEncodable]): An alias for the field.
"""
super().__init__(name, FieldType.TEXT, alias)

Expand All @@ -148,17 +148,17 @@ class TagField(Field):
def __init__(
self,
name: TEncodable,
alias: Optional[str] = None,
separator: Optional[str] = None,
alias: Optional[TEncodable] = None,
separator: Optional[TEncodable] = None,
case_sensitive: bool = False,
):
"""
Initialize a new TagField instance.
Args:
name (TEncodable): The name of the tag field.
alias (Optional[str]): An alias for the field.
separator (Optional[str]): Specify how text in the attribute is split into individual tags. Must be a single character.
alias (Optional[TEncodable]): An alias for the field.
separator (Optional[TEncodable]): Specify how text in the attribute is split into individual tags. Must be a single character.
case_sensitive (bool): Preserve the original letter cases of tags. If set to False, characters are converted to lowercase by default.
"""
super().__init__(name, FieldType.TAG, alias)
Expand All @@ -185,13 +185,13 @@ class NumericField(Field):
Class for defining the numeric fields in a schema.
"""

def __init__(self, name: TEncodable, alias: Optional[str] = None):
def __init__(self, name: TEncodable, alias: Optional[TEncodable] = None):
"""
Initialize a new NumericField instance.
Args:
name (TEncodable): The name of the numeric field.
alias (Optional[str]): An alias for the field.
alias (Optional[TEncodable]): An alias for the field.
"""
super().__init__(name, FieldType.NUMERIC, alias)

Expand Down Expand Up @@ -219,21 +219,21 @@ def __init__(self, dim: int, distance_metric: DistanceMetricType, type: VectorTy
Args:
dim (int): Number of dimensions in the vector.
distance_metric (DistanceMetricType): The distance metric used in vector type field. Can be one of [L2 | IP | COSINE].
type (VectorType): Vector type. The only supported type is FLOAT32.
type (VectorType): Vector type. The only supported type is FLOAT32. See `VectorType`.
"""
self.dim = dim
self.distance_metric = distance_metric
self.type = type

@abstractmethod
def toArgs(self) -> List[str]:
def toArgs(self) -> List[TEncodable]:
"""
Get the arguments to be used for the algorithm of the vector field.
Returns:
List[str]: A list of arguments.
List[TEncodable]: A list of arguments.
"""
args = []
args: List[TEncodable] = []
if self.dim:
args.extend([FtCreateKeywords.DIM, str(self.dim)])
if self.distance_metric:
Expand All @@ -260,19 +260,19 @@ def __init__(
Args:
dim (int): Number of dimensions in the vector.
distance_metric (DistanceMetricType): The distance metric used in vector type field. Can be one of [L2 | IP | COSINE].
type (VectorType): Vector type. The only supported type is FLOAT32.
distance_metric (DistanceMetricType): The distance metric used in vector type field. Can be one of [L2 | IP | COSINE]. See `DistanceMetricType`.
type (VectorType): Vector type. The only supported type is FLOAT32. See `VectorType`.
initial_cap (Optional[int]): Initial vector capacity in the index affecting memory allocation size of the index. Defaults to 1024.
"""
super().__init__(dim, distance_metric, type)
self.initial_cap = initial_cap

def toArgs(self) -> List[str]:
def toArgs(self) -> List[TEncodable]:
"""
Get the arguments representing the vector field created with FLAT algorithm.
Returns:
List[str]: A list of FLAT algorithm type vector arguments.
List[TEncodable]: A list of FLAT algorithm type vector arguments.
"""
args = super().toArgs()
if self.initial_cap:
Expand Down Expand Up @@ -300,8 +300,8 @@ def __init__(
Args:
dim (int): Number of dimensions in the vector.
distance_metric (DistanceMetricType): The distance metric used in vector type field. Can be one of [L2 | IP | COSINE].
type (VectorType): Vector type. The only supported type is FLOAT32.
distance_metric (DistanceMetricType): The distance metric used in vector type field. Can be one of [L2 | IP | COSINE]. See `DistanceMetricType`.
type (VectorType): Vector type. The only supported type is FLOAT32. See `VectorType`.
initial_cap (Optional[int]): Initial vector capacity in the index affecting memory allocation size of the index. Defaults to 1024.
m (Optional[int]): Number of maximum allowed outgoing edges for each node in the graph in each layer. Default is 16, maximum is 512.
ef_contruction (Optional[int]): Controls the number of vectors examined during index construction. Default value is 200, Maximum value is 4096.
Expand All @@ -313,12 +313,12 @@ def __init__(
self.ef_contruction = ef_contruction
self.ef_runtime = ef_runtime

def toArgs(self) -> List[str]:
def toArgs(self) -> List[TEncodable]:
"""
Get the arguments representing the vector field created with HSNW algorithm.
Returns:
List[str]: A list of HNSW algorithm type vector arguments.
List[TEncodable]: A list of HNSW algorithm type vector arguments.
"""
args = super().toArgs()
if self.initial_cap:
Expand All @@ -342,16 +342,16 @@ def __init__(
name: TEncodable,
algorithm: VectorAlgorithm,
attributes: VectorFieldAttributes,
alias: Optional[str] = None,
alias: Optional[TEncodable] = None,
):
"""
Initialize a new VectorField instance.
Args:
name (TEncodable): The name of the vector field.
algorithm (VectorAlgorithm): The vector indexing algorithm.
alias (Optional[str]): An alias for the field.
attributes (VectorFieldAttributes): Additional attributes to be passed with the vector field after the algorithm name.
algorithm (VectorAlgorithm): The vector indexing algorithm. See `VectorAlgorithm`.
alias (Optional[TEncodable]): An alias for the field.
attributes (VectorFieldAttributes): Additional attributes to be passed with the vector field after the algorithm name. See `VectorFieldAttributes`.
"""
super().__init__(name, FieldType.VECTOR, alias)
self.algorithm = algorithm
Expand Down Expand Up @@ -390,34 +390,34 @@ class DataType(Enum):

class FtCreateOptions:
"""
This class represents the input options to be used in the [FT.CREATE] command.
All fields in this class are optional inputs for [FT.CREATE].
This class represents the input options to be used in the FT.CREATE command.
All fields in this class are optional inputs for FT.CREATE.
"""

def __init__(
self,
data_type: Optional[DataType] = None,
prefixes: Optional[List[str]] = None,
prefixes: Optional[List[TEncodable]] = None,
):
"""
Initialize the [FT.CREATE] optional fields.
Initialize the FT.CREATE optional fields.
Args:
data_type (Optional[DataType]): The type of data to be indexed using [FT.CREATE].
prefixes (Optional[List[str]]): The prefix of the key to be indexed.
data_type (Optional[DataType]): The type of data to be indexed using FT.CREATE. See `DataType`.
prefixes (Optional[List[TEncodable]]): The prefix of the key to be indexed.
"""
self.data_type = data_type
self.prefixes = prefixes

def toArgs(self) -> List[str]:
def toArgs(self) -> List[TEncodable]:
"""
Get the optional arguments for the [FT.CREATE] command.
Get the optional arguments for the FT.CREATE command.
Returns:
List[str]:
List of [FT.CREATE] optional agruments.
List[TEncodable]:
List of FT.CREATE optional agruments.
"""
args = []
args: List[TEncodable] = []
if self.data_type:
args.append(FtCreateKeywords.ON)
args.append(self.data_type.value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@
VectorType,
)
from glide.config import ProtocolVersion
from glide.constants import OK
from glide.constants import OK, TEncodable
from glide.glide_client import GlideClusterClient


@pytest.mark.asyncio
class TestVss:
class TestFtCreate:
@pytest.mark.parametrize("cluster_mode", [True])
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
async def test_vss_create(self, glide_client: GlideClusterClient):
async def test_ft_create(self, glide_client: GlideClusterClient):
fields: List[Field] = []
textFieldTitle: TextField = TextField("$title")
numberField: NumericField = NumericField("$published_at")
Expand All @@ -34,7 +34,7 @@ async def test_vss_create(self, glide_client: GlideClusterClient):
fields.append(numberField)
fields.append(textFieldCategory)

prefixes: List[str] = []
prefixes: List[TEncodable] = []
prefixes.append("blog:post:")

# Create an index with multiple fields with Hash data type.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import uuid
from typing import List

import pytest
from glide.async_commands.server_modules import ft
from glide.async_commands.server_modules.ft_options.ft_create_options import (
DataType,
Field,
FtCreateOptions,
TextField,
)
from glide.config import ProtocolVersion
from glide.constants import OK, TEncodable
from glide.exceptions import RequestError
from glide.glide_client import GlideClusterClient


@pytest.mark.asyncio
class TestFtDropIndex:
@pytest.mark.parametrize("cluster_mode", [True])
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
async def test_ft_dropindex(self, glide_client: GlideClusterClient):
# Index name for the index to be dropped.
indexName = str(uuid.uuid4())

fields: List[Field] = []
textFieldTitle: TextField = TextField("$title")
fields.append(textFieldTitle)
prefixes: List[TEncodable] = []
prefixes.append("blog:post:")

# Create an index with multiple fields with Hash data type.
result = await ft.create(
glide_client, indexName, fields, FtCreateOptions(DataType.HASH, prefixes)
)
assert result == OK

# Drop the index. Expects "OK" as a response.
result = await ft.dropindex(glide_client, indexName)
assert result == OK

# Drop a non existent index. Expects a RequestError.
with pytest.raises(RequestError):
await ft.dropindex(glide_client, indexName)

0 comments on commit 0670a6e

Please sign in to comment.