mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 20:35:24 +00:00
91 lines
3.2 KiB
TypeScript
91 lines
3.2 KiB
TypeScript
import { sew } from "@/actions";
|
|
import { getRepoPermissionFilterForUser } from "@/prisma";
|
|
import { withOptionalAuthV2 } from "@/withAuthV2";
|
|
import { PrismaClient, UserWithAccounts } from "@sourcebot/db";
|
|
import { createLogger, env, hasEntitlement } from "@sourcebot/shared";
|
|
import { QueryIR } from './ir';
|
|
import { parseQuerySyntaxIntoIR } from './parser';
|
|
import { SearchOptions } from "./types";
|
|
import { createZoektSearchRequest, zoektSearch, zoektStreamSearch } from './zoektSearcher';
|
|
|
|
const logger = createLogger("searchApi");
|
|
|
|
type QueryStringSearchRequest = {
|
|
queryType: 'string';
|
|
query: string;
|
|
options: SearchOptions;
|
|
}
|
|
|
|
type QueryIRSearchRequest = {
|
|
queryType: 'ir';
|
|
query: QueryIR;
|
|
// Omit options that are specific to query syntax parsing.
|
|
options: Omit<SearchOptions, 'isRegexEnabled' | 'isCaseSensitivityEnabled'>;
|
|
}
|
|
|
|
type SearchRequest = QueryStringSearchRequest | QueryIRSearchRequest;
|
|
|
|
export const search = (request: SearchRequest) => sew(() =>
|
|
withOptionalAuthV2(async ({ prisma, user }) => {
|
|
const repoSearchScope = await getAccessibleRepoNamesForUser({ user, prisma });
|
|
|
|
// If needed, parse the query syntax into the query intermediate representation.
|
|
const query = request.queryType === 'string' ? await parseQuerySyntaxIntoIR({
|
|
query: request.query,
|
|
options: request.options,
|
|
prisma,
|
|
}) : request.query;
|
|
|
|
const zoektSearchRequest = await createZoektSearchRequest({
|
|
query,
|
|
options: request.options,
|
|
repoSearchScope,
|
|
});
|
|
|
|
logger.debug(`zoektSearchRequest:\n${JSON.stringify(zoektSearchRequest, null, 2)}`);
|
|
|
|
return zoektSearch(zoektSearchRequest, prisma);
|
|
}));
|
|
|
|
export const streamSearch = (request: SearchRequest) => sew(() =>
|
|
withOptionalAuthV2(async ({ prisma, user }) => {
|
|
const repoSearchScope = await getAccessibleRepoNamesForUser({ user, prisma });
|
|
|
|
// If needed, parse the query syntax into the query intermediate representation.
|
|
const query = request.queryType === 'string' ? await parseQuerySyntaxIntoIR({
|
|
query: request.query,
|
|
options: request.options,
|
|
prisma,
|
|
}) : request.query;
|
|
|
|
const zoektSearchRequest = await createZoektSearchRequest({
|
|
query,
|
|
options: request.options,
|
|
repoSearchScope,
|
|
});
|
|
|
|
logger.debug(`zoektStreamSearchRequest:\n${JSON.stringify(zoektSearchRequest, null, 2)}`);
|
|
|
|
return zoektStreamSearch(zoektSearchRequest, prisma);
|
|
}));
|
|
|
|
/**
|
|
* Returns a list of repository names that the user has access to.
|
|
* If permission syncing is disabled, returns undefined.
|
|
*/
|
|
const getAccessibleRepoNamesForUser = async ({ user, prisma }: { user?: UserWithAccounts, prisma: PrismaClient }) => {
|
|
if (
|
|
env.EXPERIMENT_EE_PERMISSION_SYNC_ENABLED !== 'true' ||
|
|
!hasEntitlement('permission-syncing')
|
|
) {
|
|
return undefined;
|
|
}
|
|
|
|
const accessibleRepos = await prisma.repo.findMany({
|
|
where: getRepoPermissionFilterForUser(user),
|
|
select: {
|
|
name: true,
|
|
}
|
|
});
|
|
return accessibleRepos.map(repo => repo.name);
|
|
}
|