array parter

This commit is contained in:
Nate Kelley 2025-07-16 09:54:28 -06:00
parent 5dc31814d8
commit 0d01dfcb4c
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
5 changed files with 78 additions and 5 deletions

View File

@ -14,6 +14,8 @@ const app = new Hono().get(
const { id: userId } = c.get('busterUser');
const options = c.req.valid('query');
console.log(options);
try {
const result: GetUserToOrganizationResponse = await getUserToOrganization({
userId,

View File

@ -1,7 +1,13 @@
import { type InferSelectModel, and, asc, count, eq, isNull, like } from 'drizzle-orm';
import { type InferSelectModel, and, asc, count, eq, inArray, isNull, like } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-zod';
import { z } from 'zod';
import { db } from '../../connection';
import { users, usersToOrganizations } from '../../schema';
import {
userOrganizationRoleEnum,
userOrganizationStatusEnum,
users,
usersToOrganizations,
} from '../../schema';
import { getUserOrganizationId } from '../organizations/organizations';
import { type PaginatedResponse, createPaginatedResponse } from '../shared-types';
import { withPagination } from '../shared-types/with-pagination';
@ -17,6 +23,8 @@ const GetUserToOrganizationInputSchema = z.object({
page_size: z.number().optional().default(250),
user_name: z.string().optional(),
email: z.string().optional(),
role: z.array(z.enum(userOrganizationRoleEnum.enumValues)).optional(),
status: z.array(z.enum(userOrganizationStatusEnum.enumValues)).optional(),
});
type GetUserToOrganizationInput = z.infer<typeof GetUserToOrganizationInputSchema>;
@ -33,7 +41,7 @@ export const getUserToOrganization = async (
params: GetUserToOrganizationInput
): Promise<PaginatedResponse<OrganizationUser>> => {
// Validate and destructure input
const { userId, page, page_size, user_name, email } =
const { userId, page, page_size, user_name, email, role, status } =
GetUserToOrganizationInputSchema.parse(params);
// Get the user's organization ID
@ -49,7 +57,9 @@ export const getUserToOrganization = async (
eq(usersToOrganizations.organizationId, organizationId),
isNull(usersToOrganizations.deletedAt),
user_name ? like(users.name, `%${user_name}%`) : undefined,
email ? like(users.email, `%${email}%`) : undefined
email ? like(users.email, `%${email}%`) : undefined,
role ? inArray(usersToOrganizations.role, role) : undefined,
status ? inArray(usersToOrganizations.status, status) : undefined
);
const getData = withPagination(

View File

@ -1,2 +1,3 @@
export * from './isEqual';
export * from './pagination';
export * from './query-array-preprocessor';

View File

@ -0,0 +1,54 @@
import { z } from 'zod';
/**
* Creates a preprocessor that converts query parameter strings into arrays.
* Handles various input formats:
* - Single value: "admin" ["admin"]
* - Comma-separated: "admin,member" ["admin", "member"]
* - Already an array: ["admin", "member"] ["admin", "member"]
* - No value: undefined undefined
*/
export const createQueryArrayPreprocessor = <T>(schema: z.ZodArray<z.ZodType<T>>) => {
return z.preprocess((val) => {
// Handle no value
if (!val) return undefined;
// Already an array, pass through
if (Array.isArray(val)) return val;
// Handle string input (single or comma-separated)
if (typeof val === 'string') {
return val
.split(',')
.map((item) => item.trim())
.filter(Boolean);
}
// Single value case (wrap in array)
return [val];
}, schema);
};
/**
* Type-safe helper for creating optional query array preprocessors
*/
export const createOptionalQueryArrayPreprocessor = <T>(itemSchema: z.ZodType<T>) => {
return z.preprocess((val) => {
// Handle no value
if (!val) return undefined;
// Already an array, pass through
if (Array.isArray(val)) return val;
// Handle string input (single or comma-separated)
if (typeof val === 'string') {
return val
.split(',')
.map((item) => item.trim())
.filter(Boolean);
}
// Single value case (wrap in array)
return [val];
}, z.array(itemSchema).optional());
};

View File

@ -1,6 +1,8 @@
import { z } from 'zod';
import { OrganizationStatusSchema } from '../organization';
import { OrganizationRoleSchema } from '../organization/roles.types';
import { ShareAssetTypeSchema } from '../share';
import { createOptionalQueryArrayPreprocessor } from '../type-utilities';
export const UserRequestSchema = z.object({
user_id: z.string(),
@ -50,9 +52,13 @@ export type GetUserListRequest = z.infer<typeof GetUserListRequestSchema>;
export const GetUserToOrganizationRequestSchema = z.object({
page: z.coerce.number().min(1).optional().default(1),
page_size: z.coerce.number().min(1).max(5000).optional().default(250),
page_size: z.coerce.number().min(1).max(5000).optional().default(25),
user_name: z.string().optional(),
email: z.string().optional(),
//We need this because the frontend sends the roles as a comma-separated string in the query params
role: createOptionalQueryArrayPreprocessor(OrganizationRoleSchema),
//We need this because the frontend sends the status as a comma-separated string in the query params
status: createOptionalQueryArrayPreprocessor(OrganizationStatusSchema),
});
export type GetUserToOrganizationRequest = z.infer<typeof GetUserToOrganizationRequestSchema>;