Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attributes are not sorted, users are not sorted, or previous user didn't consume all the attributes #821

Open
dvv opened this issue Jan 29, 2024 · 20 comments
Labels
bug Something isn't working

Comments

@dvv
Copy link

dvv commented Jan 29, 2024

Describe the bug

Panic "Attributes are not sorted, users are not sorted, or previous user didn't consume all the attributes" after migration.

To Reproduce
Steps to reproduce the behavior:

  1. Migrate from another LDAP via the migration tool
  2. Restart the server
  3. Login
  4. See error

Expected behavior

Server just works.
Is there a way to repack the database (postgresql) to fix the problem?

@dvv dvv added the bug Something isn't working label Jan 29, 2024
@nitnelave
Copy link
Member

Hmm, I can't reproduce the panic. Could you post a sql dump of the DB, or send it to me privately on Discord? Don't worry, I won't be able to get the passwords.

@dvv
Copy link
Author

dvv commented Jan 30, 2024

@nitnelave sorry, no, I don't own it.

Indeed I saw no sorting in migration tool hence user ids come assorted from the source LDAP.
At first I tried to sort them:

--- a/migration-tool/src/main.rs                                                                                                                                      
+++ b/migration-tool/src/main.rs
@@ -23,11 +23,12 @@ fn ask_generic_confirmation(name: &str, message: &str) -> Result<bool> {
 fn get_users_to_add(users: &[User], existing_users: &[String]) -> Result<Option<Vec<User>>> {
     let existing_users = HashSet::<&String>::from_iter(existing_users);
     let num_found_users = users.len();
-    let input_users: Vec<_> = users
+    let mut input_users: Vec<_> = users
         .iter()
         .filter(|u| !existing_users.contains(&u.user_input.id))
         .map(User::clone)
         .collect();
+    input_users.sort_by(|u1, u2| u1.user_input.id.cmp(&u2.user_input.id));
     println!(
         "Found {} users, of which {} new users: [\n  {}\n]",
         num_found_users,

but the error persisted.

Then I commented out the assertion:

--- a/server/src/domain/sql_user_backend_handler.rs
+++ b/server/src/domain/sql_user_backend_handler.rs
@@ -145,11 +145,13 @@ impl UserListerBackendHandler for SqlBackendHandler {
         let mut attributes_iter = attributes.into_iter().peekable();
         use itertools::Itertools; // For take_while_ref
         for user in users.iter_mut() {
+            /*
             assert!(attributes_iter
                 .peek()
                 .map(|u| u.user_id >= user.user.user_id)
                 .unwrap_or(true),
                 "Attributes are not sorted, users are not sorted, or previous user didn't consume all the attributes");
+            */

             user.user.attributes = attributes_iter
                 .take_while_ref(|u| u.user_id == user.user.user_id)

and it worked.

Still I can not use it: I cured symptom but indeed I broke the logic. And I do not understand the logic.

@nitnelave
Copy link
Member

The ordering comes from the SQL query, not the migration: the query is ordered by user id, and so are the attributes. Is there a debug mode in PostgreSQL that prints out the queries? Otherwise, you can run LLDAP with RUST_LOG=debug, I think that should print a lot of things, including the SQL queries used.

As for the logic, we're iterating over the users and the attributes vectors, associating every run of attributes with the same user id with the corresponding user. That relies on both users and attributes to be sorted by user id.

@nitnelave
Copy link
Member

Just to confirm, you used the migration tool provided by LLDAP, correct? Can you confirm that all the user IDs are lowercase in the DB? Something like "SELECT user_id FROM users;" (or select I'd maybe)

@dvv
Copy link
Author

dvv commented Jan 30, 2024

Yes, exactly.

Lowercased:

lldap=# select user_id from users where user_id != lower(user_id);
 user_id
---------
(0 rows)

@dvv
Copy link
Author

dvv commented Jan 30, 2024

I see when listing users in web ui:

auth-lldap-1  | 2024-01-30T18:53:58.923828459+00:00  INFO     LDAP session [ 84.5µs | 36.77% / 100.00% ]
auth-lldap-1  | 2024-01-30T18:53:58.923836389+00:00  INFO     ┕━ LDAP request [ 53.4µs | 63.23% ]
auth-lldap-1  | 2024-01-30T18:53:58.923842956+00:00  DEBUG       ┝━ 🐛 [debug]:  | msg: LdapMsg { msgid: 0, op: SearchRequest(LdapSearchRequest { base: "", scope: Base, alias
es: Never, sizelimit: 0, timelimit: 0, typesonly: false, filter: Present("objectClass"), attrs: ["supportedExtension"] }), ctrl: [] }
auth-lldap-1  | 2024-01-30T18:53:58.923844536+00:00  DEBUG       ┝━ 🐛 [debug]: rootDSE request
auth-lldap-1  | 2024-01-30T18:53:58.923857301+00:00  DEBUG       ┝━ 🐛 [debug]:  | response: SearchResultEntry(LdapSearchResultEntry { dn: "", attributes: [LdapPartialAttribu
te { atype: "objectClass", vals: ["top"] }, LdapPartialAttribute { atype: "vendorName", vals: ["LLDAP"] }, LdapPartialAttribute { atype: "vendorVersion", vals: ["lldap_0.5.1-
alpha"] }, LdapPartialAttribute { atype: "supportedLDAPVersion", vals: ["3"] }, LdapPartialAttribute { atype: "supportedExtension", vals: ["1.3.6.1.4.1.4203.1.11.1"] }, LdapP
artialAttribute { atype: "supportedControl", vals: [] }, LdapPartialAttribute { atype: "supportedFeatures", vals: ["1.3.6.1.4.1.4203.1.5.1"] }, LdapPartialAttribute { atype:
"defaultNamingContext", vals: ["dc=example,dc=com"] }, LdapPartialAttribute { atype: "namingContexts", vals: ["dc=example,dc=com"] }, LdapPartialAttribute { atype: "isGlobalCat
alogReady", vals: ["false"] }] })
auth-lldap-1  | 2024-01-30T18:53:58.923879452+00:00  DEBUG       ┕━ 🐛 [debug]:  | response: SearchResultDone(LdapResult { code: Success, matcheddn: "", message: "", referral
: [] })
auth-lldap-1  | 2024-01-30T18:54:00.764995685+00:00  DEBUG    check_if_token_is_valid [ 81.0µs | 100.00% ]
auth-lldap-1  | 2024-01-30T18:54:00.765075553+00:00  DEBUG    ┕━ 🐛 [debug]:  | return: ValidationResults { user: UserId(CaseInsensitiveString("admin")), permission: Admin }
auth-lldap-1  | thread 'actix-rt|system:0|arbiter:0' panicked at server/src/domain/sql_user_backend_handler.rs:148:13:
auth-lldap-1  | Attributes are not sorted, users are not sorted, or previous user didn't consume all the attributes
auth-lldap-1  | stack backtrace:
auth-lldap-1  |    0: rust_begin_unwind
auth-lldap-1  |              at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/std/src/panicking.rs:597:5
auth-lldap-1  |    1: core::panicking::panic_fmt
auth-lldap-1  |              at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/panicking.rs:72:14
auth-lldap-1  |    2: lldap::domain::sql_user_backend_handler::<impl lldap::domain::handler::UserListerBackendHandler for lldap::domain::sql_backend_handler::SqlBackendHandle
r>::list_users::{{closure}}
auth-lldap-1  |    3: <Handler as lldap::infra::access_control::ReadonlyBackendHandler>::list_users::{{closure}}
auth-lldap-1  |    4: <tracing::instrument::Instrumented<T> as core::future::future::Future>::poll
auth-lldap-1  |    5: <lldap::infra::graphql::query::Query<Handler> as juniper::types::async_await::GraphQLValueAsync<__S>>::resolve_field_async::{{closure}}
auth-lldap-1  |    6: juniper::types::async_await::resolve_selection_set_into_async_recursive::{{closure}}
auth-lldap-1  |    7: juniper::types::async_await::GraphQLValueAsync::resolve_async::{{closure}}
auth-lldap-1  |    8: juniper::http::GraphQLRequest<S>::execute::{{closure}}.34508
auth-lldap-1  |    9: actix_web::handler::handler_service::{{closure}}::{{closure}}
auth-lldap-1  |   10: <actix_web::resource::Resource<T> as actix_web::service::HttpServiceFactory>::register::{{closure}}::{{closure}}
auth-lldap-1  |   11: <core::pin::Pin<P> as core::future::future::Future>::poll
auth-lldap-1  |   12: <actix_web::scope::Scope<T> as actix_web::service::HttpServiceFactory>::register::{{closure}}::{{closure}}
auth-lldap-1  |   13: <actix_web::middleware::condition::ConditionMiddlewareFuture<E,D> as core::future::future::Future>::poll
auth-lldap-1  |   14: actix_http::h1::dispatcher::InnerDispatcher<T,S,B,X,U>::poll_response
auth-lldap-1  |   15: <actix_http::h1::dispatcher::Dispatcher<T,S,B,X,U> as core::future::future::Future>::poll
auth-lldap-1  |   16: tokio::runtime::task::raw::poll
auth-lldap-1  |   17: tokio::task::local::LocalSet::tick
auth-lldap-1  |   18: <tokio::task::local::RunUntil<T> as core::future::future::Future>::poll
auth-lldap-1  |   19: tokio::task::local::LocalSet::run_until::{{closure}}
auth-lldap-1  | note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
auth-lldap-1  | 2024-01-30T18:54:00.767786062+00:00  DEBUG    [GraphQL query] users [ 184ms | 1.79% / 100.00% ]
auth-lldap-1  | 2024-01-30T18:54:00.767794830+00:00  DEBUG    ┝━ 🐛 [debug]:  | filters: None
auth-lldap-1  | 2024-01-30T18:54:00.769259284+00:00  DEBUG    ┝━ 🐛 [debug]:  | summary: "BEGIN" | db.statement: "" | rows_affected: 0 | rows_returned: 0 | elapsed: 647.479µs
auth-lldap-1  | 2024-01-30T18:54:00.772258135+00:00  DEBUG    ┝━ 🐛 [debug]:  | summary: "SELECT \"user_attribute_schema\".\"user_attribute_schema_name\", \"user_attribute_sc
hema\".\"user_attribute_schema_type\", \"user_attribute_schema\".\"user_attribute_schema_is_list\", …" | db.statement: "\n\nSELECT\n  \"user_attribute_schema\".\"user_attribu
te_schema_name\",\n  \"user_attribute_schema\".\"user_attribute_schema_type\",\n  \"user_attribute_schema\".\"user_attribute_schema_is_list\",\n  \"user_attribute_schema\".\"
user_attribute_schema_is_user_visible\",\n  \"user_attribute_schema\".\"user_attribute_schema_is_user_editable\",\n  \"user_attribute_schema\".\"user_attribute_schema_is_hard
coded\"\nFROM\n  \"user_attribute_schema\"\nORDER BY\n  \"user_attribute_schema\".\"user_attribute_schema_name\" ASC\n" | rows_affected: 3 | rows_returned: 3 | elapsed: 2.268
182ms
auth-lldap-1  | 2024-01-30T18:54:00.775296545+00:00  DEBUG    ┝━ 🐛 [debug]:  | summary: "SELECT \"group_attribute_schema\".\"group_attribute_schema_name\", \"group_attribute
_schema\".\"group_attribute_schema_type\", \"group_attribute_schema\".\"group_attribute_schema_is_list\", …" | db.statement: "\n\nSELECT\n  \"group_attribute_schema\".\"group
_attribute_schema_name\",\n  \"group_attribute_schema\".\"group_attribute_schema_type\",\n  \"group_attribute_schema\".\"group_attribute_schema_is_list\",\n  \"group_attribut
e_schema\".\"group_attribute_schema_is_group_visible\",\n  \"group_attribute_schema\".\"group_attribute_schema_is_group_editable\",\n  \"group_attribute_schema\".\"group_attr
ibute_schema_is_hardcoded\"\nFROM\n  \"group_attribute_schema\"\nORDER BY\n  \"group_attribute_schema\".\"group_attribute_schema_name\" ASC\n" | rows_affected: 0 | rows_retur
ned: 0 | elapsed: 2.237188ms
auth-lldap-1  | 2024-01-30T18:54:00.776090725+00:00  DEBUG    ┝━ 🐛 [debug]:  | summary: "COMMIT" | db.statement: "" | rows_affected: 0 | rows_returned: 0 | elapsed: 742.46µs
auth-lldap-1  | 2024-01-30T18:54:00.776229233+00:00  DEBUG    ┕━ list_users [ 181ms | 98.21% ] filters: None | _get_groups: false
auth-lldap-1  | 2024-01-30T18:54:00.807388036+00:00  DEBUG       ┝━ 🐛 [debug]:  | summary: "SELECT \"users\".\"user_id\" AS \"A_user_id\", …" | db.statement: "\n\nSELECT\n
\"users\".\"user_id\" AS \"A_user_id\",\n  \"users\".\"email\" AS \"A_email\",\n  \"users\".\"lowercase_email\" AS \"A_lowercase_email\",\n  \"users\".\"display_name\" AS \"A
_display_name\",\n  \"users\".\"creation_date\" AS \"A_creation_date\",\n  \"users\".\"password_hash\" AS \"A_password_hash\",\n  \"users\".\"totp_secret\" AS \"A_totp_secret
\",\n  \"users\".\"mfa_type\" AS \"A_mfa_type\",\n  \"users\".\"uuid\" AS \"A_uuid\",\n  \"r1\".\"group_id\" AS \"B_group_id\",\n  \"r1\".\"display_name\" AS \"B_display_name
\",\n  \"r1\".\"lowercase_display_name\" AS \"B_lowercase_display_name\",\n  \"r1\".\"creation_date\" AS \"B_creation_date\",\n  \"r1\".\"uuid\" AS \"B_uuid\"\nFROM\n  \"user
s\"\n  LEFT JOIN \"memberships\" AS \"r0\" ON \"users\".\"user_id\" = \"r0\".\"user_id\"\n  LEFT JOIN \"groups\" AS \"r1\" ON \"r0\".\"group_id\" = \"r1\".\"group_id\"\nWHERE
\n  $1\nORDER BY\n  \"users\".\"user_id\" ASC,\n  \"r1\".\"display_name\" ASC\n" | rows_affected: 1246 | rows_returned: 1246 | elapsed: 29.205577ms
auth-lldap-1  | 2024-01-30T18:54:00.845373003+00:00  DEBUG       ┕━ 🐛 [debug]:  | summary: "SELECT \"user_attributes\".\"user_attribute_user_id\", \"user_attributes\".\"user
_attribute_name\", \"user_attributes\".\"user_attribute_value\" …" | db.statement: "\n\nSELECT\n  \"user_attributes\".\"user_attribute_user_id\",\n  \"user_attributes\".\"use
r_attribute_name\",\n  \"user_attributes\".\"user_attribute_value\"\nFROM\n  \"user_attributes\"\nWHERE\n  \"user_attributes\".\"user_attribute_user_id\" IN (\n    $1,\n    $
2,\n    $3,\n    $4,\n    $5,\n    $6,\n    $7,\n    $8,\n    $9,\n    $10,\n    $11,\n    $12,\n    $13,\n    $14,\n    $15,\n    $16,\n    $17,\n    $18,\n    $19,\n    $20
,\n    $21,\n    $22,\n    $23,\n    $24,\n    $25,\n    $26,\n    $27,\n    $28,\n    $29,\n    $30,\n    $31,\n    $32,\n    $33,\n    $34,\n    $35,\n    $36,\n    $37,\n
   $38,\n    $39,\n    $40,\n    $41,\n    $42,\n    $43,\n    $44,\n    $45,\n    $46,\n    $47,\n    $48,\n    $49,\n    $50,\n    $51,\n    $52,\n    $53,\n    $54,\n    $
55,\n    $56,\n    $57,\n    $58,\n    $59,\n    $60,\n    $61,\n    $62,\n    $63,\n    $64,\n    $65,\n    $66,\n    $67,\n    $68,\n    $69,\n    $70,\n    $71,\n    $72,\
n    $73,\n    $74,\n    $75,\n    $76,\n    $77,\n    $78,\n    $79,\n    $80,\n    $81,\n    $82,\n    $83,\n    $84,\n    $85,\n    $86,\n    $87,\n    $88,\n    $89,\n
 $90,\n    $91,\n    $92,\n    $93,\n    $94,\n    $95,\n    $96,\n    $97,\n    $98,\n    $99,\n    $100,\n    $101,\n    $102,\n    $103,\n    $104,\n    $105,\n    $106,\n
    $107,\n    $108,\n    $109,\n    $110,\n    $111,\n    $112,\n    $113,\n    $114,\n    $115,\n    $116,\n    $117,\n    $118,\n    $119,\n    $120,\n    $121,\n    $122,
\n    $123,\n    $124,\n    $125,\n    $126,\n    $127,\n    $128,\n    $129,\n    $130,\n    $131,\n    $132,\n    $133,\n    $134,\n    $135,\n    $136,\n    $137,\n    $13
8,\n    $139,\n    $140,\n    $141,\n    $142,\n    $143,\n    $144,\n    $145,\n    $146,\n    $147,\n    $148,\n    $149,\n    $150,\n    $151,\n    $152,\n    $153,\n    $
154,\n    $155,\n    $156,\n    $157,\n    $158,\n    $159,\n    $160,\n    $161,\n    $162,\n    $163,\n    $164,\n    $165,\n    $166,\n    $167,\n    $168,\n    $169,\n
 $170,\n    $171,\n    $172,\n    $173,\n    $174,\n    $175,\n    $176,\n    $177,\n    $178,\n    $179,\n    $180,\n    $181,\n    $182,\n    $183,\n    $184,\n    $185,\n
   $186,\n    $187,\n    $188,\n    $189,\n    $190,\n    $191,\n    $192,\n    $193,\n    $194,\n    $195,\n    $196,\n    $197,\n    $198,\n    $199,\n    $200,\n    $201,\
n    $202,\n    $203,\n    $204,\n    $205,\n    $206,\n    $207,\n    $208,\n    $209,\n    $210,\n    $211,\n    $212,\n    $213,\n    $214,\n    $215,\n    $216,\n    $217
,\n    $218,\n    $219,\n    $220,\n    $221,\n    $222,\n    $223,\n    $224,\n    $225,\n    $226,\n    $227,\n    $228,\n    $229,\n    $230,\n    $231,\n    $232,\n    $2
33,\n    $234,\n    $235,\n    $236,\n    $237,\n    $238,\n    $239,\n    $240,\n    $241,\n    $242,\n    $243,\n    $244,\n    $245,\n    $246,\n    $247,\n    $248,\n
$249,\n    $250,\n    $251,\n    $252,\n    $253,\n    $254,\n    $255,\n    $256,\n    $257,\n    $258,\n    $259,\n    $260,\n    $261,\n    $262,\n    $263,\n    $264,\n
  $265,\n    $266,\n    $267,\n    $268,\n    $269,\n    $270,\n    $271,\n    $272,\n    $273,\n    $274,\n    $275,\n    $276,\n    $277,\n    $278,\n    $279,\n    $280,\n
    $281,\n    $282,\n    $283,\n    $284,\n    $285,\n    $286,\n    $287,\n    $288,\n    $289,\n    $290,\n    $291,\n    $292,\n    $293,\n    $294,\n    $295,\n    $296,
\n    $297,\n    $298,\n    $299,\n    $300,\n    $301,\n    $302,\n    $303,\n    $304,\n    $305,\n    $306,\n    $307,\n    $308,\n    $309,\n    $310,\n    $311,\n    $31
2,\n    $313,\n    $314,\n    $315,\n    $316,\n    $317,\n    $318,\n    $319,\n    $320,\n    $321,\n    $322,\n    $323,\n    $324,\n    $325,\n    $326,\n    $327,\n    $
328,\n    $329,\n    $330,\n    $331,\n    $332,\n    $333,\n    $334,\n    $335,\n    $336,\n    $337,\n    $338,\n    $339,\n    $340,\n    $341,\n    $342,\n    $343,\n
 $344,\n    $345,\n    $346,\n    $347,\n    $348,\n    $349,\n    $350,\n    $351,\n    $352,\n    $353,\n    $354,\n    $355,\n    $356,\n    $357,\n    $358,\n    $359,\n
   $360,\n    $361,\n    $362,\n    $363,\n    $364,\n    $365,\n    $366,\n    $367,\n    $368,\n    $369,\n    $370,\n    $371,\n    $372,\n    $373,\n    $374,\n    $375,\
n    $376,\n    $377,\n    $378,\n    $379,\n    $380,\n    $381,\n    $382,\n    $383,\n    $384,\n    $385,\n    $386,\n    $387,\n    $388,\n    $389,\n    $390,\n    $391
,\n    $392,\n    $393,\n    $394,\n    $395,\n    $396,\n    $397,\n    $398,\n    $399,\n    $400,\n    $401,\n    $402,\n    $403,\n    $404,\n    $405,\n    $406,\n    $4
07,\n    $408,\n    $409,\n    $410,\n    $411,\n    $412,\n    $413,\n    $414,\n    $415,\n    $416,\n    $417,\n    $418,\n    $419,\n    $420,\n    $421,\n    $422,\n
$423,\n    $424,\n    $425,\n    $426,\n    $427,\n    $428,\n    $429,\n    $430,\n    $431,\n    $432,\n    $433,\n    $434,\n    $435,\n    $436,\n    $437,\n    $438,\n
  $439,\n    $440,\n    $441,\n    $442,\n    $443,\n    $444,\n    $445,\n    $446,\n    $447,\n    $448,\n    $449,\n    $450,\n    $451,\n    $452,\n    $453,\n    $454,\n
    $455,\n    $456,\n    $457,\n    $458,\n    $459,\n    $460,\n    $461,\n    $462,\n    $463,\n    $464,\n    $465,\n    $466,\n    $467,\n    $468,\n    $469,\n    $470,
\n    $471,\n    $472,\n    $473,\n    $474,\n    $475,\n    $476\n  )\nORDER BY\n  \"user_attributes\".\"user_attribute_user_id\" ASC,\n  \"user_attributes\".\"user_attribu........

The only quirk I see is an awful monstrous ... IN (...) clause. But I can not find the query source. Does it come from some ORM? Hmm. What if I'd have much more than 476 users?
IMO such queries should read select ... from ... where foo = any($1) passing the array to the parameter.

@nitnelave
Copy link
Member

Ah, yeah, LLDAP was not built with "big" servers in mind, more for self-hosted homelabs. But still, 476 users is not that much, it should work.

One limitation that we have is that we support only the subset of SQL common to PG, MySQL and SQLite. That often leads us to write less-than-ideal queries. I'll see if it's possible to pass an array, but I didn't think that an online table would be a problem.

@dvv
Copy link
Author

dvv commented Jan 30, 2024

I'm struggling with this:

        let attributes = model::UserAttributes::find()
            //.filter(model::UserAttributesColumn::UserId.is_in(user_ids)) // <-- this may choke
            .filter(model::UserAttributesColumn::UserId.eq(Expr::cust_with_values("ANY(?)", [user_ids]))) <-- this does not compile
            .order_by_asc(model::UserAttributesColumn::UserId)
            .order_by_asc(model::UserAttributesColumn::AttributeName)
            .all(&self.sql_pool)
            .await?;
1.224    Compiling lldap v0.5.1-alpha (/app/server)
4.693 error[E0277]: the trait bound `sea_orm::Value: std::convert::From<std::iter::Map<std::slice::Iter<'_, UserAndGroups>, {closure@server/src/domain/sql_user_backend_handle
r.rs:138:41: 138:44}>>` is not satisfied
4.693    --> server/src/domain/sql_user_backend_handler.rs:141:60
4.693     |
4.693 141 |             .filter(model::UserAttributesColumn::UserId.eq(Expr::cust_with_values("ANY(?)", [user_ids])))
4.693     |                                                            ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<std::iter::Map<std::slice::Iter<'_, UserAndGroups>
, {closure@server/src/domain/sql_user_backend_handler.rs:138:41: 138:44}>>` is not implemented for `sea_orm::Value`
4.693     |
4.693     = help: the following other types implement trait `std::convert::From<T>`:
4.693               <sea_orm::Value as std::convert::From<bool>>
4.693               <sea_orm::Value as std::convert::From<char>>
4.693               <sea_orm::Value as std::convert::From<i8>>
4.693               <sea_orm::Value as std::convert::From<i16>>
4.693               <sea_orm::Value as std::convert::From<i32>>
4.693               <sea_orm::Value as std::convert::From<i64>>
4.693               <sea_orm::Value as std::convert::From<u8>>
4.693               <sea_orm::Value as std::convert::From<u16>>
4.693             and 41 others
4.693     = note: required for `std::iter::Map<std::slice::Iter<'_, UserAndGroups>, {closure@server/src/domain/sql_user_backend_handler.rs:138:41: 138:44}>` to implement `Int
o<sea_orm::Value>`
...

Can you point out what's wrong there?

@nitnelave
Copy link
Member

I'm not in front of the computer, but you can try with user_ids.collect::<Vec<_>>()

@nitnelave
Copy link
Member

Got it to compile with:

        let user_ids: Vec<_> = users.iter().map(|u| u.user.user_id.to_string()).collect();

        let attributes = model::UserAttributes::find()
            //.filter(model::UserAttributesColumn::UserId.eq(Func::cust(Any).arg(user_ids)))
            .filter(Expr::cust_with_exprs(
                "? = ANY(?)",
                [
                    SimpleExpr::Column(model::UserAttributesColumn::UserId.into_column_ref()),
                    user_ids.into(),
                ],
            ))
            .order_by_asc(model::UserAttributesColumn::UserId)
            .order_by_asc(model::UserAttributesColumn::AttributeName)
            .all(&self.sql_pool)
            .await?;

But then we hit Sqlite doesn't support array arguments.

Can you try https://github.com/lldap/lldap/tree/filters instead? I repeat the query above with the same filter as a filter subquery. It's a bit ugly, but it should work (and it passes the tests).

@dvv
Copy link
Author

dvv commented Jan 31, 2024

"filters" downs at the same assert

@dvv
Copy link
Author

dvv commented Jan 31, 2024

Well,

-- sqlite3
select 'test.tools' >= 'testsamba'; -- 0
-- mysql
select 'test.tools' >= 'testsamba'; -- 0
# rust
println!(">= {}", "test.tools" >= "testsamba"); // false

but

-- default postgres from docker
select 'test.tools' >= 'testsamba'; -- true

@nitnelave
Copy link
Member

nitnelave commented Jan 31, 2024 via email

@nitnelave
Copy link
Member

nitnelave commented Jan 31, 2024 via email

@dvv
Copy link
Author

dvv commented Jan 31, 2024

I fix the issue altering the collation of the database.
This one may be closed.
Will you pull filters' query so that no long IN (...) live in the main branch?

@nitnelave
Copy link
Member

@dvv sure. Can you give me the SQL command you ran to update the collation? I'd like to include that in the migration scripts.

@nitnelave
Copy link
Member

On second thought, it shouldn't be necessary: the order should be the same, so just removing the assert should be enough.

@dvv
Copy link
Author

dvv commented Feb 2, 2024

@nitnelave first I tried https://stackoverflow.com/a/61595309

but then just recreated database as follows:

  lldap-db:
    image: postgres:16.1
    environment:
      ...
      LC_COLLATE: C

@dvv
Copy link
Author

dvv commented Feb 2, 2024

Right, I believe we may rely on database sort order -- be it this or that -- the point is to just compact related records, imo.

@nitnelave
Copy link
Member

On third thought, I think the itertools utility used for grouping uses the ordering, so we have to re-sort.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants