Segment editing.

This commit is contained in:
Mike Cao 2025-07-31 21:32:22 -07:00
parent fba7e12c36
commit 2dbcf63eeb
22 changed files with 306 additions and 42 deletions

View file

@ -3,7 +3,7 @@ import { formatInTimeZone } from 'date-fns-tz';
import debug from 'debug';
import { CLICKHOUSE } from '@/lib/db';
import { DEFAULT_PAGE_SIZE, OPERATORS } from './constants';
import { filtersToArray } from './params';
import { filtersObjectToArray } from './params';
import { QueryFilters, QueryOptions } from './types';
export const CLICKHOUSE_DATE_FORMATS = {
@ -88,7 +88,7 @@ function mapFilter(column: string, operator: string, name: string, type: string
}
function getFilterQuery(filters: Record<string, any>, options: QueryOptions = {}) {
const query = filtersToArray(filters, options).reduce((arr, { name, column, operator }) => {
const query = filtersObjectToArray(filters, options).reduce((arr, { name, column, operator }) => {
if (column) {
arr.push(`and ${mapFilter(column, operator, name)}`);
@ -144,7 +144,7 @@ function getDateQuery(filters: Record<string, any>) {
function getQueryParams(filters: Record<string, any>) {
return {
...filters,
...filtersToArray(filters).reduce((obj, { name, value }) => {
...filtersObjectToArray(filters).reduce((obj, { name, value }) => {
if (name && value !== undefined) {
obj[name] = value;
}

View file

@ -1,7 +1,7 @@
import { FILTER_COLUMNS, OPERATORS } from '@/lib/constants';
import { QueryFilters, QueryOptions } from '@/lib/types';
import { Filter, QueryFilters, QueryOptions } from '@/lib/types';
export function parseParameterValue(param: any) {
export function parseFilterValue(param: any) {
if (typeof param === 'string') {
const [, operator, value] = param.match(/^([a-z]+)\.(.*)/) || [];
@ -18,7 +18,7 @@ export function isSearchOperator(operator: any) {
return [OPERATORS.contains, OPERATORS.doesNotContain].includes(operator);
}
export function filtersToArray(filters: QueryFilters, options: QueryOptions = {}) {
export function filtersObjectToArray(filters: QueryFilters, options: QueryOptions = {}) {
return Object.keys(filters).reduce((arr, key) => {
const filter = filters[key];
@ -30,7 +30,7 @@ export function filtersToArray(filters: QueryFilters, options: QueryOptions = {}
return arr.concat({ ...filter, column: options?.columns?.[key] ?? FILTER_COLUMNS[key] });
}
const { operator, value } = parseParameterValue(filter);
const { operator, value } = parseFilterValue(filter);
return arr.concat({
name: key,
@ -41,3 +41,13 @@ export function filtersToArray(filters: QueryFilters, options: QueryOptions = {}
});
}, []);
}
export function filtersArrayToObject(filters: Filter[]) {
return filters.reduce((obj, filter: Filter) => {
const { name, operator, value } = filter;
obj[name] = `${operator}.${value}`;
return obj;
}, {});
}

View file

@ -4,7 +4,7 @@ import { PrismaPg } from '@prisma/adapter-pg';
import { readReplicas } from '@prisma/extension-read-replicas';
import { SESSION_COLUMNS, OPERATORS, DEFAULT_PAGE_SIZE } from './constants';
import { QueryOptions, QueryFilters } from './types';
import { filtersToArray } from './params';
import { filtersObjectToArray } from './params';
const log = debug('umami:prisma');
@ -95,7 +95,7 @@ function mapCohortFilter(column: string, operator: string, value: string) {
}
function getFilterQuery(filters: Record<string, any>, options: QueryOptions = {}): string {
const query = filtersToArray(filters, options).reduce(
const query = filtersObjectToArray(filters, options).reduce(
(arr, { name, column, operator, prefix = '' }) => {
if (column) {
arr.push(`and ${mapFilter(`${prefix}${column}`, operator, name)}`);
@ -116,7 +116,7 @@ function getFilterQuery(filters: Record<string, any>, options: QueryOptions = {}
}
function getCohortQuery(websiteId: string, filters: QueryFilters = {}, options: QueryOptions = {}) {
const query = filtersToArray(filters, options).reduce(
const query = filtersObjectToArray(filters, options).reduce(
(arr, { name, column, operator, value }) => {
if (column) {
arr.push(
@ -169,7 +169,7 @@ function getDateQuery(filters: Record<string, any>) {
function getQueryParams(filters: Record<string, any>) {
return {
...filters,
...filtersToArray(filters).reduce((obj, { name, operator, value }) => {
...filtersObjectToArray(filters).reduce((obj, { name, operator, value }) => {
obj[name] = [OPERATORS.contains, OPERATORS.doesNotContain].includes(operator)
? `%${value}%`
: value;

View file

@ -24,6 +24,13 @@ export interface Auth {
};
}
export interface Filter {
name: string;
operator: string;
value: string;
type?: string;
}
export interface DateRange {
startDate: Date;
endDate: Date;