Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,10 @@ clean_infra:

run_tests: tests

build_sync:
run_unasync:
poetry run unasync postgrest tests

build_sync: run_unasync remove_pytest_asyncio_from_sync

remove_pytest_asyncio_from_sync:
sed -i 's/@pytest.mark.asyncio//g' tests/_sync/test_client.py
18 changes: 18 additions & 0 deletions postgrest/base_request_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,24 @@ def nxr(self: Self, column: str, range: Tuple[int, int]) -> Self:
def adj(self: Self, column: str, range: Tuple[int, int]) -> Self:
return self.filter(column, Filters.ADJ, f"({range[0]},{range[1]})")

def range_gt(self: Self, column: str, range: Tuple[int, int]) -> Self:
return self.sr(column, range)

def range_gte(self: Self, column: str, range: Tuple[int, int]) -> Self:
return self.nxl(column, range)

def range_lt(self: Self, column: str, range: Tuple[int, int]) -> Self:
return self.sl(column, range)

def range_lte(self: Self, column: str, range: Tuple[int, int]) -> Self:
return self.nxr(column, range)

def range_adjacent(self: Self, column: str, range: Tuple[int, int]) -> Self:
return self.adj(column, range)

def overlaps(self: Self, column: str, values: Iterable[Any]) -> Self:
return self.ov(column, values)

def match(self: Self, query: Dict[str, Any]) -> Self:
updated_query = self

Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ upload_to_vcs_release = true
branch = "master"
changelog_components = "semantic_release.changelog.changelog_headers,semantic_release.changelog.compare_url"

[tool.pytest.ini_options]
asyncio_mode = "auto"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
100 changes: 100 additions & 0 deletions tests/_async/test_filter_request_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,24 @@ def test_equals(filter_request_builder):
assert str(builder.params) == "x=eq.a"


def test_not_equal(filter_request_builder):
builder = filter_request_builder.neq("x", "a")

assert str(builder.params) == "x=neq.a"


def test_greater_than(filter_request_builder):
builder = filter_request_builder.gt("x", "a")

assert str(builder.params) == "x=gt.a"


def test_greater_than_or_equals_to(filter_request_builder):
builder = filter_request_builder.gte("x", "a")

assert str(builder.params) == "x=gte.a"


def test_contains(filter_request_builder):
builder = filter_request_builder.contains("x", "a")

Expand Down Expand Up @@ -100,3 +118,85 @@ def test_contained_by_mixed_items(filter_request_builder):

# {a,["b",%20"c"]}
assert str(builder.params) == "x=cd.%7Ba%2C%5B%22b%22%2C%20%22c%22%5D%7D"


def test_range_greater_than(filter_request_builder):
builder = filter_request_builder.range_gt(
"x", ["2000-01-02 08:30", "2000-01-02 09:30"]
)

# {a,["b",%20"c"]}
assert str(builder.params) == "x=sr.%282000-01-02%2008%3A30%2C2000-01-02%2009%3A30%29"


def test_range_greater_than_or_equal_to(filter_request_builder):
builder = filter_request_builder.range_gte(
"x", ["2000-01-02 08:30", "2000-01-02 09:30"]
)

# {a,["b",%20"c"]}
assert (
str(builder.params) == "x=nxl.%282000-01-02%2008%3A30%2C2000-01-02%2009%3A30%29"
)


def test_range_less_than(filter_request_builder):
builder = filter_request_builder.range_lt(
"x", ["2000-01-02 08:30", "2000-01-02 09:30"]
)

# {a,["b",%20"c"]}
assert str(builder.params) == "x=sl.%282000-01-02%2008%3A30%2C2000-01-02%2009%3A30%29"


def test_range_less_than_or_equal_to(filter_request_builder):
builder = filter_request_builder.range_lte(
"x", ["2000-01-02 08:30", "2000-01-02 09:30"]
)

# {a,["b",%20"c"]}
assert (
str(builder.params) == "x=nxr.%282000-01-02%2008%3A30%2C2000-01-02%2009%3A30%29"
)


def test_range_adjacent(filter_request_builder):
builder = filter_request_builder.range_adjacent(
"x", ["2000-01-02 08:30", "2000-01-02 09:30"]
)

# {a,["b",%20"c"]}
assert (
str(builder.params) == "x=adj.%282000-01-02%2008%3A30%2C2000-01-02%2009%3A30%29"
)


def test_overlaps(filter_request_builder):
builder = filter_request_builder.overlaps("x", ["is:closed", "severity:high"])

# {a,["b",%20"c"]}
assert str(builder.params) == "x=ov.%7Bis%3Aclosed%2Cseverity%3Ahigh%7D"


def test_like(filter_request_builder):
builder = filter_request_builder.like("x", "%a%")

assert str(builder.params) == "x=like.%25a%25"


def test_ilike(filter_request_builder):
builder = filter_request_builder.ilike("x", "%a%")

assert str(builder.params) == "x=ilike.%25a%25"


def test_is_(filter_request_builder):
builder = filter_request_builder.is_("x", "a")

assert str(builder.params) == "x=is.a"


def test_in_(filter_request_builder):
builder = filter_request_builder.in_("x", ["a", "b"])

