Skip to content

feat: add Postgres support to SearchOperations#3307

Merged
Ziinc merged 18 commits intoLogflare:mainfrom
msmithstubbs:feat/postgres-search
Apr 2, 2026
Merged

feat: add Postgres support to SearchOperations#3307
Ziinc merged 18 commits intoLogflare:mainfrom
msmithstubbs:feat/postgres-search

Conversation

@msmithstubbs
Copy link
Copy Markdown
Contributor

@msmithstubbs msmithstubbs commented Mar 24, 2026

Adds support for searches against a postgres backend.

  • Adds a backend_type field to %SearchOperation{}, defaults to `:bigquery', and is set automatically to default backend.
  • SearchOperations builds the search query for the appropriate backend

Intended for integration tests in CI. Part of #3239

Follows on from #3306 and #3317

  • use test_connection/1 in test setup
  • handle custom aggregates
  • unit tests in SearchOperationTest
  • unit tests in SearchLV
CleanShot 2026-03-25 at 16 01 00@2x

@msmithstubbs msmithstubbs force-pushed the feat/postgres-search branch 2 times, most recently from 693cf45 to ee679c4 Compare March 24, 2026 05:24
@msmithstubbs msmithstubbs marked this pull request as ready for review March 24, 2026 06:34
Comment thread lib/logflare/logs/search_operations.ex Outdated
Comment on lines +622 to +623
key = if key == "count", do: "value", else: key
Map.put(acc, key, normalize_postgres_value(key, value))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to factor in custom aggregates. chart would break for custom agg like p99 i think

Comment thread test/logflare/logs/search_test.exs
@Ziinc
Copy link
Copy Markdown
Contributor

Ziinc commented Mar 24, 2026

I've added a high level search test, do we also want units tests in SearchOperationTest to mirror the BigQuery coverage?
some unit tests would be nice.

would also be good to have unit test in logs_search_lv_test.exs

@msmithstubbs msmithstubbs force-pushed the feat/postgres-search branch 4 times, most recently from b385b5a to 87671ca Compare March 26, 2026 04:27
@msmithstubbs msmithstubbs requested a review from Ziinc March 26, 2026 06:13
|> nested_map_update()
end

{:ok, rows}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make the returned map the same as bigquery so that we don't have to normalise in the caller

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An Adaptor.QueryResult struct might work to make things more standardised

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handled this in a separate PR #3317

|> TestUtils.wait_for_render("#logs-list-container li")

assert view |> element("#logs-list-container") |> render() =~ matching_message
end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should refute non matching message

Comment on lines +1372 to +1379
bq_schema = TestUtils.build_bq_schema(%{"event_message" => matching_message})

assert {:ok, _source_schema} =
SourceSchemas.create_or_update_source_schema(source, %{
bigquery_schema: bq_schema,
schema_flat_map: SchemaUtils.bq_schema_to_flat_typemap(bq_schema)
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be combined into a source_schema factory so that it is a bit more ergonomic.

schema_flat_map: SchemaUtils.bq_schema_to_flat_typemap(bq_schema)
})

Cachex.clear(Logflare.SourceSchemas.Cache)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need to clear cache if it is inserted before source sup is started

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, moved the insert to happen before source sup start.

end

test "generates expected SQL for all aggregate types", %{base_so: base_so} do
for agg <- [:count, :avg, :sum, :max] do
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're only testing a subset of the accepted aggs?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had thought of this more as an integration test that aggregate types work since each agg is covered by postgres backend transformer test. But it's cheap test to do here, too.

Added full list: :count, :avg, :sum, :max, :countd, :p50, :p95, :p99

@msmithstubbs msmithstubbs force-pushed the feat/postgres-search branch 2 times, most recently from 3bda886 to b9b809f Compare April 1, 2026 03:38
@msmithstubbs msmithstubbs force-pushed the feat/postgres-search branch from b9b809f to ead7a22 Compare April 1, 2026 03:42
Copy link
Copy Markdown
Contributor

@Ziinc Ziinc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@msmithstubbs can you make the test adjustments in a follow up? 🙏

Comment on lines +549 to +558
PostgresAdaptor
|> expect(:execute_query, fn ^backend, %Ecto.Query{}, [query_type: :search] ->
rows = [%{"count" => 2, "timestamp" => unix_timestamp}]
{:ok, QueryResult.new(rows, %{total_rows: length(rows)})}
end)

PostgresAdaptor
|> expect(:ecto_to_sql, fn %Ecto.Query{}, [] ->
{:ok, {"SELECT count(*) FROM test_table", []}}
end)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not stub this so thar we have a full integration test

|> expect(:get_default_backend, fn _user -> backend end)

PostgresAdaptor
|> expect(:execute_query, fn ^backend, %Ecto.Query{}, [query_type: :search] ->
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simulating a raise (like bad connection) would be preferred

end)

PostgresAdaptor
|> expect(:execute_query, fn ^backend, %Ecto.Query{} = query, opts ->
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mock here is not referred for comprehensiveness

end

describe "postgres backend adaptor integration" do
setup %{user: user} do
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the SingleTenant test module, there is some test macros that should be used when dealing with single tenant mode that will help with all this provisioning so that we don't need to mock anything

@Ziinc Ziinc merged commit 206bba5 into Logflare:main Apr 2, 2026
12 checks passed
Ziinc added a commit that referenced this pull request Apr 10, 2026
* refactor: backend execute_query/3 returns Adaptor.QueryResult

* feat: PostgresAdaptor include total_rows in result

* refactor: decouple SearchLV LQL from BigQuery TableSchema

* fix: dialyzer warnings

* feat: add Postgres support to SearchOperations

* style: alias nested modules (credo)

* implement PostgresAdaptor.test_connection/1

* fix: postgres adaptor aggregates

* fix: execute_query can return error (dialyzer)

* test: SearchOperations postgres unit tests

* test: SearchLV postgres backend search

* test tidy up

* refactor: move postgres result normalisation to PostgresAdaptor

* test: refute non matching message

* test: full list of aggregate types

* bump ci

* test: put_sql_string matches on backend_type

---------

Co-authored-by: Ziinc <Ziinc@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants