Compare commits
8 Commits
339d06ce7e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
946ee9677c | ||
|
|
ec16930569 | ||
|
|
accfb4f346 | ||
|
|
e5ce96e210 | ||
|
|
a506cd8f08 | ||
|
|
1cedd58708 | ||
|
|
7f7ebd3ad6 | ||
|
|
9f6d480aee |
110
Cargo.lock
generated
110
Cargo.lock
generated
@@ -493,11 +493,12 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "canvas"
|
name = "canvas"
|
||||||
version = "0.5.0"
|
version = "0.5.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
|
"derivative",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
"regex",
|
"regex",
|
||||||
@@ -584,7 +585,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "client"
|
name = "client"
|
||||||
version = "0.5.0"
|
version = "0.5.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -601,6 +602,8 @@ dependencies = [
|
|||||||
"rstest",
|
"rstest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"strum 0.27.2",
|
||||||
|
"strum_macros 0.27.2",
|
||||||
"time",
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-test",
|
"tokio-test",
|
||||||
@@ -635,7 +638,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "common"
|
name = "common"
|
||||||
version = "0.5.0"
|
version = "0.5.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"prost 0.13.5",
|
"prost 0.13.5",
|
||||||
"prost-build 0.14.1",
|
"prost-build 0.14.1",
|
||||||
@@ -936,6 +939,17 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derivative"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
@@ -1959,11 +1973,11 @@ checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchers"
|
name = "matchers"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex-automata 0.1.10",
|
"regex-automata",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2080,12 +2094,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.46.0"
|
version = "0.50.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"overload",
|
"windows-sys 0.60.2",
|
||||||
"winapi",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2243,12 +2256,6 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "overload"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ownedbytes"
|
name = "ownedbytes"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@@ -2756,7 +2763,7 @@ dependencies = [
|
|||||||
"itertools 0.13.0",
|
"itertools 0.13.0",
|
||||||
"lru",
|
"lru",
|
||||||
"paste",
|
"paste",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"unicode-truncate",
|
"unicode-truncate",
|
||||||
"unicode-width 0.2.0",
|
"unicode-width 0.2.0",
|
||||||
@@ -2810,17 +2817,8 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata 0.4.9",
|
"regex-automata",
|
||||||
"regex-syntax 0.8.5",
|
"regex-syntax",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-automata"
|
|
||||||
version = "0.1.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
|
||||||
dependencies = [
|
|
||||||
"regex-syntax 0.6.29",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2831,15 +2829,9 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-syntax 0.8.5",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.6.29"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
@@ -3100,7 +3092,7 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "search"
|
name = "search"
|
||||||
version = "0.5.0"
|
version = "0.5.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"common",
|
"common",
|
||||||
@@ -3199,7 +3191,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "server"
|
name = "server"
|
||||||
version = "0.5.0"
|
version = "0.5.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bcrypt",
|
"bcrypt",
|
||||||
@@ -3210,6 +3202,7 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"jsonwebtoken",
|
"jsonwebtoken",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"once_cell",
|
||||||
"prost 0.13.5",
|
"prost 0.13.5",
|
||||||
"prost-build 0.14.1",
|
"prost-build 0.14.1",
|
||||||
"prost-types 0.13.5",
|
"prost-types 0.13.5",
|
||||||
@@ -3234,6 +3227,7 @@ dependencies = [
|
|||||||
"tonic",
|
"tonic",
|
||||||
"tonic-reflection",
|
"tonic-reflection",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
"uuid",
|
"uuid",
|
||||||
"validator",
|
"validator",
|
||||||
]
|
]
|
||||||
@@ -3756,9 +3750,15 @@ version = "0.26.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"strum_macros",
|
"strum_macros 0.26.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum"
|
||||||
|
version = "0.27.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strum_macros"
|
name = "strum_macros"
|
||||||
version = "0.26.4"
|
version = "0.26.4"
|
||||||
@@ -3772,6 +3772,18 @@ dependencies = [
|
|||||||
"syn 2.0.104",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum_macros"
|
||||||
|
version = "0.27.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.104",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "2.6.1"
|
version = "2.6.1"
|
||||||
@@ -3830,7 +3842,7 @@ dependencies = [
|
|||||||
"fnv",
|
"fnv",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"plist",
|
"plist",
|
||||||
"regex-syntax 0.8.5",
|
"regex-syntax",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -3936,7 +3948,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "d60769b80ad7953d8a7b2c70cdfe722bbcdcac6bccc8ac934c40c034d866fc18"
|
checksum = "d60769b80ad7953d8a7b2c70cdfe722bbcdcac6bccc8ac934c40c034d866fc18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"regex-syntax 0.8.5",
|
"regex-syntax",
|
||||||
"utf8-ranges",
|
"utf8-ranges",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4318,9 +4330,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.41"
|
version = "0.1.44"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@@ -4330,9 +4342,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-attributes"
|
name = "tracing-attributes"
|
||||||
version = "0.1.30"
|
version = "0.1.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
|
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -4341,9 +4353,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-core"
|
name = "tracing-core"
|
||||||
version = "0.1.34"
|
version = "0.1.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
|
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"valuable",
|
"valuable",
|
||||||
@@ -4362,14 +4374,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-subscriber"
|
name = "tracing-subscriber"
|
||||||
version = "0.3.19"
|
version = "0.3.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
|
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"matchers",
|
"matchers",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"regex",
|
"regex-automata",
|
||||||
"sharded-slab",
|
"sharded-slab",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thread_local",
|
"thread_local",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ resolver = "2"
|
|||||||
[workspace.package]
|
[workspace.package]
|
||||||
# TODO: idk how to do the name, fix later
|
# TODO: idk how to do the name, fix later
|
||||||
# name = "komp_ac"
|
# name = "komp_ac"
|
||||||
version = "0.5.0"
|
version = "0.5.10"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
authors = ["Filip Priečinský <filippriec@gmail.com>"]
|
authors = ["Filip Priečinský <filippriec@gmail.com>"]
|
||||||
|
|||||||
@@ -16,10 +16,5 @@ cargo watch -x 'run --package client -- client'
|
|||||||
|
|
||||||
Client with tracing:
|
Client with tracing:
|
||||||
```
|
```
|
||||||
ENABLE_TRACING=1 RUST_LOG=client=debug cargo watch -x 'run --package client -- client'
|
|
||||||
```
|
|
||||||
|
|
||||||
Client with debug that cant be traced
|
|
||||||
```
|
|
||||||
cargo run --package client --features ui-debug -- client
|
cargo run --package client --features ui-debug -- client
|
||||||
```
|
```
|
||||||
|
|||||||
2
canvas
2
canvas
Submodule canvas updated: 29fdc5a6c7...2c03fc4814
2
client
2
client
Submodule client updated: c1839bd960...6cba369adb
@@ -20,6 +20,18 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
".komp_ac.table_validation.TableValidationResponse",
|
".komp_ac.table_validation.TableValidationResponse",
|
||||||
"#[derive(serde::Serialize, serde::Deserialize)]",
|
"#[derive(serde::Serialize, serde::Deserialize)]",
|
||||||
)
|
)
|
||||||
|
.type_attribute(
|
||||||
|
".komp_ac.table_validation.PatternRule",
|
||||||
|
"#[derive(serde::Serialize, serde::Deserialize)]",
|
||||||
|
)
|
||||||
|
.type_attribute(
|
||||||
|
".komp_ac.table_validation.PatternRules",
|
||||||
|
"#[derive(serde::Serialize, serde::Deserialize)]",
|
||||||
|
)
|
||||||
|
.type_attribute(
|
||||||
|
".komp_ac.table_validation.CustomFormatter",
|
||||||
|
"#[derive(serde::Serialize, serde::Deserialize)]",
|
||||||
|
)
|
||||||
.type_attribute(
|
.type_attribute(
|
||||||
".komp_ac.table_validation.UpdateFieldValidationRequest",
|
".komp_ac.table_validation.UpdateFieldValidationRequest",
|
||||||
"#[derive(serde::Serialize, serde::Deserialize)]",
|
"#[derive(serde::Serialize, serde::Deserialize)]",
|
||||||
|
|||||||
@@ -3,5 +3,9 @@ syntax = "proto3";
|
|||||||
package komp_ac.common;
|
package komp_ac.common;
|
||||||
|
|
||||||
message Empty {}
|
message Empty {}
|
||||||
message CountResponse { int64 count = 1; }
|
message CountResponse {
|
||||||
message PositionRequest { int64 position = 1; }
|
int64 count = 1;
|
||||||
|
}
|
||||||
|
message PositionRequest {
|
||||||
|
int64 position = 1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,17 +12,14 @@ service TableDefinition {
|
|||||||
// Creates a new table (and schema if missing) with system columns,
|
// Creates a new table (and schema if missing) with system columns,
|
||||||
// linked-table foreign keys, user-defined columns, and optional indexes.
|
// linked-table foreign keys, user-defined columns, and optional indexes.
|
||||||
// Also inserts metadata and default validation rules. Entirely transactional.
|
// Also inserts metadata and default validation rules. Entirely transactional.
|
||||||
rpc PostTableDefinition(PostTableDefinitionRequest)
|
rpc PostTableDefinition(PostTableDefinitionRequest) returns (TableDefinitionResponse);
|
||||||
returns (TableDefinitionResponse);
|
|
||||||
|
|
||||||
// Lists all profiles (schemas) and their tables with declared dependencies.
|
// Lists all profiles (schemas) and their tables with declared dependencies.
|
||||||
// This provides a tree-like overview of table relationships.
|
// This provides a tree-like overview of table relationships.
|
||||||
rpc GetProfileTree(komp_ac.common.Empty)
|
rpc GetProfileTree(komp_ac.common.Empty) returns (ProfileTreeResponse);
|
||||||
returns (ProfileTreeResponse);
|
|
||||||
|
|
||||||
// Drops a table and its metadata, then deletes the profile if it becomes empty.
|
// Drops a table and its metadata, then deletes the profile if it becomes empty.
|
||||||
rpc DeleteTable(DeleteTableRequest)
|
rpc DeleteTable(DeleteTableRequest) returns (DeleteTableResponse);
|
||||||
returns (DeleteTableResponse);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A single link to another table within the same profile (schema).
|
// A single link to another table within the same profile (schema).
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ service TableStructureService {
|
|||||||
// - Normalizes data_type text (details under TableColumn.data_type)
|
// - Normalizes data_type text (details under TableColumn.data_type)
|
||||||
// - Returns an empty list if the table is validated but has no visible
|
// - Returns an empty list if the table is validated but has no visible
|
||||||
// columns in information_schema (e.g., physical table missing)
|
// columns in information_schema (e.g., physical table missing)
|
||||||
rpc GetTableStructure(GetTableStructureRequest)
|
rpc GetTableStructure(GetTableStructureRequest) returns (TableStructureResponse);
|
||||||
returns (TableStructureResponse);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request identifying the profile (schema) and table to inspect.
|
// Request identifying the profile (schema) and table to inspect.
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ message FieldValidation {
|
|||||||
// Current: only CharacterLimits. More rules can be added later.
|
// Current: only CharacterLimits. More rules can be added later.
|
||||||
CharacterLimits limits = 10;
|
CharacterLimits limits = 10;
|
||||||
// Future expansion:
|
// Future expansion:
|
||||||
// PatternRules pattern = 11;
|
PatternRules pattern = 11; // Validation 2
|
||||||
|
optional CustomFormatter formatter = 14; // Validation 4 – custom formatting logic
|
||||||
DisplayMask mask = 3;
|
DisplayMask mask = 3;
|
||||||
// ExternalValidation external = 13;
|
// ExternalValidation external = 13;
|
||||||
// CustomFormatter formatter = 14;
|
// CustomFormatter formatter = 14;
|
||||||
@@ -57,13 +58,45 @@ message DisplayMask {
|
|||||||
optional string template_char = 3; // e.g., "_"
|
optional string template_char = 3; // e.g., "_"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// One position‑based validation rule, similar to CharacterFilter + PositionRange
|
||||||
|
message PatternRule {
|
||||||
|
// Range descriptor: how far the rule applies
|
||||||
|
// Examples:
|
||||||
|
// - "0" → Single position 0
|
||||||
|
// - "0-3" → Range 0..3 inclusive
|
||||||
|
// - "from:5" → From position 5 onward
|
||||||
|
// - "0,2,5" → Multiple discrete positions
|
||||||
|
string range = 1;
|
||||||
|
|
||||||
|
// Character filter type, case‑insensitive keywords:
|
||||||
|
// "ALPHABETIC", "NUMERIC", "ALPHANUMERIC",
|
||||||
|
// "ONEOF(<chars>)", "EXACT(:)", "CUSTOM(<name>)"
|
||||||
|
string filter = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CustomFormatter {
|
||||||
|
// Formatter type identifier; handled client‑side.
|
||||||
|
// Examples: "PSCFormatter", "PhoneFormatter", "CreditCardFormatter", "DateFormatter"
|
||||||
|
string type = 1;
|
||||||
|
|
||||||
|
// Optional free‑text note or parameters (e.g. locale, pattern)
|
||||||
|
optional string description = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collection of pattern rules for one field
|
||||||
|
message PatternRules {
|
||||||
|
// All rules that make up the validation logic
|
||||||
|
repeated PatternRule rules = 1;
|
||||||
|
|
||||||
|
// Optional human‑readable description for UI/debug purposes
|
||||||
|
optional string description = 2;
|
||||||
|
}
|
||||||
|
|
||||||
// Service to fetch validations for a table
|
// Service to fetch validations for a table
|
||||||
service TableValidationService {
|
service TableValidationService {
|
||||||
rpc GetTableValidation(GetTableValidationRequest)
|
rpc GetTableValidation(GetTableValidationRequest) returns (TableValidationResponse);
|
||||||
returns (TableValidationResponse);
|
|
||||||
|
|
||||||
rpc UpdateFieldValidation(UpdateFieldValidationRequest)
|
rpc UpdateFieldValidation(UpdateFieldValidationRequest) returns (UpdateFieldValidationResponse);
|
||||||
returns (UpdateFieldValidationResponse);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message UpdateFieldValidationRequest {
|
message UpdateFieldValidationRequest {
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ pub mod proto {
|
|||||||
pub mod table_validation {
|
pub mod table_validation {
|
||||||
include!("proto/komp_ac.table_validation.rs");
|
include!("proto/komp_ac.table_validation.rs");
|
||||||
}
|
}
|
||||||
pub const FILE_DESCRIPTOR_SET: &[u8] =
|
pub const FILE_DESCRIPTOR_SET: &[u8] = include_bytes!("proto/descriptor.bin");
|
||||||
include_bytes!("proto/descriptor.bin");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -26,7 +26,13 @@ pub struct FieldValidation {
|
|||||||
#[prost(message, optional, tag = "10")]
|
#[prost(message, optional, tag = "10")]
|
||||||
pub limits: ::core::option::Option<CharacterLimits>,
|
pub limits: ::core::option::Option<CharacterLimits>,
|
||||||
/// Future expansion:
|
/// Future expansion:
|
||||||
/// PatternRules pattern = 11;
|
///
|
||||||
|
/// Validation 2
|
||||||
|
#[prost(message, optional, tag = "11")]
|
||||||
|
pub pattern: ::core::option::Option<PatternRules>,
|
||||||
|
/// Validation 4 – custom formatting logic
|
||||||
|
#[prost(message, optional, tag = "14")]
|
||||||
|
pub formatter: ::core::option::Option<CustomFormatter>,
|
||||||
#[prost(message, optional, tag = "3")]
|
#[prost(message, optional, tag = "3")]
|
||||||
pub mask: ::core::option::Option<DisplayMask>,
|
pub mask: ::core::option::Option<DisplayMask>,
|
||||||
/// ExternalValidation external = 13;
|
/// ExternalValidation external = 13;
|
||||||
@@ -65,6 +71,46 @@ pub struct DisplayMask {
|
|||||||
#[prost(string, optional, tag = "3")]
|
#[prost(string, optional, tag = "3")]
|
||||||
pub template_char: ::core::option::Option<::prost::alloc::string::String>,
|
pub template_char: ::core::option::Option<::prost::alloc::string::String>,
|
||||||
}
|
}
|
||||||
|
/// One position‑based validation rule, similar to CharacterFilter + PositionRange
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct PatternRule {
|
||||||
|
/// Range descriptor: how far the rule applies
|
||||||
|
/// Examples:
|
||||||
|
/// - "0" → Single position 0
|
||||||
|
/// - "0-3" → Range 0..3 inclusive
|
||||||
|
/// - "from:5" → From position 5 onward
|
||||||
|
/// - "0,2,5" → Multiple discrete positions
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub range: ::prost::alloc::string::String,
|
||||||
|
/// Character filter type, case‑insensitive keywords:
|
||||||
|
/// "ALPHABETIC", "NUMERIC", "ALPHANUMERIC",
|
||||||
|
/// "ONEOF(<chars>)", "EXACT(:)", "CUSTOM(<name>)"
|
||||||
|
#[prost(string, tag = "2")]
|
||||||
|
pub filter: ::prost::alloc::string::String,
|
||||||
|
}
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct CustomFormatter {
|
||||||
|
/// Formatter type identifier; handled client‑side.
|
||||||
|
/// Examples: "PSCFormatter", "PhoneFormatter", "CreditCardFormatter", "DateFormatter"
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub r#type: ::prost::alloc::string::String,
|
||||||
|
/// Optional free‑text note or parameters (e.g. locale, pattern)
|
||||||
|
#[prost(string, optional, tag = "2")]
|
||||||
|
pub description: ::core::option::Option<::prost::alloc::string::String>,
|
||||||
|
}
|
||||||
|
/// Collection of pattern rules for one field
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct PatternRules {
|
||||||
|
/// All rules that make up the validation logic
|
||||||
|
#[prost(message, repeated, tag = "1")]
|
||||||
|
pub rules: ::prost::alloc::vec::Vec<PatternRule>,
|
||||||
|
/// Optional human‑readable description for UI/debug purposes
|
||||||
|
#[prost(string, optional, tag = "2")]
|
||||||
|
pub description: ::core::option::Option<::prost::alloc::string::String>,
|
||||||
|
}
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct UpdateFieldValidationRequest {
|
pub struct UpdateFieldValidationRequest {
|
||||||
|
|||||||
@@ -48,8 +48,7 @@ pub fn register_slovak_tokenizers(index: &Index) -> tantivy::Result<()> {
|
|||||||
let tokenizer_manager = index.tokenizers();
|
let tokenizer_manager = index.tokenizers();
|
||||||
|
|
||||||
// TOKENIZER for `prefix_edge`: Edge N-gram (1-4 chars)
|
// TOKENIZER for `prefix_edge`: Edge N-gram (1-4 chars)
|
||||||
let edge_tokenizer =
|
let edge_tokenizer = TextAnalyzer::builder(NgramTokenizer::new(1, 4, true)?)
|
||||||
TextAnalyzer::builder(NgramTokenizer::new(1, 4, true)?)
|
|
||||||
.filter(RemoveLongFilter::limit(40))
|
.filter(RemoveLongFilter::limit(40))
|
||||||
.filter(LowerCaser)
|
.filter(LowerCaser)
|
||||||
.filter(AsciiFoldingFilter)
|
.filter(AsciiFoldingFilter)
|
||||||
@@ -57,8 +56,7 @@ pub fn register_slovak_tokenizers(index: &Index) -> tantivy::Result<()> {
|
|||||||
tokenizer_manager.register("slovak_prefix_edge", edge_tokenizer);
|
tokenizer_manager.register("slovak_prefix_edge", edge_tokenizer);
|
||||||
|
|
||||||
// TOKENIZER for `prefix_full`: Simple word tokenizer
|
// TOKENIZER for `prefix_full`: Simple word tokenizer
|
||||||
let full_tokenizer =
|
let full_tokenizer = TextAnalyzer::builder(SimpleTokenizer::default())
|
||||||
TextAnalyzer::builder(SimpleTokenizer::default())
|
|
||||||
.filter(RemoveLongFilter::limit(40))
|
.filter(RemoveLongFilter::limit(40))
|
||||||
.filter(LowerCaser)
|
.filter(LowerCaser)
|
||||||
.filter(AsciiFoldingFilter)
|
.filter(AsciiFoldingFilter)
|
||||||
@@ -66,8 +64,7 @@ pub fn register_slovak_tokenizers(index: &Index) -> tantivy::Result<()> {
|
|||||||
tokenizer_manager.register("slovak_prefix_full", full_tokenizer);
|
tokenizer_manager.register("slovak_prefix_full", full_tokenizer);
|
||||||
|
|
||||||
// NGRAM TOKENIZER: For substring matching.
|
// NGRAM TOKENIZER: For substring matching.
|
||||||
let ngram_tokenizer =
|
let ngram_tokenizer = TextAnalyzer::builder(NgramTokenizer::new(3, 3, false)?)
|
||||||
TextAnalyzer::builder(NgramTokenizer::new(3, 3, false)?)
|
|
||||||
.filter(RemoveLongFilter::limit(40))
|
.filter(RemoveLongFilter::limit(40))
|
||||||
.filter(LowerCaser)
|
.filter(LowerCaser)
|
||||||
.filter(AsciiFoldingFilter)
|
.filter(AsciiFoldingFilter)
|
||||||
|
|||||||
@@ -14,12 +14,17 @@
|
|||||||
{
|
{
|
||||||
devShells.default = pkgs.mkShell {
|
devShells.default = pkgs.mkShell {
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
|
mermaid-cli
|
||||||
# Rust toolchain
|
# Rust toolchain
|
||||||
rustc
|
rustc
|
||||||
cargo
|
cargo
|
||||||
rustfmt
|
rustfmt
|
||||||
clippy
|
clippy
|
||||||
cargo-watch
|
cargo-watch
|
||||||
|
rust-analyzer
|
||||||
|
cargo-tarpaulin
|
||||||
|
cargo-flamegraph
|
||||||
|
rust-code-analysis
|
||||||
|
|
||||||
# C build tools (for your linker issue)
|
# C build tools (for your linker issue)
|
||||||
gcc
|
gcc
|
||||||
@@ -37,6 +42,7 @@
|
|||||||
# Protocol Buffers compiler for gRPC
|
# Protocol Buffers compiler for gRPC
|
||||||
protobuf
|
protobuf
|
||||||
protoc-gen-doc
|
protoc-gen-doc
|
||||||
|
buf
|
||||||
];
|
];
|
||||||
|
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
|
|||||||
@@ -4,18 +4,15 @@ use std::collections::HashMap;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use tantivy::collector::TopDocs;
|
use tantivy::collector::TopDocs;
|
||||||
use tantivy::query::{
|
use tantivy::query::{
|
||||||
BooleanQuery, BoostQuery, FuzzyTermQuery, Occur, Query, QueryParser,
|
BooleanQuery, BoostQuery, FuzzyTermQuery, Occur, Query, QueryParser, TermQuery,
|
||||||
TermQuery,
|
|
||||||
};
|
};
|
||||||
use tantivy::schema::{IndexRecordOption, Value};
|
use tantivy::schema::{IndexRecordOption, Value};
|
||||||
use tantivy::{Index, TantivyDocument, Term};
|
use tantivy::{Index, TantivyDocument, Term};
|
||||||
use tonic::{Request, Response, Status};
|
use tonic::{Request, Response, Status};
|
||||||
|
|
||||||
use common::proto::komp_ac::search::{
|
|
||||||
search_response::Hit, SearchRequest, SearchResponse,
|
|
||||||
};
|
|
||||||
pub use common::proto::komp_ac::search::searcher_server::SearcherServer;
|
|
||||||
use common::proto::komp_ac::search::searcher_server::Searcher;
|
use common::proto::komp_ac::search::searcher_server::Searcher;
|
||||||
|
pub use common::proto::komp_ac::search::searcher_server::SearcherServer;
|
||||||
|
use common::proto::komp_ac::search::{search_response::Hit, SearchRequest, SearchResponse};
|
||||||
use common::search::register_slovak_tokenizers;
|
use common::search::register_slovak_tokenizers;
|
||||||
use sqlx::{PgPool, Row};
|
use sqlx::{PgPool, Row};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
@@ -86,22 +83,15 @@ impl Searcher for SearcherService {
|
|||||||
qualified_table
|
qualified_table
|
||||||
);
|
);
|
||||||
|
|
||||||
let rows = sqlx::query(&sql)
|
let rows = sqlx::query(&sql).fetch_all(&self.pool).await.map_err(|e| {
|
||||||
.fetch_all(&self.pool)
|
Status::internal(format!("DB query for default results failed: {}", e))
|
||||||
.await
|
|
||||||
.map_err(|e| {
|
|
||||||
Status::internal(format!(
|
|
||||||
"DB query for default results failed: {}",
|
|
||||||
e
|
|
||||||
))
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let hits: Vec<Hit> = rows
|
let hits: Vec<Hit> = rows
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|row| {
|
.map(|row| {
|
||||||
let id: i64 = row.try_get("id").unwrap_or_default();
|
let id: i64 = row.try_get("id").unwrap_or_default();
|
||||||
let json_data: serde_json::Value =
|
let json_data: serde_json::Value = row.try_get("data").unwrap_or_default();
|
||||||
row.try_get("data").unwrap_or_default();
|
|
||||||
Hit {
|
Hit {
|
||||||
id,
|
id,
|
||||||
// Score is 0.0 as this is not a relevance-ranked search
|
// Score is 0.0 as this is not a relevance-ranked search
|
||||||
@@ -111,7 +101,10 @@ impl Searcher for SearcherService {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
info!("--- SERVER: Successfully processed empty query. Returning {} default hits. ---", hits.len());
|
info!(
|
||||||
|
"--- SERVER: Successfully processed empty query. Returning {} default hits. ---",
|
||||||
|
hits.len()
|
||||||
|
);
|
||||||
return Ok(Response::new(SearchResponse { hits }));
|
return Ok(Response::new(SearchResponse { hits }));
|
||||||
}
|
}
|
||||||
// --- END OF MODIFIED LOGIC ---
|
// --- END OF MODIFIED LOGIC ---
|
||||||
@@ -131,15 +124,15 @@ impl Searcher for SearcherService {
|
|||||||
Status::internal(format!("Failed to register Slovak tokenizers: {}", e))
|
Status::internal(format!("Failed to register Slovak tokenizers: {}", e))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let reader = index.reader().map_err(|e| {
|
let reader = index
|
||||||
Status::internal(format!("Failed to create index reader: {}", e))
|
.reader()
|
||||||
})?;
|
.map_err(|e| Status::internal(format!("Failed to create index reader: {}", e)))?;
|
||||||
let searcher = reader.searcher();
|
let searcher = reader.searcher();
|
||||||
let schema = index.schema();
|
let schema = index.schema();
|
||||||
|
|
||||||
let pg_id_field = schema.get_field("pg_id").map_err(|_| {
|
let pg_id_field = schema
|
||||||
Status::internal("Schema is missing the 'pg_id' field.")
|
.get_field("pg_id")
|
||||||
})?;
|
.map_err(|_| Status::internal("Schema is missing the 'pg_id' field."))?;
|
||||||
|
|
||||||
// --- Query Building Logic (no changes here) ---
|
// --- Query Building Logic (no changes here) ---
|
||||||
let prefix_edge_field = schema.get_field("prefix_edge").unwrap();
|
let prefix_edge_field = schema.get_field("prefix_edge").unwrap();
|
||||||
@@ -158,25 +151,17 @@ impl Searcher for SearcherService {
|
|||||||
{
|
{
|
||||||
let mut must_clauses: Vec<(Occur, Box<dyn Query>)> = Vec::new();
|
let mut must_clauses: Vec<(Occur, Box<dyn Query>)> = Vec::new();
|
||||||
for word in &words {
|
for word in &words {
|
||||||
let edge_term =
|
let edge_term = Term::from_field_text(prefix_edge_field, word);
|
||||||
Term::from_field_text(prefix_edge_field, word);
|
let full_term = Term::from_field_text(prefix_full_field, word);
|
||||||
let full_term =
|
|
||||||
Term::from_field_text(prefix_full_field, word);
|
|
||||||
|
|
||||||
let per_word_query = BooleanQuery::new(vec![
|
let per_word_query = BooleanQuery::new(vec![
|
||||||
(
|
(
|
||||||
Occur::Should,
|
Occur::Should,
|
||||||
Box::new(TermQuery::new(
|
Box::new(TermQuery::new(edge_term, IndexRecordOption::Basic)),
|
||||||
edge_term,
|
|
||||||
IndexRecordOption::Basic,
|
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Occur::Should,
|
Occur::Should,
|
||||||
Box::new(TermQuery::new(
|
Box::new(TermQuery::new(full_term, IndexRecordOption::Basic)),
|
||||||
full_term,
|
|
||||||
IndexRecordOption::Basic,
|
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
must_clauses.push((Occur::Must, Box::new(per_word_query) as Box<dyn Query>));
|
must_clauses.push((Occur::Must, Box::new(per_word_query) as Box<dyn Query>));
|
||||||
@@ -184,8 +169,7 @@ impl Searcher for SearcherService {
|
|||||||
|
|
||||||
if !must_clauses.is_empty() {
|
if !must_clauses.is_empty() {
|
||||||
let prefix_query = BooleanQuery::new(must_clauses);
|
let prefix_query = BooleanQuery::new(must_clauses);
|
||||||
let boosted_query =
|
let boosted_query = BoostQuery::new(Box::new(prefix_query), 4.0);
|
||||||
BoostQuery::new(Box::new(prefix_query), 4.0);
|
|
||||||
query_layers.push((Occur::Should, Box::new(boosted_query)));
|
query_layers.push((Occur::Should, Box::new(boosted_query)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,8 +179,7 @@ impl Searcher for SearcherService {
|
|||||||
// ===============================
|
// ===============================
|
||||||
{
|
{
|
||||||
let last_word = words.last().unwrap();
|
let last_word = words.last().unwrap();
|
||||||
let fuzzy_term =
|
let fuzzy_term = Term::from_field_text(prefix_full_field, last_word);
|
||||||
Term::from_field_text(prefix_full_field, last_word);
|
|
||||||
let fuzzy_query = FuzzyTermQuery::new(fuzzy_term, 2, true);
|
let fuzzy_query = FuzzyTermQuery::new(fuzzy_term, 2, true);
|
||||||
let boosted_query = BoostQuery::new(Box::new(fuzzy_query), 3.0);
|
let boosted_query = BoostQuery::new(Box::new(fuzzy_query), 3.0);
|
||||||
query_layers.push((Occur::Should, Box::new(boosted_query)));
|
query_layers.push((Occur::Should, Box::new(boosted_query)));
|
||||||
@@ -206,8 +189,7 @@ impl Searcher for SearcherService {
|
|||||||
// LAYER 3: PHRASE MATCHING WITH SLOP (MEDIUM PRIORITY, Boost: 2.0)
|
// LAYER 3: PHRASE MATCHING WITH SLOP (MEDIUM PRIORITY, Boost: 2.0)
|
||||||
// ===============================
|
// ===============================
|
||||||
if words.len() > 1 {
|
if words.len() > 1 {
|
||||||
let slop_parser =
|
let slop_parser = QueryParser::for_index(&index, vec![prefix_full_field]);
|
||||||
QueryParser::for_index(&index, vec![prefix_full_field]);
|
|
||||||
let slop_query_str = format!("\"{}\"~3", normalized_query);
|
let slop_query_str = format!("\"{}\"~3", normalized_query);
|
||||||
if let Ok(slop_query) = slop_parser.parse_query(&slop_query_str) {
|
if let Ok(slop_query) = slop_parser.parse_query(&slop_query_str) {
|
||||||
let boosted_query = BoostQuery::new(slop_query, 2.0);
|
let boosted_query = BoostQuery::new(slop_query, 2.0);
|
||||||
@@ -219,11 +201,8 @@ impl Searcher for SearcherService {
|
|||||||
// LAYER 4: NGRAM SUBSTRING MATCHING (LOWEST PRIORITY, Boost: 1.0)
|
// LAYER 4: NGRAM SUBSTRING MATCHING (LOWEST PRIORITY, Boost: 1.0)
|
||||||
// ===============================
|
// ===============================
|
||||||
{
|
{
|
||||||
let ngram_parser =
|
let ngram_parser = QueryParser::for_index(&index, vec![text_ngram_field]);
|
||||||
QueryParser::for_index(&index, vec![text_ngram_field]);
|
if let Ok(ngram_query) = ngram_parser.parse_query(&normalized_query) {
|
||||||
if let Ok(ngram_query) =
|
|
||||||
ngram_parser.parse_query(&normalized_query)
|
|
||||||
{
|
|
||||||
let boosted_query = BoostQuery::new(ngram_query, 1.0);
|
let boosted_query = BoostQuery::new(ngram_query, 1.0);
|
||||||
query_layers.push((Occur::Should, Box::new(boosted_query)));
|
query_layers.push((Occur::Should, Box::new(boosted_query)));
|
||||||
}
|
}
|
||||||
@@ -244,9 +223,9 @@ impl Searcher for SearcherService {
|
|||||||
// Step 1: Extract (score, pg_id) from Tantivy results.
|
// Step 1: Extract (score, pg_id) from Tantivy results.
|
||||||
let mut scored_ids: Vec<(f32, u64)> = Vec::new();
|
let mut scored_ids: Vec<(f32, u64)> = Vec::new();
|
||||||
for (score, doc_address) in top_docs {
|
for (score, doc_address) in top_docs {
|
||||||
let doc: TantivyDocument = searcher.doc(doc_address).map_err(|e| {
|
let doc: TantivyDocument = searcher
|
||||||
Status::internal(format!("Failed to retrieve document: {}", e))
|
.doc(doc_address)
|
||||||
})?;
|
.map_err(|e| Status::internal(format!("Failed to retrieve document: {}", e)))?;
|
||||||
if let Some(pg_id_value) = doc.get_first(pg_id_field) {
|
if let Some(pg_id_value) = doc.get_first(pg_id_field) {
|
||||||
if let Some(pg_id) = pg_id_value.as_u64() {
|
if let Some(pg_id) = pg_id_value.as_u64() {
|
||||||
scored_ids.push((score, pg_id));
|
scored_ids.push((score, pg_id));
|
||||||
@@ -255,8 +234,7 @@ impl Searcher for SearcherService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Fetch all corresponding rows from Postgres in a single query.
|
// Step 2: Fetch all corresponding rows from Postgres in a single query.
|
||||||
let pg_ids: Vec<i64> =
|
let pg_ids: Vec<i64> = scored_ids.iter().map(|(_, id)| *id as i64).collect();
|
||||||
scored_ids.iter().map(|(_, id)| *id as i64).collect();
|
|
||||||
let qualified_table = format!("gen.\"{}\"", table_name);
|
let qualified_table = format!("gen.\"{}\"", table_name);
|
||||||
let query_str = format!(
|
let query_str = format!(
|
||||||
"SELECT id, to_jsonb(t) AS data FROM {} t WHERE id = ANY($1)",
|
"SELECT id, to_jsonb(t) AS data FROM {} t WHERE id = ANY($1)",
|
||||||
@@ -267,9 +245,7 @@ impl Searcher for SearcherService {
|
|||||||
.bind(&pg_ids)
|
.bind(&pg_ids)
|
||||||
.fetch_all(&self.pool)
|
.fetch_all(&self.pool)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| Status::internal(format!("Database query failed: {}", e)))?;
|
||||||
Status::internal(format!("Database query failed: {}", e))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Step 3: Map the database results by ID for quick lookup.
|
// Step 3: Map the database results by ID for quick lookup.
|
||||||
let mut content_map: HashMap<i64, String> = HashMap::new();
|
let mut content_map: HashMap<i64, String> = HashMap::new();
|
||||||
@@ -284,9 +260,7 @@ impl Searcher for SearcherService {
|
|||||||
let hits: Vec<Hit> = scored_ids
|
let hits: Vec<Hit> = scored_ids
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|(score, pg_id)| {
|
.filter_map(|(score, pg_id)| {
|
||||||
content_map
|
content_map.get(&(pg_id as i64)).map(|content_json| Hit {
|
||||||
.get(&(pg_id as i64))
|
|
||||||
.map(|content_json| Hit {
|
|
||||||
id: pg_id as i64,
|
id: pg_id as i64,
|
||||||
score,
|
score,
|
||||||
content_json: content_json.clone(),
|
content_json: content_json.clone(),
|
||||||
@@ -294,7 +268,10 @@ impl Searcher for SearcherService {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
info!("--- SERVER: Successfully processed search. Returning {} hits. ---", hits.len());
|
info!(
|
||||||
|
"--- SERVER: Successfully processed search. Returning {} hits. ---",
|
||||||
|
hits.len()
|
||||||
|
);
|
||||||
|
|
||||||
let response = SearchResponse { hits };
|
let response = SearchResponse { hits };
|
||||||
Ok(Response::new(response))
|
Ok(Response::new(response))
|
||||||
|
|||||||
2
server
2
server
Submodule server updated: e497676789...515f9932f8
Reference in New Issue
Block a user