From d8f280ec8e6cf2ac1dd17b6e214bd8be82469b75 Mon Sep 17 00:00:00 2001 From: Priec Date: Tue, 21 Jul 2026 12:29:30 +0200 Subject: [PATCH] accounting as table defined --- client | 2 +- common/proto/table_definition.proto | 4 + common/src/proto/descriptor.bin | Bin 120159 -> 120423 bytes common/src/proto/komp_ac.table_definition.rs | 5 + common/src/search.rs | 2 +- search/src/lib.rs | 100 ++----------------- server | 2 +- tui-canvas | 2 +- tui-pages | 2 +- 9 files changed, 20 insertions(+), 99 deletions(-) diff --git a/client b/client index e40a195..2465eb9 160000 --- a/client +++ b/client @@ -1 +1 @@ -Subproject commit e40a1955819d131c8c2915a62ade3e817095598f +Subproject commit 2465eb9ca99946aab8e2b435d0e73907a989c163 diff --git a/common/proto/table_definition.proto b/common/proto/table_definition.proto index dbb3551..0136ef0 100644 --- a/common/proto/table_definition.proto +++ b/common/proto/table_definition.proto @@ -171,6 +171,9 @@ message ProfileTreeResponse { // Column whose value is used as the human-readable row label. string row_display_column = 4; + + // "dynamic" for user-defined tables, "system" for backend-managed tables. + string table_kind = 5; } // Profile (schema) entry. @@ -247,6 +250,7 @@ message TableDetail { string base_currency = 5; string row_display_column = 6; map column_behaviors = 7; + string table_kind = 8; } // Server-owned behavior for one logical column returned in table details. diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index f4e6650e6feb9019b2ab60784583c633c3e05343..172bac1bf20729c1b47371a235ed660569290d34 100644 GIT binary patch delta 3640 zcmZ9OYitx%6vyYB&d$!vcDuW?rL@~3OMMlwO%*j7Lo_~!g73F{F@+XI0VDW9KaC+` zFp7vHESLyJ!Us@O!-j}SO$Tel z4sA^z|2X}@H~hwHRsQC99i2{2?S7UklsvlUrODBxFnqCR?!vyOo?EcEw>ed&j^Lp{ zjm*YCb?=@{F8x(~Vc!z^|6Kq7bB_$pNe3%>!gQ1(r&^tPXmtyHk^Fe}5&E>+`TLFB z`ef+2sXB+<$n7V$RJyy|-uv?6o<$4hwO1DAsX4y7+`jbXr7!j^YA?@!eo1+5&%EdQ z7WZ~8>RH_LbYE{-rM0vx40B;x8>N)fe+EbfG81Yu>SUm~C7c?%kWl1Ri9e^hQcL-P zCC|@au&}S(v2@-ueT#agmiv;||0ooy6c)nSDpO)7aSQzmCt z!2nj-PEj$u-RLl3M>1{r&f9j7TmSDg@-R%%!Vl$gUJA8B8#vXpkk{<7!1%Qlf(N%cD=~^lAN!Swvqc9za+mL-V9eyTz3+e zN}UzjPff|YBkf&aUpXKO!<`gNun5DQa)9^1Fdcc{lCvi{Ix;){mi#GUJq*)gxC@3# z0YXuL+7Af7UDgi>zg^;|r3mgOZZ}dwX8`q9(=6w;n=(x{swPjIq_7ELSna0rl<*Fu z=11OlHVQ5K;r`)POMDOF^5B!f!84E*mL=`)X2x6lkTS zqW?-Im3>zFpwAq+gLYdWYzwHj1%%ZgWeR3lhSeb9LzMa=3adfc)iu~v5PAE_`7t>( z+8ysFzg49c$gU0$7nK48KcHt3eg`PsU=e-?s1O+`fIN*k0_t4>RW!&OsqE?p zDmE%<9LTN?+B$=v1*Xkp*~UTgt+Q<7psjNtbck4YDF{-amEyAm`nt}Ds>v;-@G+b~ z7vvI*r34%=iva0Kd&0O5GpHXRU-hb5W2(66CnI+T1kHfzR^ zEegh9Fhm)>b)d|l!ewf6Ko|_sl^v=mnaDdr&Tq-o3*GS%@-J5jWh9}a#5tt^!4Ign z2!!8J@^uRU;dhj>4MvLKuXZmPl?qVr1*oFtg9JkQt3B8_BSkqzTsF%}QGj+?+3GRr z8|f{~h4z@-4)XD3gpLz8o1hd0XqT0u9H&4x8Rn|VO%sh29esj$Qf#y?v|y`sp*=x? zb#|dWL9J~@i@7JEHPVzuD@{RqvL;PIda@?Pg>b5tv6t#rY_%S=r)nvC(4HcsJQICX zA9<(A`91N*?~G5AKTYLQFGV|JPacF^fZ7iTzcaRrfbctGPrhD`_AK%BY8xP&2v8Ro zh)mB?ro%?nZN;qWC!p>Lpo*GS1VVbwwql%>ei|j#iG#2$pxzb`+Zv^e z?k6CuMyc&mlZ7S!gA>p?)xqh!{Hdig5rxxvYKnDNfRz}xpmb_h zvKX`12MA{Yv}YmRHb#NIJ`ja;jBtHuDdt|V-$$0E+kjRo-FATjyPs4H?FIXRWM#J( ziKm+!J&iU+>9&h>Ntca6dXcWV)-0Qj+;Q8fSx#eFpj|c%>9}oFL?IoQMtwX)J2XVz zE9|_U4FC05{uRcp_#}>?LE2#%Cv*Ou)42>~P>W&^M$0&@Z!I8XYFdL^?i4G6~o)SU=KE-TsBKSChtJqwMIia_i8`T~`kOHk# z+VpJ>^d*m|nv8d!v|3KObTxC!O-3ti3btBl)72bUXKB;bJh2&XO?LBQv{E^~3Y*IvQAjIn zF84Su$G48n4Gn@8XtmR3wsQHlre?8`R^uGU(E@E(~Z-gyFf_ z)&vO8%~F$BNvRRtQt3$1Yh7Dv8p&geEk>mB*doQ~LLSA)`-Gip<#38RbDuE&BGRgD~p1X92|G{c;xa>@Uh$Y^!YaXvXAic5MvGD4R0?LbC0%iyrmv F`v<^t#329x delta 3371 zcmYM1TWnNS6ozN5&YU^tOsCU1Q(D?`Y4HL`+7wYDF$BXcS`g+K&F7&*F5kqxIDL)G_7s%B0uz zmY)m~6#F{=$7-6=vFF^HO8P#k7+6mGJKi05j?>fqcsx-=fpd`f+i2e4wCq9hv;Gp_ zk!6kr@k7zt!B=J-qPXv8{G?tbEK@2|SSXT(Am=YII&3%`jSeoFf0*LMkG7G6Wl9Hy z1=&Zr%EAJS4%38*{tU@WKHnLILv?dIiG4rqCu9vKos!mx|RSNbo* zFc~;UDfV;p&G3@&D7m$MF$|MpcnpS00ZJ&;en9vgvwlGM9TPt-MX;NAijh)Wp)NJa za$en(Dz{O!xniQia)e>kO*OUtLZs#fP7lR?jao+*ggxX|DSuZ|J5F4yBp{>))Tses zc$~ZmHVVJvG`Yq|5j;_l5~M&YB^7-nl~hhx=`xo&h@Z4&flwAumj#5?NlInSXBk!} zDbQsh3agV+)l5|71t0l zf@g_!cRiM>fVwK6ih89+Dpj4OT$z%Fo>bLq`wW5>m^7QEj9zlBvy{lPEfS|Fy>RrkaupoJ$n@D;j># z5MCnp36)Sv61q&BQ3??JfVxB={4SHLM*s-F%akrLQUtHqT2d+%psod|qUHw)g!GC% z*f1qcxk_APJ}XTD+RsXRfso#_ zqZp=To(73^;vkd-)MWut)*z+yJON=fNE042S;#;Q(vwq77N8+}38uLSPC)Ba1g9ZN z>FWYfI1N#GsHXy~#JB}zQqz*fu)RJ&I18XX3z@cI^7QqAD5S%L>qASicf|fa(k#;k zv{IS25%O$3iKWnv*dIt*svRYsWy*6j+7xBlMrl&LjY2v~GoSWXprs{&^N?a6Mi2jM zDtjn5+nXq(L|QtA%eQJtery@lw5_ArbzpsQBMQSYO6n^J2*WYCeP35v1e@D#(Tcie zbU}TyM76S+A1S1j%?!nIr9dZJ@~erO>RZ@UT%uam!d``Oke0P@RW)8N9M1&KdX9aR zA0V0^u4h;O&B#dF8<_R^f^dXDJx)L*wt-#!*9-{54O})(oqk3JWFwn<9|S2-pFU7U zP2+%&Ze-KAFe8(=iOtOhf);4C;=GAX=MaT<6PueYBea>hOce=&6lkR~Yn$2AH#MSa zGahd;FBuuNEzFg3j8u~vXbgfHcu81q(GewP({s?1qkU*`3by$ zY?49X?BduL`S%huFSCpBDqM(;1d>d9{)YrDu5Y(aScFr%?F0}`?a~SSyCE7xcjp@% zT35fjppmcdwk^OOXm(2r>hbkl;Ou4m=W)%Uy3Ah2AK^D(l#`F|%hx1nW!*k|0$7C6 qK6?T{810i2kQaMSzI`CSCrNWBAF$uXqO7v190, + #[prost(string, tag = "8")] + pub table_kind: ::prost::alloc::string::String, } /// Server-owned behavior for one logical column returned in table details. #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] diff --git a/common/src/search.rs b/common/src/search.rs index 8342a2a..b973142 100644 --- a/common/src/search.rs +++ b/common/src/search.rs @@ -17,7 +17,7 @@ pub const F_ALL_TEXT: &str = "all_text"; pub const F_DATA_WORD: &str = "data_word"; pub const F_DATA_NGRAM: &str = "data_ngram"; pub const F_DATA_EXACT: &str = "data_exact"; -pub const JOURNAL_SEARCH_TABLE_NAME: &str = "journal_entries"; +pub const JOURNAL_TABLE_NAME: &str = "journal_entries"; pub const TOK_WORD: &str = "kw_word"; pub const TOK_NGRAM: &str = "kw_ngram"; diff --git a/search/src/lib.rs b/search/src/lib.rs index 696ce69..fde5b71 100644 --- a/search/src/lib.rs +++ b/search/src/lib.rs @@ -9,9 +9,7 @@ pub use common::proto::komp_ac::search::searcher_server::SearcherServer; use common::proto::komp_ac::search::{ SearchOrderDirection, SearchRequest, SearchResponse, search_response::Hit, }; -use common::search::{ - JOURNAL_SEARCH_TABLE_NAME, SchemaFields, register_tokenizers, search_index_path, -}; +use common::search::{SchemaFields, register_tokenizers, search_index_path}; use query_builder::{ ConstraintMode, SearchConstraint, SearchConstraintTarget, build_master_query, }; @@ -273,10 +271,6 @@ async fn profile_exists(pool: &PgPool, profile_name: &str) -> Result Result { - if table_name == JOURNAL_SEARCH_TABLE_NAME { - return profile_exists(pool, profile_name).await; - } - let exists = sqlx::query_scalar::<_, bool>( r#" SELECT EXISTS( @@ -481,10 +475,6 @@ async fn table_physical_to_display_map( profile_name: &str, table_name: &str, ) -> Result, Status> { - if table_name == JOURNAL_SEARCH_TABLE_NAME { - return Ok(HashMap::new()); - } - let rows = sqlx::query( r#" SELECT tdc.physical_name, tdc.display_name @@ -519,10 +509,6 @@ async fn table_row_display_column( profile_name: &str, table_name: &str, ) -> Result { - if table_name == JOURNAL_SEARCH_TABLE_NAME { - return Ok("journal_name".to_string()); - } - sqlx::query_scalar( r#" SELECT td.row_display_column @@ -674,15 +660,6 @@ async fn fetch_ordered_rows( limit: usize, offset: usize, ) -> Result, Status> { - if table_name == JOURNAL_SEARCH_TABLE_NAME { - if order.is_some() { - return Err(Status::invalid_argument( - "Explicit ordering is not supported for journal search", - )); - } - return fetch_journal_rows(pool, profile_name, limit, offset).await; - } - let physical_to_display = table_physical_to_display_map(pool, profile_name, table_name).await?; let display_column = table_row_display_column(pool, profile_name, table_name).await?; let (resolved_order, direction) = match order { @@ -731,53 +708,6 @@ async fn fetch_ordered_rows( .collect()) } -async fn fetch_journal_rows( - pool: &PgPool, - profile_name: &str, - limit: usize, - offset: usize, -) -> Result, Status> { - let rows = sqlx::query( - r#"WITH positioned AS ( - SELECT journal.*, - ROW_NUMBER() OVER (ORDER BY journal.id) AS picker_position - FROM journal_entries journal - JOIN schemas schema_meta ON schema_meta.id = journal.schema_id - WHERE schema_meta.name = $1 - ) - SELECT id, - to_jsonb(positioned) - 'schema_id' - 'picker_position' AS data, - picker_position - FROM positioned - ORDER BY picker_position DESC - LIMIT $2 OFFSET $3"#, - ) - .bind(profile_name) - .bind(limit as i64) - .bind(offset as i64) - .fetch_all(pool) - .await - .map_err(|error| Status::internal(format!("Journal list query failed: {}", error)))?; - - Ok(rows - .into_iter() - .map(|row| { - let id: i64 = row.try_get("id").unwrap_or_default(); - let json_data: serde_json::Value = row.try_get("data").unwrap_or_default(); - let position: i64 = row.try_get("picker_position").unwrap_or_default(); - Hit { - id, - score: 0.0, - row_display_value: row_display_value(&json_data, "journal_name"), - content_json: json_data.to_string(), - table_name: JOURNAL_SEARCH_TABLE_NAME.to_string(), - row_display_column: "journal_name".to_string(), - position: u64::try_from(position).ok(), - } - }) - .collect()) -} - async fn run_search( pool: &PgPool, profile: &ProfileIndex, @@ -860,11 +790,6 @@ async fn run_search( if let Some(order) = order { let table_name = table_filter.expect("ordered searches require a normalized table filter"); - if table_name == JOURNAL_SEARCH_TABLE_NAME { - return Err(Status::invalid_argument( - "Explicit ordering is not supported for journal search", - )); - } return fetch_ordered_candidate_rows( pool, profile_name, @@ -891,27 +816,14 @@ async fn run_search( let physical_to_display = table_physical_to_display_map(pool, profile_name, &table_name).await?; let display_column = table_row_display_column(pool, profile_name, &table_name).await?; - let rows = if table_name == JOURNAL_SEARCH_TABLE_NAME { - sqlx::query( - r#"SELECT journal.id, to_jsonb(journal) - 'schema_id' AS data - FROM journal_entries journal - JOIN schemas schema_meta ON schema_meta.id = journal.schema_id - WHERE schema_meta.name = $1 AND journal.id = ANY($2)"#, - ) - .bind(profile_name) + let sql = format!( + "SELECT id, to_jsonb(t) AS data FROM {} t WHERE deleted = FALSE AND id = ANY($1)", + qualify_profile_table(profile_name, &table_name) + ); + let rows = sqlx::query(AssertSqlSafe(sql)) .bind(&pg_ids) .fetch_all(pool) .await - } else { - let sql = format!( - "SELECT id, to_jsonb(t) AS data FROM {} t WHERE deleted = FALSE AND id = ANY($1)", - qualify_profile_table(profile_name, &table_name) - ); - sqlx::query(AssertSqlSafe(sql)) - .bind(&pg_ids) - .fetch_all(pool) - .await - } .map_err(|e| Status::internal(format!("Database query failed: {}", e)))?; for row in rows { diff --git a/server b/server index 9e7a186..9fa5673 160000 --- a/server +++ b/server @@ -1 +1 @@ -Subproject commit 9e7a186a0ab247582511598b720c3987443cef3e +Subproject commit 9fa56738c557e46c297b7fd740beacb1d8664681 diff --git a/tui-canvas b/tui-canvas index 8e14380..2a1849f 160000 --- a/tui-canvas +++ b/tui-canvas @@ -1 +1 @@ -Subproject commit 8e143805fdea77dea932ad17e9ec423c1d1c596f +Subproject commit 2a1849fb95d9c942fac4eecf7a260b46a92d3020 diff --git a/tui-pages b/tui-pages index cfce2e5..76e6d56 160000 --- a/tui-pages +++ b/tui-pages @@ -1 +1 @@ -Subproject commit cfce2e590b2277e0defcc0efbc3b227c0060d141 +Subproject commit 76e6d5688fd43a81b72557013d2a0410e240ff23