assert str(builder.params) == "x=in.%28a%2Cb%29"
4 changes: 0 additions & 4 deletions tests/_sync/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ def test_simple(self, postgrest_client: SyncPostgrestClient):
)
assert session.headers.items() >= headers.items()

@pytest.mark.asyncio
def test_custom_headers(self):
with SyncPostgrestClient(
"https://example.com", schema="pub", headers={"Custom-Header": "value"}
Expand Down Expand Up @@ -72,15 +71,13 @@ def test_schema(postgrest_client: SyncPostgrestClient):
assert subheaders.items() < dict(session.headers).items()


@pytest.mark.asyncio
def test_params_purged_after_execute(postgrest_client: SyncPostgrestClient):
assert len(postgrest_client.session.params) == 0
with pytest.raises(APIError):
postgrest_client.from_("test").select("a", "b").eq("c", "d").execute()
assert len(postgrest_client.session.params) == 0


@pytest.mark.asyncio
def test_response_status_code_outside_ok(postgrest_client: SyncPostgrestClient):
with pytest.raises(APIError) as exc_info:
postgrest_client.from_("test").select("a", "b").eq(
Expand All @@ -96,7 +93,6 @@ def test_response_status_code_outside_ok(postgrest_client: SyncPostgrestClient):
assert exc_response["errors"][0].get("code") == 400


@pytest.mark.asyncio
def test_response_maybe_single(postgrest_client: SyncPostgrestClient):
with patch(
"postgrest._async.request_builder.AsyncSingleRequestBuilder.execute",
Expand Down
100 changes: 100 additions & 0 deletions tests/_sync/test_filter_request_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,24 @@ def test_equals(filter_request_builder):
assert str(builder.params) == "x=eq.a"


def test_not_equal(filter_request_builder):
builder = filter_request_builder.neq("x", "a")

assert str(builder.params) == "x=neq.a"


def test_greater_than(filter_request_builder):
builder = filter_request_builder.gt("x", "a")

assert str(builder.params) == "x=gt.a"


def test_greater_than_or_equals_to(filter_request_builder):
builder = filter_request_builder.gte("x", "a")

assert str(builder.params) == "x=gte.a"


def test_contains(filter_request_builder):
builder = filter_request_builder.contains("x", "a")

Expand Down Expand Up @@ -100,3 +118,85 @@ def test_contained_by_mixed_items(filter_request_builder):

# {a,["b",%20"c"]}
assert str(builder.params) == "x=cd.%7Ba%2C%5B%22b%22%2C%20%22c%22%5D%7D"


def test_range_greater_than(filter_request_builder):
builder = filter_request_builder.range_gt(
"x", ["2000-01-02 08:30", "2000-01-02 09:30"]
)

# {a,["b",%20"c"]}
assert str(builder.params) == "x=sr.%282000-01-02%2008%3A30%2C2000-01-02%2009%3A30%29"


def test_range_greater_than_or_equal_to(filter_request_builder):
builder = filter_request_builder.range_gte(
"x", ["2000-01-02 08:30", "2000-01-02 09:30"]
)

# {a,["b",%20"c"]}
assert (
str(builder.params) == "x=nxl.%282000-01-02%2008%3A30%2C2000-01-02%2009%3A30%29"
)


def test_range_less_than(filter_request_builder):
builder = filter_request_builder.range_lt(
"x", ["2000-01-02 08:30", "2000-01-02 09:30"]
)

# {a,["b",%20"c"]}
assert str(builder.params) == "x=sl.%282000-01-02%2008%3A30%2C2000-01-02%2009%3A30%29"


def test_range_less_than_or_equal_to(filter_request_builder):
builder = filter_request_builder.range_lte(
"x", ["2000-01-02 08:30", "2000-01-02 09:30"]
)

# {a,["b",%20"c"]}
assert (
str(builder.params) == "x=nxr.%282000-01-02%2008%3A30%2C2000-01-02%2009%3A30%29"
)


def test_range_adjacent(filter_request_builder):
builder = filter_request_builder.range_adjacent(
"x", ["2000-01-02 08:30", "2000-01-02 09:30"]
)

# {a,["b",%20"c"]}
assert (
str(builder.params) == "x=adj.%282000-01-02%2008%3A30%2C2000-01-02%2009%3A30%29"
)


def test_overlaps(filter_request_builder):
builder = filter_request_builder.overlaps("x", ["is:closed", "severity:high"])

# {a,["b",%20"c"]}
assert str(builder.params) == "x=ov.%7Bis%3Aclosed%2Cseverity%3Ahigh%7D"


def test_like(filter_request_builder):
builder = filter_request_builder.like("x", "%a%")

assert str(builder.params) == "x=like.%25a%25"


def test_ilike(filter_request_builder):
builder = filter_request_builder.ilike("x", "%a%")

assert str(builder.params) == "x=ilike.%25a%25"


def test_is_(filter_request_builder):
builder = filter_request_builder.is_("x", "a")

assert str(builder.params) == "x=is.a"


def test_in_(filter_request_builder):
builder = filter_request_builder.in_("x", ["a", "b"])

assert str(builder.params) == "x=in.%28a%2Cb%29"