Skip to content

Commit f002ce9

Browse files
authored
Merge pull request #1 from redis-developer/feat/redisvl-integration-tests
Minor update -> testing with redisvl
2 parents 353d031 + 623057f commit f002ce9

24 files changed

Lines changed: 1997 additions & 544 deletions

.github/workflows/lint.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: Lint
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
9+
env:
10+
UV_VERSION: "0.7.13"
11+
12+
jobs:
13+
check:
14+
name: Style-check ${{ matrix.python-version }}
15+
runs-on: ubuntu-latest
16+
strategy:
17+
matrix:
18+
python-version:
19+
- "3.9"
20+
- "3.11"
21+
- "3.13"
22+
23+
steps:
24+
- name: Check out repository
25+
uses: actions/checkout@v4
26+
27+
- name: Install Python
28+
uses: actions/setup-python@v5
29+
with:
30+
python-version: ${{ matrix.python-version }}
31+
32+
- name: Install uv
33+
uses: astral-sh/setup-uv@v4
34+
with:
35+
version: ${{ env.UV_VERSION }}
36+
enable-cache: true
37+
python-version: ${{ matrix.python-version }}
38+
cache-dependency-glob: |
39+
pyproject.toml
40+
uv.lock
41+
42+
- name: Install dependencies
43+
run: |
44+
uv sync --frozen
45+
46+
- name: check-sort-import
47+
run: |
48+
make check-sort-imports
49+
50+
- name: check-black-format
51+
run: |
52+
make check-format
53+
54+
- name: check-mypy
55+
run: |
56+
make check-types
57+

.github/workflows/test.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: Test Suite
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
workflow_dispatch:
9+
10+
env:
11+
UV_VERSION: "0.7.13"
12+
13+
jobs:
14+
test:
15+
name: Python ${{ matrix.python-version }}
16+
runs-on: ubuntu-latest
17+
strategy:
18+
fail-fast: false
19+
matrix:
20+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
21+
22+
steps:
23+
- name: Check out repository
24+
uses: actions/checkout@v4
25+
26+
- name: Install Python
27+
uses: actions/setup-python@v5
28+
with:
29+
python-version: ${{ matrix.python-version }}
30+
31+
- name: Install uv
32+
uses: astral-sh/setup-uv@v4
33+
with:
34+
version: ${{ env.UV_VERSION }}
35+
enable-cache: true
36+
python-version: ${{ matrix.python-version }}
37+
cache-dependency-glob: |
38+
pyproject.toml
39+
uv.lock
40+
41+
- name: Install dependencies
42+
run: |
43+
uv sync
44+
45+
- name: Run tests
46+
run: |
47+
make test
48+

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ wheels/
1919
*.egg-info/
2020
.installed.cfg
2121
*.egg
22+
.python-version
2223

2324
# Virtual environments
2425
.venv/

.pre-commit-config.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
repos:
2+
- repo: local
3+
hooks:
4+
- id: code-quality-checks
5+
name: Run pre-commit checks (format, sort-imports, check-mypy)
6+
entry: bash -c 'make format && make check-sort-imports && make check-types'
7+
language: system
8+
pass_filenames: false
9+
- repo: https://github.com/codespell-project/codespell
10+
rev: v2.2.6
11+
hooks:
12+
- id: codespell
13+
name: Check spelling
14+
args:
15+
- --write-changes
16+
- --skip=*.pyc,*.pyo,*.lock,*.git,*.mypy_cache,__pycache__,*.egg-info,.pytest_cache,env,venv,.venv
17+

Makefile

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
.PHONY: install format lint test clean check-types check-format check-sort-imports sort-imports build help
2+
.DEFAULT_GOAL := help
3+
4+
# Allow passing arguments to make targets (e.g., make test ARGS="...")
5+
ARGS ?=
6+
7+
install: ## Install the project and all dependencies
8+
@echo "🚀 Installing project dependencies with uv"
9+
uv sync
10+
11+
format: ## Format code with isort and black
12+
@echo "🎨 Formatting code"
13+
uv run isort ./sql_redis ./tests/ --profile black
14+
uv run black ./sql_redis ./tests/
15+
16+
check-format: ## Check code formatting
17+
@echo "🔍 Checking code formatting"
18+
uv run black --check ./sql_redis ./tests/
19+
20+
sort-imports: ## Sort imports with isort
21+
@echo "📦 Sorting imports"
22+
uv run isort ./sql_redis ./tests/ --profile black
23+
24+
check-sort-imports: ## Check import sorting
25+
@echo "🔍 Checking import sorting"
26+
uv run isort ./sql_redis ./tests/ --check-only --profile black
27+
28+
check-types: ## Run mypy type checking
29+
@echo "🔍 Running mypy type checking"
30+
uv run python -m mypy ./sql_redis
31+
32+
lint: format check-types ## Run all linting (format + type check)
33+
34+
test: ## Run tests (pass extra args with ARGS="...")
35+
@echo "🧪 Running tests"
36+
uv run python -m pytest $(ARGS)
37+
38+
test-verbose: ## Run tests with verbose output
39+
@echo "🧪 Running tests (verbose)"
40+
uv run python -m pytest -vv -s $(ARGS)
41+
42+
test-cov: ## Run tests with coverage report
43+
@echo "🧪 Running tests with coverage"
44+
uv run python -m pytest --cov=sql_redis --cov-report=term-missing --cov-report=html $(ARGS)
45+
46+
check: lint test ## Run all checks (lint + test)
47+
48+
build: ## Build wheel and source distribution
49+
@echo "🏗️ Building distribution packages"
50+
uv build
51+
52+
clean: ## Clean up build artifacts and caches
53+
@echo "🧹 Cleaning up directory"
54+
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
55+
find . -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true
56+
find . -type d -name ".mypy_cache" -exec rm -rf {} + 2>/dev/null || true
57+
find . -type d -name ".coverage" -delete 2>/dev/null || true
58+
find . -type d -name "htmlcov" -exec rm -rf {} + 2>/dev/null || true
59+
find . -type d -name "dist" -exec rm -rf {} + 2>/dev/null || true
60+
find . -type d -name "build" -exec rm -rf {} + 2>/dev/null || true
61+
find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
62+
find . -type f -name "*.log" -exec rm -rf {} + 2>/dev/null || true
63+
64+
help: ## Show this help message
65+
@echo "Available commands:"
66+
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}'
67+

pyproject.toml

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,77 @@
22
name = "sql-redis"
33
version = "0.1.0"
44
description = "SQL to Redis command translation utility"
5-
requires-python = ">=3.11"
5+
authors = [{ name = "Redis Inc.", email = "applied.ai@redis.com" }]
6+
requires-python = ">=3.9,<3.14"
7+
readme = "README.md"
8+
license = "MIT"
9+
keywords = [
10+
"sql",
11+
"redis",
12+
"redis-client",
13+
"query-translation",
14+
]
15+
classifiers = [
16+
"Programming Language :: Python :: 3.9",
17+
"Programming Language :: Python :: 3.10",
18+
"Programming Language :: Python :: 3.11",
19+
"Programming Language :: Python :: 3.12",
20+
"Programming Language :: Python :: 3.13",
21+
"License :: OSI Approved :: MIT License",
22+
]
623
dependencies = [
724
"redis>=5.0.0",
825
"sqlglot>=26.0.0",
926
]
1027

11-
[project.optional-dependencies]
12-
dev = [
13-
"pytest>=8.0.0",
14-
"pytest-cov>=4.0.0",
15-
"testcontainers[redis]>=4.0.0",
16-
]
28+
[project.urls]
29+
Homepage = "https://github.com/redis/sql-redis"
30+
Repository = "https://github.com/redis/sql-redis"
1731

1832
[build-system]
1933
requires = ["hatchling"]
2034
build-backend = "hatchling.build"
2135

22-
[tool.pytest.ini_options]
23-
testpaths = ["tests"]
24-
addopts = "--cov=sql_redis --cov-report=term-missing"
36+
[dependency-groups]
37+
dev = [
38+
"black>=25.1.0,<26",
39+
"isort>=5.6.4,<6",
40+
"mypy>=1.11.0,<2",
41+
"pytest>=8.0.0,<9",
42+
"pytest-cov>=4.0.0,<5",
43+
"pytest-asyncio>=0.23.6,<0.24",
44+
"pre-commit>=4.1.0,<5",
45+
"codespell>=2.4.1,<3",
46+
"testcontainers[redis]>=4.0.0,<5",
47+
]
2548

26-
[tool.coverage.run]
27-
source = ["sql_redis"]
28-
branch = true
49+
[tool.uv]
50+
default-groups = ["dev"]
2951

