diff --git a/server/src/server/user.gleam b/server/src/server/user.gleam index 2d2f3df..dc61e41 100644 --- a/server/src/server/user.gleam +++ b/server/src/server/user.gleam @@ -67,6 +67,30 @@ pub fn find_by_email_prefix( }) } +/// 󰀖 Find all users which name is similar to the given input. +/// Text search supports partial matches. +pub fn find_by_name( + db db: pog.Connection, + name name: String, + limit max: Int, +) -> Result(List(User), UserError) { + use returned <- result.map( + sql.find_by_name(db, name, max) + |> result.map_error(DataBase), + ) + + list.map(returned.rows, fn(row) { + User( + id: row.id, + role: enum_to_role(row.role), + full_name: row.full_name, + email: row.email, + phone: row.phone, + is_active: row.is_active, + ) + }) +} + /// Register an new user in the database /// ///  The password will be **hashed** before inserted. diff --git a/server/src/server/user/sql.gleam b/server/src/server/user/sql.gleam index d289595..61aa6fa 100644 --- a/server/src/server/user/sql.gleam +++ b/server/src/server/user/sql.gleam @@ -124,6 +124,71 @@ limit $2; |> pog.execute(db) } +/// A row you get from running the `find_by_name` query +/// defined in `./src/server/user/sql/find_by_name.sql`. +/// +/// > 🐿️ This type definition was generated automatically using v4.6.0 of the +/// > [squirrel package](https://github.com/giacomocavalieri/squirrel). +/// +pub type FindByNameRow { + FindByNameRow( + id: Uuid, + role: UserRoleEnum, + full_name: String, + email: String, + phone: String, + is_active: Bool, + ) +} + +///  Find a user by their name +/// +/// > 🐿️ This function was generated automatically using v4.6.0 of +/// > the [squirrel package](https://github.com/giacomocavalieri/squirrel). +/// +pub fn find_by_name( + db: pog.Connection, + arg_1: String, + arg_2: Int, +) -> Result(pog.Returned(FindByNameRow), pog.QueryError) { + let decoder = { + use id <- decode.field(0, uuid_decoder()) + use role <- decode.field(1, user_role_enum_decoder()) + use full_name <- decode.field(2, decode.string) + use email <- decode.field(3, decode.string) + use phone <- decode.field(4, decode.string) + use is_active <- decode.field(5, decode.bool) + decode.success(FindByNameRow( + id:, + role:, + full_name:, + email:, + phone:, + is_active:, + )) + } + + "--  Find a user by their name +select + u.id, + u.user_role as role, + u.full_name, + u.email, + u.phone, + u.is_active +from user_account as u +where + to_tsvector('simple', u.full_name) + @@ websearch_to_tsquery ('simple', $1::text || ':*') --noqa +limit $2; +" + |> pog.query + |> pog.parameter(pog.text(arg_1)) + |> pog.parameter(pog.int(arg_2)) + |> pog.returning(decoder) + |> pog.execute(db) +} + /// A row you get from running the `register` query /// defined in `./src/server/user/sql/register.sql`. /// diff --git a/server/src/server/user/sql/find_by_name.sql b/server/src/server/user/sql/find_by_name.sql new file mode 100644 index 0000000..c4ee2a4 --- /dev/null +++ b/server/src/server/user/sql/find_by_name.sql @@ -0,0 +1,13 @@ +--  Find a user by their name +select + u.id, + u.user_role as role, + u.full_name, + u.email, + u.phone, + u.is_active +from user_account as u +where + to_tsvector('simple', u.full_name) + @@ websearch_to_tsquery ('simple', $1::text || ':*') --noqa +limit $2; diff --git a/sql/create/tables.sql b/sql/create/tables.sql index b42ad93..f3ca77a 100644 --- a/sql/create/tables.sql +++ b/sql/create/tables.sql @@ -32,6 +32,11 @@ create table user_account ( create index idx_user_account_email_lowercase on user_account (email_lowercase); +create index idx_user_account_full_name_tsvector +on user_account +using gin (to_tsvector('simple', full_name)); + + create table crew ( id uuid default uuidv7(), crew_leader uuid not null references user_account (id)