From 6bff93ca1274e8470431e90e2ad214512ca9c3d0 Mon Sep 17 00:00:00 2001 From: zhao vistart Date: Sun, 8 Nov 2026 19:28:31 +0800 Subject: [PATCH 1/6] feat(postgres): render seconds_between as EXTRACT(EPOCH) --- .../postgres_specific_features/dialect.md | 54 +++++ .../postgres_specific_features/dialect.md | 21 +- .../backend/impl/postgres/mixins/datetime.py | 25 ++- .../postgres/test_postgres_seconds_between.py | 195 ++++++++++++++++++ 4 files changed, 292 insertions(+), 3 deletions(-) create mode 100644 tests/rhosocial/activerecord_postgres_test/feature/backend/postgres/test_postgres_seconds_between.py diff --git a/docs/en_US/postgres_specific_features/dialect.md b/docs/en_US/postgres_specific_features/dialect.md index 979d6a3f..8c006d67 100644 --- a/docs/en_US/postgres_specific_features/dialect.md +++ b/docs/en_US/postgres_specific_features/dialect.md @@ -279,3 +279,57 @@ Product.query().where("attributes ? 'brand'", ()) ``` 💡 *AI Prompt:* "How do PostgreSQL's ILIKE and standard LIKE differ in performance?" + +## Date/Time Interval Expressions + +PostgreSQL renders the temporal expression nodes with the standard spellings +(`EXTRACT`, `DATE_TRUNC` and `INTERVAL`): + +```python +from rhosocial.activerecord.backend.expression import Column +from rhosocial.activerecord.backend.expression.functions import ( + date_add, date_diff, date_trunc, extract, +) + +expr = extract(dialect, "year", Column(dialect, "created_at")) +# Generates: EXTRACT(YEAR FROM "created_at") + +expr = date_trunc(dialect, "month", Column(dialect, "created_at")) +# Generates: DATE_TRUNC('month', "created_at") + +expr = date_add(dialect, Column(dialect, "created_at"), 30, "day") +# Generates: "created_at" + INTERVAL '30' DAY + +expr = date_diff( + dialect, "day", Column(dialect, "started_at"), Column(dialect, "ended_at") +) +# Generates: (EXTRACT(EPOCH FROM ("ended_at" - "started_at")) / 86400) +``` + +`date_diff` counts whole units crossed. To measure elapsed time as a signed, +fractional number of seconds, use `seconds_between`: + +```python +from rhosocial.activerecord.backend.expression import Column, seconds_between + +elapsed = seconds_between( + dialect, + Column(dialect, "queued_at"), + Column(dialect, "started_at"), +).as_("queue_seconds") +# Generates: EXTRACT(EPOCH FROM ("started_at" - "queued_at")) AS "queue_seconds" +``` + +The result is always `end - start` in seconds: + +| Case | Result | +|------|--------| +| `end` later than `start` | positive | +| `end` earlier than `start` | negative | +| same instant | `0` | +| a sub-second difference | the fraction is kept | + +`EXTRACT(EPOCH FROM interval)` returns a PostgreSQL `numeric`, so the value +keeps the microseconds stored in the timestamp; round it explicitly if whole +seconds are wanted. `started_at.seconds_between(ended_at)` asks the same +question from a timestamp column. diff --git a/docs/zh_CN/postgres_specific_features/dialect.md b/docs/zh_CN/postgres_specific_features/dialect.md index 577dec28..aa596b81 100644 --- a/docs/zh_CN/postgres_specific_features/dialect.md +++ b/docs/zh_CN/postgres_specific_features/dialect.md @@ -324,12 +324,31 @@ expr = DatetimeAddExpression(dialect, Column(dialect, "created_at"), IntervalExpression(dialect, 30, IntervalUnit.DAY)) # 生成: "created_at" + INTERVAL '30' DAY -# 日期差 +# 日期差(按整天计数) expr = DatetimeDiffExpression(dialect, DateTimeField.DAY, Column(dialect, "start"), Column(dialect, "end")) # 生成: EXTRACT(EPOCH FROM "end" - "start") / 86400 ``` +`date_diff` 按指定的整数单位计数。如果需要带符号、保留小数的秒数,使用 +`seconds_between`: + +```python +from rhosocial.activerecord.backend.expression import Column, seconds_between + +elapsed = seconds_between( + dialect, + Column(dialect, "queued_at"), + Column(dialect, "started_at"), +).as_("queue_seconds") +# 生成: EXTRACT(EPOCH FROM ("started_at" - "queued_at")) AS "queue_seconds" +``` + +结果始终是 `end - start` 的秒数:`end` 晚于 `start` 为正,早于 `start` 为负, +同一时刻为 `0`。PostgreSQL 的 `EXTRACT(EPOCH FROM interval)` 返回 `numeric`, +因此时间戳中的微秒部分会保留;需要整数秒时请调用方显式取整。 +`started_at.seconds_between(ended_at)` 在时间戳列上提出同一个问题。 + ## SQL/XML 标准表达式 PostgreSQL 支持 SQL/XML 标准表达式(PG 8.3+): diff --git a/src/rhosocial/activerecord/backend/impl/postgres/mixins/datetime.py b/src/rhosocial/activerecord/backend/impl/postgres/mixins/datetime.py index 5f0ddc6b..05d510c8 100644 --- a/src/rhosocial/activerecord/backend/impl/postgres/mixins/datetime.py +++ b/src/rhosocial/activerecord/backend/impl/postgres/mixins/datetime.py @@ -4,11 +4,14 @@ from typing import Tuple, TYPE_CHECKING if TYPE_CHECKING: - from rhosocial.activerecord.backend.expression.datetime import DatetimeDiffExpression + from rhosocial.activerecord.backend.expression.datetime import ( + DatetimeDiffExpression, + SecondsBetweenExpression, + ) class PostgresDateTimeMixin: - """PostgreSQL datetime diff expression formatting.""" + """PostgreSQL datetime diff and elapsed-seconds formatting.""" def format_datetime_diff_expression(self, expr: "DatetimeDiffExpression") -> Tuple[str, tuple]: start_sql, start_params = expr.start.to_sql() @@ -39,3 +42,21 @@ def format_datetime_diff_expression(self, expr: "DatetimeDiffExpression") -> Tup ) params = end_params + start_params return self.apply_alias(sql, params, expr) + + def format_seconds_between_expression( + self, expr: "SecondsBetweenExpression" + ) -> Tuple[str, tuple]: + """Render signed, fractional seconds from ``start`` to ``end``. + + ``EXTRACT(EPOCH FROM interval)`` is a ``numeric``, so the subtraction + keeps microseconds and the sign is whatever ``end - start`` yields: + an end before the start is negative, equal instants are exactly zero. + + The SQL writes ``end`` first, so its bind parameters are collected + first as well -- bind order follows the SQL, not the constructor's + argument order. + """ + start_sql, start_params = expr.start.to_sql() + end_sql, end_params = expr.end.to_sql() + sql = f"EXTRACT(EPOCH FROM ({end_sql} - {start_sql}))" + return self.apply_alias(sql, end_params + start_params, expr) diff --git a/tests/rhosocial/activerecord_postgres_test/feature/backend/postgres/test_postgres_seconds_between.py b/tests/rhosocial/activerecord_postgres_test/feature/backend/postgres/test_postgres_seconds_between.py new file mode 100644 index 00000000..c921f787 --- /dev/null +++ b/tests/rhosocial/activerecord_postgres_test/feature/backend/postgres/test_postgres_seconds_between.py @@ -0,0 +1,195 @@ +# tests/rhosocial/activerecord_postgres_test/feature/backend/postgres/ +# test_postgres_seconds_between.py +"""Signed, fractional seconds between two instants on PostgreSQL. + +What matters here is what a calendar-component sum gets wrong: the sign, +the zero, the fraction, and the boundaries where a month or a year changes. +``EXTRACT(EPOCH FROM (end - start))`` is a ``numeric``, so the value keeps the +microseconds PostgreSQL stores and turns negative when the end is earlier. +""" + +import pytest + +from rhosocial.activerecord.backend.expression import ( + Column, + Literal, + QueryStatement, + seconds_between, +) +from rhosocial.activerecord.backend.expression.datetime import SecondsBetweenExpression +from rhosocial.activerecord.backend.expression.value_types import NumericValue +from rhosocial.activerecord.backend.options import ExecutionOptions +from rhosocial.activerecord.backend.schema import StatementType + +_SPANS = [ + ("2026-06-04 10:00:00", "2026-06-04 10:00:00", 0.0), + ("2026-06-04 10:00:00", "2026-06-04 11:00:00", 3600.0), + ("2026-06-04 11:00:00", "2026-06-04 10:00:00", -3600.0), + ("2026-01-31 23:59:59", "2026-02-01 00:00:00", 1.0), + ("2025-12-31 12:00:00", "2026-01-01 12:00:00", 86400.0), + ("2026-06-04 10:00:00.000", "2026-06-04 10:00:00.500", 0.5), + ("2026-06-04 10:00:00.250", "2026-06-04 10:00:00.000", -0.25), +] + +_TABLE = "postgres_seconds_between_spans" + + +def _setup_statements() -> list: + statements = [f"DROP TABLE IF EXISTS {_TABLE} CASCADE"] + statements.append( + f""" + CREATE TABLE {_TABLE} ( + id INTEGER PRIMARY KEY, + started_at TIMESTAMP NOT NULL, + ended_at TIMESTAMP NOT NULL + ) + """ + ) + for index, (start, end, _) in enumerate(_SPANS, start=1): + statements.append( + f"INSERT INTO {_TABLE} (id, started_at, ended_at) VALUES " + f"({index}, TIMESTAMP '{start}', TIMESTAMP '{end}')" + ) + return statements + + +_CLEANUP = f"DROP TABLE IF EXISTS {_TABLE} CASCADE" +_DQL_OPTIONS = ExecutionOptions(stmt_type=StatementType.DQL) + + +def _seconds_query(dialect) -> QueryStatement: + return QueryStatement( + dialect, + select=[ + seconds_between( + dialect, + Column(dialect, "started_at"), + Column(dialect, "ended_at"), + ).as_("seconds"), + Column(dialect, "id"), + ], + from_=_TABLE, + ) + + +class TestPostgresSecondsBetweenExpression: + """The SQL PostgreSQL renders for the node.""" + + def test_columns(self, postgres_dialect): + expr = seconds_between( + postgres_dialect, + Column(postgres_dialect, "started_at"), + Column(postgres_dialect, "ended_at"), + ) + + sql, params = expr.to_sql() + + assert sql == 'EXTRACT(EPOCH FROM ("ended_at" - "started_at"))' + assert params == () + + def test_literal_params_follow_sql_order(self, postgres_dialect): + expr = seconds_between( + postgres_dialect, + Literal(postgres_dialect, "2026-01-01 00:00:00"), + Literal(postgres_dialect, "2026-01-02 00:00:00"), + ) + + sql, params = expr.to_sql() + + assert sql == "EXTRACT(EPOCH FROM (%s - %s))" + # ``end`` is written first, so its parameter binds first. + assert params == ("2026-01-02 00:00:00", "2026-01-01 00:00:00") + + def test_factory_coerces_string_to_column(self, postgres_dialect): + expr = seconds_between(postgres_dialect, "started_at", "ended_at") + + sql, params = expr.to_sql() + + assert sql == 'EXTRACT(EPOCH FROM ("ended_at" - "started_at"))' + assert params == () + + def test_alias(self, postgres_dialect): + expr = seconds_between( + postgres_dialect, + Column(postgres_dialect, "started_at"), + Column(postgres_dialect, "ended_at"), + ).as_("elapsed") + + sql, params = expr.to_sql() + + assert sql == ( + 'EXTRACT(EPOCH FROM ("ended_at" - "started_at")) AS "elapsed"' + ) + assert params == () + + def test_is_a_signed_fractional_number(self, postgres_dialect): + expr = seconds_between( + postgres_dialect, + Column(postgres_dialect, "started_at"), + Column(postgres_dialect, "ended_at"), + ) + + assert isinstance(expr, SecondsBetweenExpression) + assert isinstance(expr, NumericValue) + assert expr.format_method == "format_seconds_between_expression" + + def test_query_integration(self, postgres_dialect): + query = QueryStatement( + postgres_dialect, + select=[ + seconds_between( + postgres_dialect, + Column(postgres_dialect, "started_at"), + Column(postgres_dialect, "ended_at"), + ).as_("seconds") + ], + from_="spans", + ) + + sql, params = query.to_sql() + + assert 'EXTRACT(EPOCH FROM ("ended_at" - "started_at")) AS "seconds"' in sql + assert params == () + + +class TestSyncPostgresSecondsBetweenExecution: + """The value the PostgreSQL spelling actually produces.""" + + def test_signed_fractional_semantics(self, postgres_backend_single): + backend = postgres_backend_single + try: + for statement in _setup_statements(): + backend.execute(statement) + + query = _seconds_query(backend.dialect) + sql, params = query.to_sql() + result = backend.execute(sql, params, options=_DQL_OPTIONS) + + rows = {row["id"]: row["seconds"] for row in result.data} + for index, (_, _, expected) in enumerate(_SPANS, start=1): + assert float(rows[index]) == pytest.approx(expected, abs=1e-6) + finally: + backend.execute(_CLEANUP) + + +class TestAsyncPostgresSecondsBetweenExecution: + """The same value asked through the async backend.""" + + @pytest.mark.asyncio + async def test_signed_fractional_semantics( + self, async_postgres_backend_single + ): + backend = async_postgres_backend_single + try: + for statement in _setup_statements(): + await backend.execute(statement) + + query = _seconds_query(backend.dialect) + sql, params = query.to_sql() + result = await backend.execute(sql, params, options=_DQL_OPTIONS) + + rows = {row["id"]: row["seconds"] for row in result.data} + for index, (_, _, expected) in enumerate(_SPANS, start=1): + assert float(rows[index]) == pytest.approx(expected, abs=1e-6) + finally: + await backend.execute(_CLEANUP) From 02846c0df882b0f676a1be25e0b46f67c323d35a Mon Sep 17 00:00:00 2001 From: zhao vistart Date: Sun, 8 Nov 2026 20:03:33 +0800 Subject: [PATCH 2/6] chore(ci): test against the core extract-epoch branch --- .github/workflows/test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a4c72039..cd046678 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -63,7 +63,7 @@ jobs: - name: Install activerecord and testsuite run: | - pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev30" + pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17" - name: Install dependencies @@ -278,7 +278,7 @@ jobs: - name: Install activerecord and testsuite run: | - pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev30" + pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17" - name: Install dependencies @@ -385,7 +385,7 @@ jobs: - name: Install activerecord and testsuite run: | - pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev30" + pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17" - name: Install dependencies @@ -488,7 +488,7 @@ jobs: - name: Install activerecord and testsuite run: | - pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev30" + pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17" - name: Install dependencies From 9cbfb4878ed2529a3d397446a5363dce2c2aa5d2 Mon Sep 17 00:00:00 2001 From: zhao vistart Date: Sun, 8 Nov 2026 20:07:44 +0800 Subject: [PATCH 3/6] chore: add changelog fragment for PR #65 --- changelog.d/65.added.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 changelog.d/65.added.md diff --git a/changelog.d/65.added.md b/changelog.d/65.added.md new file mode 100644 index 00000000..0fcab7a9 --- /dev/null +++ b/changelog.d/65.added.md @@ -0,0 +1,2 @@ +Render `seconds_between` as `EXTRACT(EPOCH FROM (end - start))`. + From 8d39d9bbd25707480e65700e91c71947efff6970 Mon Sep 17 00:00:00 2001 From: zhao vistart Date: Sun, 8 Nov 2026 20:11:34 +0800 Subject: [PATCH 4/6] chore(ci): annotate the paired core install as intentional --- .github/workflows/test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cd046678..ab5f03e5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -63,7 +63,7 @@ jobs: - name: Install activerecord and testsuite run: | - pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" + pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" # NOSONAR pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17" - name: Install dependencies @@ -278,7 +278,7 @@ jobs: - name: Install activerecord and testsuite run: | - pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" + pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" # NOSONAR pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17" - name: Install dependencies @@ -385,7 +385,7 @@ jobs: - name: Install activerecord and testsuite run: | - pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" + pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" # NOSONAR pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17" - name: Install dependencies @@ -488,7 +488,7 @@ jobs: - name: Install activerecord and testsuite run: | - pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" + pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" # NOSONAR pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17" - name: Install dependencies From 8f1f447bcc16b7a93c6b407b7656bf9fc8caa5b3 Mon Sep 17 00:00:00 2001 From: zhao vistart Date: Sun, 8 Nov 2026 22:03:10 +0800 Subject: [PATCH 5/6] chore(ci): test against the testsuite extract-epoch branch --- .github/workflows/test.yml | 8 ++++---- .../query/typed_column/test_seconds_between_contract.py | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 tests/rhosocial/activerecord_postgres_test/feature/query/typed_column/test_seconds_between_contract.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ab5f03e5..a65f72c1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -64,7 +64,7 @@ jobs: - name: Install activerecord and testsuite run: | pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" # NOSONAR - pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17" + pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@feature/extract-epoch" - name: Install dependencies run: | @@ -279,7 +279,7 @@ jobs: - name: Install activerecord and testsuite run: | pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" # NOSONAR - pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17" + pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@feature/extract-epoch" - name: Install dependencies run: | @@ -386,7 +386,7 @@ jobs: - name: Install activerecord and testsuite run: | pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" # NOSONAR - pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17" + pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@feature/extract-epoch" - name: Install dependencies run: | @@ -489,7 +489,7 @@ jobs: - name: Install activerecord and testsuite run: | pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" # NOSONAR - pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17" + pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@feature/extract-epoch" - name: Install dependencies run: | diff --git a/tests/rhosocial/activerecord_postgres_test/feature/query/typed_column/test_seconds_between_contract.py b/tests/rhosocial/activerecord_postgres_test/feature/query/typed_column/test_seconds_between_contract.py new file mode 100644 index 00000000..318177ec --- /dev/null +++ b/tests/rhosocial/activerecord_postgres_test/feature/query/typed_column/test_seconds_between_contract.py @@ -0,0 +1,2 @@ +# tests/rhosocial/activerecord_postgres_test/feature/query/typed_column/test_seconds_between_contract.py +from rhosocial.activerecord.testsuite.feature.query.typed_column.test_seconds_between_contract import * # noqa: F401,F403 From 11025a799dd1f6e552bf5890f630129378862bad Mon Sep 17 00:00:00 2001 From: zhao vistart Date: Sun, 8 Nov 2026 22:18:30 +0800 Subject: [PATCH 6/6] chore(ci): test against the merged core release --- .github/workflows/test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a65f72c1..19948c55 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -63,7 +63,7 @@ jobs: - name: Install activerecord and testsuite run: | - pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" # NOSONAR + pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev30" # NOSONAR pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@feature/extract-epoch" - name: Install dependencies @@ -278,7 +278,7 @@ jobs: - name: Install activerecord and testsuite run: | - pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" # NOSONAR + pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev30" # NOSONAR pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@feature/extract-epoch" - name: Install dependencies @@ -385,7 +385,7 @@ jobs: - name: Install activerecord and testsuite run: | - pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" # NOSONAR + pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev30" # NOSONAR pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@feature/extract-epoch" - name: Install dependencies @@ -488,7 +488,7 @@ jobs: - name: Install activerecord and testsuite run: | - pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@feature/extract-epoch" # NOSONAR + pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev30" # NOSONAR pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@feature/extract-epoch" - name: Install dependencies