30-
[tool.coverage.report]
31-
exclude_lines = [
32-
"pragma: no cover",
33-
"raise NotImplementedError",
34-
]
52+
[tool.black]
53+
target-version = ['py39', 'py310', 'py311', 'py312', 'py313']
54+
exclude = '''
55+
(
56+
| \.egg
57+
| \.git
58+
| \.hg
59+
| \.mypy_cache
60+
| \.nox
61+
| \.tox
62+
| \.venv
63+
| _build
64+
| build
65+
| dist
66+
| setup.py
67+
)
68+
'''
69+
70+
[tool.pytest.ini_options]
71+
log_cli = true
72+
asyncio_mode = "auto"
73+
74+
[tool.mypy]
75+
warn_unused_configs = true
76+
ignore_missing_imports = true
77+
exclude = ["env", "venv", ".venv"]
3578

sql_redis/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""SQL to Redis command translation utility."""
22

3-
from sql_redis.translator import Translator, TranslatedQuery
3+
from sql_redis.translator import TranslatedQuery, Translator
44

55
__all__ = ["Translator", "TranslatedQuery"]
6-

sql_redis/analyzer.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
"""SQL analyzer component - resolves field types from schema."""
22

3+
from __future__ import annotations
4+
35
from dataclasses import dataclass, field
46

5-
from sql_redis.parser import ParsedQuery, AggregationSpec, ComputedField, Condition
7+
from sql_redis.parser import AggregationSpec, ComputedField, Condition, ParsedQuery
68

79

810
@dataclass
911
class VectorSearchAnalysis:
1012
"""Analyzed vector search details."""
13+
1114
field: str
1215
k: int
1316
alias: str
@@ -16,7 +19,7 @@ class VectorSearchAnalysis:
1619
@dataclass
1720
class AnalyzedQuery:
1821
"""Result of analyzing a parsed SQL query with schema context."""
19-
22+
2023
parsed: ParsedQuery = field(default_factory=ParsedQuery)
2124
field_types: dict[str, str] = field(default_factory=dict)
2225
aggregations: list[AggregationSpec] = field(default_factory=list)
@@ -25,15 +28,16 @@ class AnalyzedQuery:
2528
is_global_aggregation: bool = False
2629
vector_search: VectorSearchAnalysis | None = None
2730
has_prefilter: bool = False
28-
31+
2932
def get_field_type(self, field_name: str) -> str | None:
3033
"""Get the type of a field."""
3134
return self.field_types.get(field_name)
32-
35+
3336
def get_conditions_by_type(self, field_type: str) -> list[Condition]:
3437
"""Get conditions for fields of a specific type."""
3538
return [
36-
c for c in self.parsed.conditions
39+
c
40+
for c in self.parsed.conditions
3741
if self.field_types.get(c.field) == field_type
3842
]
3943

@@ -127,4 +131,3 @@ def analyze(self, parsed: ParsedQuery) -> AnalyzedQuery:
127131
result.has_prefilter = len(parsed.conditions) > 0
128132

129133
return result
130-

sql_redis/executor.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""SQL Executor - executes translated queries against Redis."""
22

3+
from __future__ import annotations
4+
35
from dataclasses import dataclass
46

57
import redis
@@ -25,9 +27,7 @@ def __init__(self, client: redis.Redis, schema_registry: SchemaRegistry):
2527
self._schema_registry = schema_registry
2628
self._translator = Translator(schema_registry)
2729

28-
def execute(
29-
self, sql: str, *, params: dict | None = None
30-
) -> QueryResult:
30+
def execute(self, sql: str, *, params: dict | None = None) -> QueryResult:
3131
"""Execute a SQL query and return results."""
3232
params = params or {}
3333

@@ -44,10 +44,11 @@ def execute(
4444
translated = self._translator.translate(sql)
4545

4646
# Build command list and substitute vector params
47-
cmd = list(translated.to_command_list())
47+
# Use list[str | bytes] to allow bytes for vector params
48+
cmd: list[str | bytes] = list(translated.to_command_list())
4849

4950
# Find any bytes params (vectors) to substitute
50-
vector_param = None
51+
vector_param: bytes | None = None
5152
for value in params.values():
5253
if isinstance(value, bytes):
5354
vector_param = value
@@ -80,4 +81,3 @@ def execute(
8081
rows.append(row)
8182

8283
return QueryResult(rows=rows, count=count)
83-

0 commit comments

Comments
 (0)