From 14c7942f68e46da5825323928c53e80c59576fe6 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 13:05:22 +0100 Subject: [PATCH 01/41] feat: step 1 - remove recordings-ingestion capability from plugin server --- plugin-server/src/capabilities.ts | 7 - .../session-recordings-consumer-v1.ts | 402 ------------------ plugin-server/src/main/pluginsServer.ts | 24 -- plugin-server/src/types.ts | 2 - .../session-recordings-consumer-v1.test.ts | 182 -------- posthog/api/capture.py | 11 - posthog/settings/ingestion.py | 7 - 7 files changed, 635 deletions(-) delete mode 100644 plugin-server/src/main/ingestion-queues/session-recording/session-recordings-consumer-v1.ts delete mode 100644 plugin-server/tests/main/ingestion-queues/session-recording/session-recordings-consumer-v1.test.ts diff --git a/plugin-server/src/capabilities.ts b/plugin-server/src/capabilities.ts index 1468412020651..bbb8a49823ed7 100644 --- a/plugin-server/src/capabilities.ts +++ b/plugin-server/src/capabilities.ts @@ -18,7 +18,6 @@ export function getPluginServerCapabilities(config: PluginsServerConfig): Plugin processPluginJobs: true, processAsyncOnEventHandlers: true, processAsyncWebhooksHandlers: true, - sessionRecordingIngestion: true, sessionRecordingBlobIngestion: true, transpileFrontendApps: true, preflightSchedules: true, @@ -30,7 +29,6 @@ export function getPluginServerCapabilities(config: PluginsServerConfig): Plugin return { mmdb: true, ingestion: true, - sessionRecordingIngestion: true, ...sharedCapabilities, } case PluginServerMode.ingestion_overflow: @@ -51,11 +49,6 @@ export function getPluginServerCapabilities(config: PluginsServerConfig): Plugin ingestion: true, ...sharedCapabilities, } - case PluginServerMode.recordings_ingestion: - return { - sessionRecordingIngestion: true, - ...sharedCapabilities, - } case PluginServerMode.recordings_blob_ingestion: return { sessionRecordingBlobIngestion: true, diff --git a/plugin-server/src/main/ingestion-queues/session-recording/session-recordings-consumer-v1.ts b/plugin-server/src/main/ingestion-queues/session-recording/session-recordings-consumer-v1.ts deleted file mode 100644 index 7f1c6f3fdd2f9..0000000000000 --- a/plugin-server/src/main/ingestion-queues/session-recording/session-recordings-consumer-v1.ts +++ /dev/null @@ -1,402 +0,0 @@ -import { PluginEvent } from '@posthog/plugin-scaffold' -import { captureException, captureMessage } from '@sentry/node' -import { DateTime } from 'luxon' -import { HighLevelProducer as RdKafkaProducer, Message, NumberNullUndefined } from 'node-rdkafka-acosom' - -import { - KAFKA_CLICKHOUSE_SESSION_RECORDING_EVENTS, - KAFKA_CLICKHOUSE_SESSION_REPLAY_EVENTS, - KAFKA_PERFORMANCE_EVENTS, - KAFKA_SESSION_RECORDING_EVENTS, - KAFKA_SESSION_RECORDING_EVENTS_DLQ, -} from '../../../config/kafka-topics' -import { startBatchConsumer } from '../../../kafka/batch-consumer' -import { createRdConnectionConfigFromEnvVars } from '../../../kafka/config' -import { retryOnDependencyUnavailableError } from '../../../kafka/error-handling' -import { createKafkaProducer, disconnectProducer, flushProducer, produce } from '../../../kafka/producer' -import { PipelineEvent, RawEventMessage, Team } from '../../../types' -import { KafkaConfig } from '../../../utils/db/hub' -import { status } from '../../../utils/status' -import { - createPerformanceEvent, - createSessionRecordingEvent, - createSessionReplayEvent, - SummarizedSessionRecordingEvent, -} from '../../../worker/ingestion/process-event' -import { TeamManager } from '../../../worker/ingestion/team-manager' -import { parseEventTimestamp } from '../../../worker/ingestion/timestamps' -import { eventDroppedCounter } from '../metrics' - -export const startSessionRecordingEventsConsumerV1 = async ({ - teamManager, - kafkaConfig, - consumerMaxBytes, - consumerMaxBytesPerPartition, - consumerMaxWaitMs, - consumerErrorBackoffMs, - batchingTimeoutMs, - topicCreationTimeoutMs, -}: { - teamManager: TeamManager - kafkaConfig: KafkaConfig - consumerMaxBytes: number - consumerMaxBytesPerPartition: number - consumerMaxWaitMs: number - consumerErrorBackoffMs: number - batchingTimeoutMs: number - topicCreationTimeoutMs: number -}) => { - /* - For Session Recordings we need to prepare the data for ClickHouse. - Additionally, we process `$performance_event` events which are closely - tied to session recording events. - - We use the node-rdkafka library for handling consumption and production - from Kafka. Note that this is different from the other consumers as this - is a test bed for consumer improvements, which should be ported to the - other consumers. - - We consume batches of messages, process these to completion, including - getting acknowledgements that the messages have been pushed to Kafka, - then commit the offsets of the messages we have processed. We do this - instead of going completely stream happy just to keep the complexity - low. We may well move this ingester to a different framework - specifically for stream processing so no need to put too much work into - this. - */ - - const groupId = 'session-recordings' - const sessionTimeout = 30000 - const fetchBatchSize = 500 - - status.info('🔁', 'Starting session recordings consumer') - - const connectionConfig = createRdConnectionConfigFromEnvVars(kafkaConfig) - const producer = await createKafkaProducer(connectionConfig) - - const eachBatchWithContext = eachBatch({ - teamManager, - producer, - }) - - // Create a node-rdkafka consumer that fetches batches of messages, runs - // eachBatchWithContext, then commits offsets for the batch. - const consumer = await startBatchConsumer({ - connectionConfig, - groupId, - topic: KAFKA_SESSION_RECORDING_EVENTS, - sessionTimeout, - consumerMaxBytesPerPartition, - consumerMaxBytes, - consumerMaxWaitMs, - consumerErrorBackoffMs, - fetchBatchSize, - batchingTimeoutMs, - topicCreationTimeoutMs, - eachBatch: eachBatchWithContext, - }) - - // Make sure to disconnect the producer after we've finished consuming. - consumer.join().finally(async () => { - await disconnectProducer(producer) - }) - - return consumer -} - -export const eachBatch = - ({ teamManager, producer }: { teamManager: TeamManager; producer: RdKafkaProducer }) => - async (messages: Message[]) => { - // To start with, we simply process each message in turn, - // without attempting to perform any concurrency. There is a lot - // of caching e.g. for team lookups so not so much IO going on - // anyway. - // - // Where we do allow some parallelism is in the producing to - // Kafka. The eachMessage function will return a Promise for any - // produce requests, rather than blocking on them. This way we - // can handle errors for the main processing, and the production - // errors separately. - // - // For the main processing errors we will check to see if they - // are intermittent errors, and if so, we will retry the - // processing of the message. If the error is not intermittent, - // we will simply stop processing as we assume this is a code - // issue that will need to be resolved. We use - // DependencyUnavailableError error to distinguish between - // intermittent and permanent errors. - const pendingProduceRequests: Promise[] = [] - const eachMessageWithContext = eachMessage({ teamManager, producer }) - - for (const message of messages) { - const results = await retryOnDependencyUnavailableError(() => eachMessageWithContext(message)) - if (results) { - pendingProduceRequests.push(...results) - } - } - - // On each loop, we flush the producer to ensure that all messages - // are sent to Kafka. - try { - await flushProducer(producer) - } catch (error) { - // Rather than handling errors from flush, we instead handle - // errors per produce request, which gives us a little more - // flexibility in terms of deciding if it is a terminal - // error or not. - } - - // We wait on all the produce requests to complete. After the - // flush they should all have been resolved/rejected already. If - // we get an intermittent error, such as a Kafka broker being - // unavailable, we will throw. We are relying on the Producer - // already having handled retries internally. - for (const produceRequest of pendingProduceRequests) { - try { - await produceRequest - } catch (error) { - status.error('🔁', 'main_loop_error', { error }) - - if (error?.isRetriable) { - // We assume the if the error is retriable, then we - // are probably in a state where e.g. Kafka is down - // temporarily and we would rather simply throw and - // have the process restarted. - throw error - } - } - } - } - -const eachMessage = - ({ teamManager, producer }: { teamManager: TeamManager; producer: RdKafkaProducer }) => - async (message: Message) => { - // For each message, we: - // - // 1. Check that the message is valid. If not, send it to the DLQ. - // 2. Parse the message and extract the event. - // 3. Get the associated team for the event. - // 4. Convert the event to something we can insert into ClickHouse. - - if (!message.value || !message.timestamp) { - status.warn('⚠️', 'invalid_message', { - reason: 'empty', - offset: message.offset, - partition: message.partition, - }) - return [ - produce({ - producer, - topic: KAFKA_SESSION_RECORDING_EVENTS_DLQ, - value: message.value, - key: message.key ? Buffer.from(message.key) : null, - }), - ] - } - - let messagePayload: RawEventMessage - let event: PipelineEvent - - try { - // NOTE: we need to parse the JSON for these events because we - // need to add in the team_id to events, as it is possible due - // to a drive to remove postgres dependency on the the capture - // endpoint we may only have `token`. - messagePayload = JSON.parse(message.value.toString()) - event = JSON.parse(messagePayload.data) - } catch (error) { - status.warn('⚠️', 'invalid_message', { - reason: 'invalid_json', - error: error, - offset: message.offset, - partition: message.partition, - }) - return [ - produce({ - producer, - topic: KAFKA_SESSION_RECORDING_EVENTS_DLQ, - value: message.value, - key: message.key ? Buffer.from(message.key) : null, - }), - ] - } - - status.debug('⬆️', 'processing_session_recording', { uuid: messagePayload.uuid }) - - if (messagePayload.team_id == null && !messagePayload.token) { - eventDroppedCounter - .labels({ - event_type: 'session_recordings', - drop_cause: 'no_token', - }) - .inc() - status.warn('⚠️', 'invalid_message', { - reason: 'no_token', - offset: message.offset, - partition: message.partition, - }) - return - } - - let team: Team | null = null - - if (messagePayload.team_id != null) { - team = await teamManager.fetchTeam(messagePayload.team_id) - } else if (messagePayload.token) { - team = await teamManager.getTeamByToken(messagePayload.token) - } - - if (team == null) { - eventDroppedCounter - .labels({ - event_type: 'session_recordings', - drop_cause: 'invalid_token', - }) - .inc() - status.warn('⚠️', 'invalid_message', { - reason: 'team_not_found', - offset: message.offset, - partition: message.partition, - }) - return - } - - if (team.session_recording_opt_in) { - try { - if (event.event === '$snapshot_items') { - eventDroppedCounter - .labels({ - event_type: 'session_recordings', - drop_cause: 'recordings-consumer-does-not-handle-snapshot-items', - }) - .inc() - } else if (event.event === '$snapshot') { - const clickHouseRecord = createSessionRecordingEvent( - messagePayload.uuid, - team.id, - messagePayload.distinct_id, - parseEventTimestamp(event as PluginEvent), - event.properties || {} - ) - - let replayRecord: null | SummarizedSessionRecordingEvent = null - try { - const properties = event.properties || {} - const shouldCreateReplayEvents = (properties['$snapshot_consumer'] ?? 'v1') === 'v1' - const eventsSummary: any[] = properties.$snapshot_data?.events_summary || [] - - if (shouldCreateReplayEvents && eventsSummary.length) { - replayRecord = createSessionReplayEvent( - messagePayload.uuid, - team.id, - messagePayload.distinct_id, - properties['$session_id'], - eventsSummary - ) - } - // the replay record timestamp has to be valid and be within a reasonable diff from now - if (replayRecord !== null) { - const asDate = DateTime.fromSQL(replayRecord.first_timestamp) - if (!asDate.isValid || Math.abs(asDate.diffNow('months').months) >= 0.99) { - captureMessage( - `Invalid replay record timestamp: ${replayRecord.first_timestamp} for event ${messagePayload.uuid}`, - { - extra: { - replayRecord, - uuid: clickHouseRecord.uuid, - timestamp: clickHouseRecord.timestamp, - }, - tags: { - team: team.id, - session_id: clickHouseRecord.session_id, - }, - } - ) - replayRecord = null - } - } - } catch (e) { - status.warn('??', 'session_replay_summarizer_error', { error: e }) - captureException(e, { - extra: { - clickHouseRecord: { - uuid: clickHouseRecord.uuid, - timestamp: clickHouseRecord.timestamp, - snapshot_data: clickHouseRecord.snapshot_data, - }, - replayRecord, - }, - tags: { - team: team.id, - session_id: clickHouseRecord.session_id, - chunk_index: event.properties?.['$snapshot_data']?.chunk_index || 'unknown', - chunk_count: event.properties?.['$snapshot_data']?.chunk_count || 'unknown', - }, - }) - } - - const producePromises = [ - produce({ - producer, - topic: KAFKA_CLICKHOUSE_SESSION_RECORDING_EVENTS, - value: Buffer.from(JSON.stringify(clickHouseRecord)), - key: message.key ? Buffer.from(message.key) : null, - }), - ] - - if (replayRecord) { - producePromises.push( - produce({ - producer, - topic: KAFKA_CLICKHOUSE_SESSION_REPLAY_EVENTS, - value: Buffer.from(JSON.stringify(replayRecord)), - key: message.key ? Buffer.from(message.key) : null, - }) - ) - } - return producePromises - } else if (event.event === '$performance_event') { - const clickHouseRecord = createPerformanceEvent( - messagePayload.uuid, - team.id, - messagePayload.distinct_id, - event.properties || {} - ) - - return [ - produce({ - producer, - topic: KAFKA_PERFORMANCE_EVENTS, - value: Buffer.from(JSON.stringify(clickHouseRecord)), - key: message.key ? Buffer.from(message.key) : null, - }), - ] - } else { - status.warn('⚠️', 'invalid_message', { - reason: 'invalid_event_type', - type: event.event, - offset: message.offset, - partition: message.partition, - }) - eventDroppedCounter - .labels({ - event_type: 'session_recordings', - drop_cause: 'invalid_event_type', - }) - .inc() - } - } catch (error) { - status.error('⚠️', 'processing_error', { - eventId: event.uuid, - error: error, - }) - } - } else { - eventDroppedCounter - .labels({ - event_type: 'session_recordings', - drop_cause: 'disabled', - }) - .inc() - } - } diff --git a/plugin-server/src/main/pluginsServer.ts b/plugin-server/src/main/pluginsServer.ts index 08fc4c6ed0e66..0c18c94554d68 100644 --- a/plugin-server/src/main/pluginsServer.ts +++ b/plugin-server/src/main/pluginsServer.ts @@ -34,7 +34,6 @@ import { startAsyncWebhooksHandlerConsumer, } from './ingestion-queues/on-event-handler-consumer' import { startScheduledTasksConsumer } from './ingestion-queues/scheduled-tasks-consumer' -import { startSessionRecordingEventsConsumerV1 } from './ingestion-queues/session-recording/session-recordings-consumer-v1' import { SessionRecordingIngesterV2 } from './ingestion-queues/session-recording/session-recordings-consumer-v2' import { createHttpServer } from './services/http-server' import { getObjectStorage } from './services/object_storage' @@ -392,29 +391,6 @@ export async function startPluginsServer( hub.lastActivityType = 'serverStart' } - if (capabilities.sessionRecordingIngestion) { - const statsd = hub?.statsd ?? createStatsdClient(serverConfig, null) - const postgres = hub?.postgres ?? new PostgresRouter(serverConfig, statsd) - const teamManager = hub?.teamManager ?? new TeamManager(postgres, serverConfig) - const { - stop, - isHealthy: isSessionRecordingsHealthy, - join, - } = await startSessionRecordingEventsConsumerV1({ - teamManager: teamManager, - kafkaConfig: serverConfig, - consumerMaxBytes: serverConfig.KAFKA_CONSUMPTION_MAX_BYTES, - consumerMaxBytesPerPartition: serverConfig.KAFKA_CONSUMPTION_MAX_BYTES_PER_PARTITION, - consumerMaxWaitMs: serverConfig.KAFKA_CONSUMPTION_MAX_WAIT_MS, - consumerErrorBackoffMs: serverConfig.KAFKA_CONSUMPTION_ERROR_BACKOFF_MS, - batchingTimeoutMs: serverConfig.KAFKA_CONSUMPTION_BATCHING_TIMEOUT_MS, - topicCreationTimeoutMs: serverConfig.KAFKA_TOPIC_CREATION_TIMEOUT_MS, - }) - stopSessionRecordingEventsConsumer = stop - joinSessionRecordingEventsConsumer = join - healthChecks['session-recordings'] = isSessionRecordingsHealthy - } - if (capabilities.sessionRecordingBlobIngestion) { const recordingConsumerConfig = sessionRecordingConsumerConfig(serverConfig) const statsd = hub?.statsd ?? createStatsdClient(serverConfig, null) diff --git a/plugin-server/src/types.ts b/plugin-server/src/types.ts index 3c16957e997f8..d25e3bb81e9b3 100644 --- a/plugin-server/src/types.ts +++ b/plugin-server/src/types.ts @@ -77,7 +77,6 @@ export enum PluginServerMode { jobs = 'jobs', scheduler = 'scheduler', analytics_ingestion = 'analytics-ingestion', - recordings_ingestion = 'recordings-ingestion', recordings_blob_ingestion = 'recordings-blob-ingestion', } @@ -286,7 +285,6 @@ export interface PluginServerCapabilities { processPluginJobs?: boolean processAsyncOnEventHandlers?: boolean processAsyncWebhooksHandlers?: boolean - sessionRecordingIngestion?: boolean sessionRecordingBlobIngestion?: boolean transpileFrontendApps?: boolean // TODO: move this away from pod startup, into a graphile job preflightSchedules?: boolean // Used for instance health checks on hobby deploy, not useful on cloud diff --git a/plugin-server/tests/main/ingestion-queues/session-recording/session-recordings-consumer-v1.test.ts b/plugin-server/tests/main/ingestion-queues/session-recording/session-recordings-consumer-v1.test.ts deleted file mode 100644 index d9fe676086d05..0000000000000 --- a/plugin-server/tests/main/ingestion-queues/session-recording/session-recordings-consumer-v1.test.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { DateTime } from 'luxon' -import LibrdKafkaError from 'node-rdkafka-acosom/lib/error' - -import { defaultConfig } from '../../../../src/config/config' -import { eachBatch } from '../../../../src/main/ingestion-queues/session-recording/session-recordings-consumer-v1' -import { now } from '../../../../src/main/ingestion-queues/session-recording/utils' -import { PostgresRouter } from '../../../../src/utils/db/postgres' -import { TeamManager } from '../../../../src/worker/ingestion/team-manager' -import { createOrganization, createTeam } from '../../../helpers/sql' - -describe('session-recordings-consumer', () => { - const producer = { - produce: jest.fn(), - flush: jest.fn(), - } as any - let postgres: PostgresRouter - let teamManager: TeamManager - let eachBachWithDependencies: any - - beforeEach(() => { - postgres = new PostgresRouter(defaultConfig, undefined) - teamManager = new TeamManager(postgres, {} as any) - eachBachWithDependencies = eachBatch({ producer, teamManager }) - }) - - afterEach(() => { - jest.clearAllMocks() - }) - - test('eachBatch throws on recoverable Kafka errors', async () => { - const organizationId = await createOrganization(postgres) - const teamId = await createTeam(postgres, organizationId) - const error = new LibrdKafkaError({ message: 'test', code: 1, errno: 1, origin: 'test', isRetriable: true }) - producer.produce.mockImplementation( - (_topic: any, _partition: any, _message: any, _key: any, _timestamp: any, _headers: any, cb: any) => - cb(error) - ) - producer.flush.mockImplementation((_timeout: any, cb: any) => cb(null)) - await expect( - eachBachWithDependencies([ - { - key: 'test', - value: JSON.stringify({ team_id: teamId, data: JSON.stringify({ event: '$snapshot' }) }), - }, - ]) - ).rejects.toEqual(error) - }) - - test('eachBatch emits to DLQ and returns on unrecoverable KafkaJS errors', async () => { - const organizationId = await createOrganization(postgres) - const teamId = await createTeam(postgres, organizationId) - const error = new LibrdKafkaError({ message: 'test', code: 1, errno: 1, origin: 'test', isRetriable: false }) - producer.produce.mockImplementation( - (_topic: any, _partition: any, _message: any, _key: any, _timestamp: any, _headers: any, cb: any) => - cb(error) - ) - producer.flush.mockImplementation((_timeout: any, cb: any) => cb(null)) - await eachBachWithDependencies([ - { - key: 'test', - value: JSON.stringify({ team_id: teamId, data: JSON.stringify({ event: '$snapshot' }) }), - }, - ]) - - // Should have sent to the DLQ. - expect(producer.produce).toHaveBeenCalledTimes(1) - }) - - test('eachBatch emits to only one topic', async () => { - const organizationId = await createOrganization(postgres) - const teamId = await createTeam(postgres, organizationId) - - await eachBachWithDependencies([ - { - key: 'test', - value: JSON.stringify({ team_id: teamId, data: JSON.stringify({ event: '$snapshot' }) }), - timestamp: 123, - }, - ]) - - expect(producer.produce).toHaveBeenCalledTimes(1) - }) - - test('eachBatch can emit to two topics', async () => { - const organizationId = await createOrganization(postgres) - const teamId = await createTeam(postgres, organizationId) - - const eachBachWithDependencies: any = eachBatch({ producer, teamManager }) - - await eachBachWithDependencies([ - { - key: 'test', - value: JSON.stringify({ - team_id: teamId, - data: JSON.stringify({ - event: '$snapshot', - properties: { $snapshot_data: { events_summary: [{ timestamp: now() }] } }, - }), - }), - timestamp: 123, - }, - ]) - - expect(producer.produce).toHaveBeenCalledTimes(2) - }) - - test('eachBatch does not emit replay event if set to other consumer', async () => { - const organizationId = await createOrganization(postgres) - const teamId = await createTeam(postgres, organizationId) - - const eachBachWithDependencies: any = eachBatch({ producer, teamManager }) - - await eachBachWithDependencies([ - { - key: 'test', - value: JSON.stringify({ - team_id: teamId, - data: JSON.stringify({ - event: '$snapshot', - properties: { - $snapshot_data: { events_summary: [{ timestamp: now() }] }, - $snapshot_consumer: 'v2', - }, - }), - }), - timestamp: 123, - }, - ]) - - expect(producer.produce).toHaveBeenCalledTimes(1) - }) - - test('eachBatch does not emit a replay record that is more than a month in the future', async () => { - const organizationId = await createOrganization(postgres) - const teamId = await createTeam(postgres, organizationId) - - const eachBachWithDependencies: any = eachBatch({ producer, teamManager }) - - const aMonthInFuture = DateTime.now().plus({ months: 1 }).toMillis() - - await eachBachWithDependencies([ - { - key: 'test', - value: JSON.stringify({ - team_id: teamId, - data: JSON.stringify({ - event: '$snapshot', - properties: { $snapshot_data: { events_summary: [{ timestamp: aMonthInFuture }] } }, - }), - }), - timestamp: 123, - }, - ]) - - expect(producer.produce).toHaveBeenCalledTimes(1) - }) - - test('eachBatch does not emit a replay record that is more than a month in the past', async () => { - const organizationId = await createOrganization(postgres) - const teamId = await createTeam(postgres, organizationId) - - const eachBachWithDependencies: any = eachBatch({ producer, teamManager }) - - const aMonthInFuture = DateTime.now().minus({ months: 1 }).toMillis() - - await eachBachWithDependencies([ - { - key: 'test', - value: JSON.stringify({ - team_id: teamId, - data: JSON.stringify({ - event: '$snapshot', - properties: { $snapshot_data: { events_summary: [{ timestamp: aMonthInFuture }] } }, - }), - }), - timestamp: 123, - }, - ]) - - expect(producer.produce).toHaveBeenCalledTimes(1) - }) -}) diff --git a/posthog/api/capture.py b/posthog/api/capture.py index c3b45cafef816..8b6a576012d9b 100644 --- a/posthog/api/capture.py +++ b/posthog/api/capture.py @@ -3,7 +3,6 @@ import re import time from datetime import datetime -from random import random from typing import Any, Dict, Iterator, List, Optional, Tuple import structlog @@ -367,8 +366,6 @@ def get_event(request): # NOTE: Whilst we are testing this code we want to track exceptions but allow the events through if anything goes wrong capture_exception(e) - consumer_destination = "v2" if random() <= settings.REPLAY_EVENTS_NEW_CONSUMER_RATIO else "v1" - try: replay_events, other_events = split_replay_events(events) processed_replay_events = replay_events @@ -377,10 +374,6 @@ def get_event(request): # Legacy solution stays in place processed_replay_events = legacy_preprocess_session_recording_events_for_clickhouse(replay_events) - # Mark all events so that they are only consumed by one consumer - for event in processed_replay_events: - event["properties"]["$snapshot_consumer"] = consumer_destination - events = processed_replay_events + other_events except ValueError as e: @@ -459,10 +452,6 @@ def get_event(request): replay_events, settings.SESSION_RECORDING_KAFKA_MAX_REQUEST_SIZE_BYTES ) - # Mark all events so that they are only consumed by one consumer - for event in alternative_replay_events: - event["properties"]["$snapshot_consumer"] = consumer_destination - futures = [] # We want to be super careful with our new ingestion flow for now so the whole thing is separated diff --git a/posthog/settings/ingestion.py b/posthog/settings/ingestion.py index a970414f04fd1..fb9d07cf964a2 100644 --- a/posthog/settings/ingestion.py +++ b/posthog/settings/ingestion.py @@ -31,13 +31,6 @@ ) REPLAY_EVENT_MAX_SIZE = get_from_env("REPLAY_EVENT_MAX_SIZE", type_cast=int, default=1024 * 512) # 512kb -REPLAY_EVENTS_NEW_CONSUMER_RATIO = get_from_env("REPLAY_EVENTS_NEW_CONSUMER_RATIO", type_cast=float, default=0.0) - -if REPLAY_EVENTS_NEW_CONSUMER_RATIO > 1 or REPLAY_EVENTS_NEW_CONSUMER_RATIO < 0: - logger.critical( - "Environment variable REPLAY_EVENTS_NEW_CONSUMER_RATIO is not between 0 and 1. Setting to 0 to be safe." - ) - REPLAY_EVENTS_NEW_CONSUMER_RATIO = 0 REPLAY_RETENTION_DAYS_MIN = 30 REPLAY_RETENTION_DAYS_MAX = 90 From c71516867ca7fdbffddce75afe861990de10def6 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 13:26:03 +0100 Subject: [PATCH 02/41] fix --- posthog/api/test/test_capture.py | 1 - 1 file changed, 1 deletion(-) diff --git a/posthog/api/test/test_capture.py b/posthog/api/test/test_capture.py index 14b5238ac7cb9..8d5be14170913 100644 --- a/posthog/api/test/test_capture.py +++ b/posthog/api/test/test_capture.py @@ -1216,7 +1216,6 @@ def test_legacy_recording_ingestion_compression_and_transformation(self, kafka_p { "event": "$snapshot", "properties": { - "$snapshot_consumer": "v1", "$snapshot_data": { "chunk_count": 1, "chunk_id": "fake-uuid", From 7d3baefeca53079e7f3b786d3594b2f8cca3e858 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 14:01:05 +0100 Subject: [PATCH 03/41] wat --- plugin-server/functional_tests/api.ts | 15 +- .../session-recordings.test.ts | 285 ++++-------------- plugin-server/src/config/kafka-topics.ts | 3 - plugin-server/src/types.ts | 110 +------ plugin-server/tests/helpers/kafka.ts | 4 +- 5 files changed, 79 insertions(+), 338 deletions(-) diff --git a/plugin-server/functional_tests/api.ts b/plugin-server/functional_tests/api.ts index cb6ba5e5d5e99..51306752e9d03 100644 --- a/plugin-server/functional_tests/api.ts +++ b/plugin-server/functional_tests/api.ts @@ -14,7 +14,7 @@ import { RawAction, RawClickHouseEvent, RawPerformanceEvent, - RawSessionRecordingEvent, + RawSessionReplayEvent, } from '../src/types' import { PostgresRouter, PostgresUse } from '../src/utils/db/postgres' import { parseRawClickHouseEvent } from '../src/utils/event' @@ -62,7 +62,7 @@ export const capture = async ({ now = new Date(), $set = undefined, $set_once = undefined, - topic = ['$performance_event', '$snapshot'].includes(event) + topic = ['$performance_event', '$snapshot_items'].includes(event) ? 'session_recording_events' : 'events_plugin_ingestion', }: { @@ -300,16 +300,15 @@ export const fetchPostgresPersons = async (teamId: number) => { return rows } -export const fetchSessionRecordingsEvents = async (teamId: number, uuid?: string) => { +export const fetchSessionReplayEvents = async (teamId: number, sessionId?: string) => { const queryResult = (await clickHouseClient.querying( - `SELECT * FROM session_recording_events WHERE team_id = ${teamId} ${ - uuid ? ` AND uuid = '${uuid}'` : '' - } ORDER BY timestamp ASC` - )) as unknown as ClickHouse.ObjectQueryResult + `SELECT min(min_first_timestamp), any(team_id), any(distinct_id), sessionId, any(window) FROM session_replay_events WHERE team_id = ${teamId} ${ + sessionId ? ` AND sessionId = '${sessionId}'` : '' + } group by sessionId ORDER BY min_first_timestamp ASC` + )) as unknown as ClickHouse.ObjectQueryResult return queryResult.data.map((event) => { return { ...event, - snapshot_data: event.snapshot_data ? JSON.parse(event.snapshot_data) : null, } }) } diff --git a/plugin-server/functional_tests/session-recordings.test.ts b/plugin-server/functional_tests/session-recordings.test.ts index aaf86be6b5392..daec04c1b1fda 100644 --- a/plugin-server/functional_tests/session-recordings.test.ts +++ b/plugin-server/functional_tests/session-recordings.test.ts @@ -1,50 +1,17 @@ -import { Consumer, Kafka, KafkaMessage, logLevel } from 'kafkajs' import { v4 as uuidv4 } from 'uuid' -import { defaultConfig } from '../src/config/config' +import { KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS } from '../src/config/kafka-topics' import { UUIDT } from '../src/utils/utils' -import { - capture, - createOrganization, - createTeam, - fetchPerformanceEvents, - fetchSessionRecordingsEvents, - getMetric, -} from './api' +import { capture, createOrganization, createTeam, fetchSessionReplayEvents, getMetric } from './api' import { waitForExpect } from './expectations' import { produce } from './kafka' -let kafka: Kafka let organizationId: string -let dlq: KafkaMessage[] -let dlqConsumer: Consumer - beforeAll(async () => { - kafka = new Kafka({ brokers: [defaultConfig.KAFKA_HOSTS], logLevel: logLevel.NOTHING }) - - // Make sure the dlq topic exists before starting the consumer - const admin = kafka.admin() - await admin.createTopics({ topics: [{ topic: 'session_recording_events_dlq' }] }) - await admin.disconnect() - - dlq = [] - dlqConsumer = kafka.consumer({ groupId: 'session_recording_events_test' }) - await dlqConsumer.subscribe({ topic: 'session_recording_events_dlq', fromBeginning: true }) - await dlqConsumer.run({ - eachMessage: ({ message }) => { - dlq.push(message) - return Promise.resolve() - }, - }) - organizationId = await createOrganization() }) -afterAll(async () => { - await dlqConsumer.disconnect() -}) - test.concurrent( `snapshot captured, processed, ingested`, async () => { @@ -57,16 +24,16 @@ test.concurrent( teamId, distinctId, uuid, - event: '$snapshot', + event: '$snapshot_items', properties: { $session_id: sessionId, $window_id: 'abc1234', - $snapshot_data: 'yes way', + $snapshot_items: ['yes way'], }, }) const events = await waitForExpect(async () => { - const events = await fetchSessionRecordingsEvents(teamId) + const events = await fetchSessionReplayEvents(teamId) expect(events.length).toBe(1) return events }) @@ -107,10 +74,10 @@ test.concurrent( teamId: null, distinctId, uuid, - event: '$snapshot', + event: '$snapshot_items', properties: { $session_id: '1234abc', - $snapshot_data: 'yes way', + $snapshot_items: ['yes way'], }, token, sentAt: new Date(), @@ -119,11 +86,8 @@ test.concurrent( }) await waitForExpect(async () => { - const events = await fetchSessionRecordingsEvents(teamId) + const events = await fetchSessionReplayEvents(teamId) expect(events.length).toBe(1) - - // processEvent did not modify - expect(events[0].snapshot_data).toEqual('yes way') }) }, 20000 @@ -145,10 +109,10 @@ test.concurrent(`recording events not ingested to ClickHouse if team is opted ou teamId: null, distinctId: new UUIDT().toString(), uuid: uuidOptedOut, - event: '$snapshot', + event: '$snapshot_items', properties: { $session_id: '1234abc', - $snapshot_data: 'yes way', + $snapshot_items: ['yes way'], }, token: tokenOptedOut, sentAt: new Date(), @@ -164,10 +128,10 @@ test.concurrent(`recording events not ingested to ClickHouse if team is opted ou teamId: null, distinctId: new UUIDT().toString(), uuid: uuidOptedIn, - event: '$snapshot', + event: '$snapshot_items', properties: { $session_id: '1234abc', - $snapshot_data: 'yes way', + $snapshot_items: ['yes way'], }, token: tokenOptedIn, sentAt: new Date(), @@ -176,7 +140,7 @@ test.concurrent(`recording events not ingested to ClickHouse if team is opted ou }) await waitForExpect(async () => { - const events = await fetchSessionRecordingsEvents(teamOptedInId) + const events = await fetchSessionReplayEvents(teamOptedInId) expect(events.length).toBe(1) }) @@ -184,126 +148,10 @@ test.concurrent(`recording events not ingested to ClickHouse if team is opted ou // and that the consumer produceAndFlushs messages in the order they are consumed. // TODO: add some side-effect we can assert on rather than relying on the // partitioning / ordering setup e.g. an ingestion warning. - const events = await fetchSessionRecordingsEvents(teamOptedOutId, uuidOptedOut) + const events = await fetchSessionReplayEvents(teamOptedOutId) expect(events.length).toBe(0) }) -test.concurrent( - `ingests $performance_event`, - async () => { - const teamId = await createTeam(organizationId) - const distinctId = new UUIDT().toString() - const uuid = new UUIDT().toString() - const sessionId = new UUIDT().toString() - const now = new Date() - - const properties = { - // Taken from a real event from the JS - '0': 'resource', - '1': now.getTime(), - '2': 'http://localhost:8000/api/projects/1/session_recordings', - '3': 10737.89999999106, - '4': 0, - '5': 0, - '6': 0, - '7': 10737.89999999106, - '8': 10737.89999999106, - '9': 10737.89999999106, - '10': 10737.89999999106, - '11': 0, - '12': 10737.89999999106, - '13': 10745.09999999404, - '14': 11121.70000000298, - '15': 11122.20000000298, - '16': 73374, - '17': 1767, - '18': 'fetch', - '19': 'http/1.1', - '20': 'non-blocking', - '22': 2067, - '39': 384.30000001192093, - '40': now.getTime() + 1000, - token: 'phc_234', - $session_id: sessionId, - $window_id: '1853a793ad424a5-017f7473b057f1-17525635-384000-1853a793ad524dc', - distinct_id: '5AzhubH8uMghFHxXq0phfs14JOjH6SA2Ftr1dzXj7U4', - $current_url: 'http://localhost:8000/recordings/recent', - } - - await capture({ - teamId, - distinctId, - uuid, - event: '$performance_event', - properties, - token: null, - sentAt: now, - eventTime: now, - now, - }) - - const events = await waitForExpect(async () => { - const events = await fetchPerformanceEvents(teamId) - expect(events.length).toBe(1) - return events - }) - - expect(events[0]).toEqual({ - session_id: sessionId, - _offset: expect.any(Number), - _partition: expect.any(Number), - _timestamp: expect.any(String), - connect_end: 10737.89999999106, - connect_start: 10737.89999999106, - current_url: 'http://localhost:8000/recordings/recent', - decoded_body_size: 73374, - distinct_id: distinctId, - dom_complete: 0, - dom_content_loaded_event: 0, - dom_interactive: 0, - domain_lookup_end: 10737.89999999106, - domain_lookup_start: 10737.89999999106, - duration: 384.30000001192093, - encoded_body_size: 1767, - entry_type: 'resource', - fetch_start: 10737.89999999106, - initiator_type: 'fetch', - largest_contentful_paint_element: '', - largest_contentful_paint_id: '', - largest_contentful_paint_load_time: 0, - largest_contentful_paint_render_time: 0, - largest_contentful_paint_size: 0, - largest_contentful_paint_url: '', - load_event_end: 0, - load_event_start: 0, - name: 'http://localhost:8000/api/projects/1/session_recordings', - navigation_type: '', - next_hop_protocol: 'http/1.1', - pageview_id: '', - redirect_count: 0, - redirect_end: 0, - redirect_start: 0, - render_blocking_status: 'non-blocking', - request_start: 10745.09999999404, - response_end: 11122.20000000298, - response_start: 11121.70000000298, - response_status: 0, - secure_connection_start: 0, - start_time: 10737.89999999106, - team_id: teamId, - time_origin: expect.any(String), - timestamp: expect.any(String), - transfer_size: 2067, - unload_event_end: 0, - unload_event_start: 0, - uuid: uuid, - window_id: '1853a793ad424a5-017f7473b057f1-17525635-384000-1853a793ad524dc', - worker_start: 0, - }) - }, - 20000 -) - test.concurrent(`liveness check endpoint works`, async () => { await waitForExpect(async () => { const response = await fetch('http://localhost:6738/_health') @@ -318,21 +166,6 @@ test.concurrent(`liveness check endpoint works`, async () => { }) }) -test.concurrent( - `consumer handles empty messages`, - async () => { - const key = uuidv4() - - await produce({ topic: 'session_recording_events', message: null, key }) - - await waitForExpect(() => { - const messages = dlq.filter((message) => message.key?.toString() === key) - expect(messages.length).toBe(1) - }) - }, - 20000 -) - test.concurrent('consumer updates timestamp exported to prometheus', async () => { // NOTE: it may be another event other than the one we emit here that causes // the gauge to increase, but pushing this event through should at least @@ -340,16 +173,24 @@ test.concurrent('consumer updates timestamp exported to prometheus', async () => const metricBefore = await getMetric({ name: 'latest_processed_timestamp_ms', type: 'GAUGE', - labels: { topic: 'session_recording_events', partition: '0', groupId: 'session-recordings' }, + labels: { + topic: KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS, + partition: '0', + groupId: 'session-recordings-blob', + }, }) - await produce({ topic: 'session_recording_events', message: Buffer.from(''), key: '' }) + await produce({ topic: KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS, message: Buffer.from(''), key: '' }) await waitForExpect(async () => { const metricAfter = await getMetric({ name: 'latest_processed_timestamp_ms', type: 'GAUGE', - labels: { topic: 'session_recording_events', partition: '0', groupId: 'session-recordings' }, + labels: { + topic: KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS, + partition: '0', + groupId: 'session-recordings-blob', + }, }) expect(metricAfter).toBeGreaterThan(metricBefore) expect(metricAfter).toBeLessThan(Date.now()) // Make sure, e.g. we're not setting micro seconds @@ -357,18 +198,42 @@ test.concurrent('consumer updates timestamp exported to prometheus', async () => }, 10_000) }) -test.concurrent(`handles invalid JSON`, async () => { - const key = uuidv4() - - await produce({ topic: 'session_recording_events', message: Buffer.from('invalid json'), key }) - - await waitForExpect(() => { - const messages = dlq.filter((message) => message.key?.toString() === key) - expect(messages.length).toBe(1) - }) -}) +function makeSessionMessage( + teamId: number, + sessionId: string, + uuid?: string +): { + teamId: number | null + distinctId: string + uuid: string + event: string + properties?: object | undefined + token?: string | null | undefined + sentAt?: Date | undefined + eventTime?: Date | undefined + now?: Date | undefined + topic?: string | undefined + $set?: object | undefined + $set_once?: object | undefined +} { + return { + teamId: teamId, + distinctId: new UUIDT().toString(), + uuid: uuid || new UUIDT().toString(), + event: '$snapshot_items', + properties: { + $session_id: sessionId, + $snapshot_items: ['yes way'], + }, + sentAt: new Date(), + eventTime: new Date(), + now: new Date(), + topic: KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS, + } +} -test.concurrent(`handles message with no token or with token and no associated team_id`, async () => { +// TODO we can't query for replay events by UUID +test.skip(`handles message with no token or with token and no associated team_id`, async () => { // NOTE: Here we are relying on the topic only having a single partition, // which ensures that if the last message we send is in ClickHouse, then // that should mean that the previous messages have already been processed. @@ -382,48 +247,30 @@ test.concurrent(`handles message with no token or with token and no associated t const noAssociatedTeamKey = uuidv4() const noTokenUuid = uuidv4() const noAssociatedTeamUuid = uuidv4() - const uuid = uuidv4() await produce({ - topic: 'session_recording_events', + topic: KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS, message: Buffer.from(JSON.stringify({ uuid: noTokenUuid, data: JSON.stringify({}) })), key: noTokenKey, }) await produce({ - topic: 'session_recording_events', + topic: KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS, message: Buffer.from( JSON.stringify({ uuid: noAssociatedTeamUuid, token: 'no associated team', data: JSON.stringify({}) }) ), key: noAssociatedTeamKey, }) - await capture({ - teamId: teamId, - distinctId: new UUIDT().toString(), - uuid: uuid, - event: '$snapshot', - properties: { - $session_id: '1234abc', - $snapshot_data: 'yes way', - }, - sentAt: new Date(), - eventTime: new Date(), - now: new Date(), - topic: 'session_recording_events', - }) + await capture(makeSessionMessage(teamId, 'should be ingested')) await waitForExpect(async () => { - const events = await fetchSessionRecordingsEvents(teamId, uuid) + const events = await fetchSessionReplayEvents(teamId, 'should be ingested') expect(events.length).toBe(1) }) - // These shouldn't have been DLQ'd - expect(dlq.filter((message) => message.key?.toString() === noTokenKey).length).toBe(0) - expect(dlq.filter((message) => message.key?.toString() === noAssociatedTeamKey).length).toBe(0) - // And they shouldn't have been ingested into ClickHouse - expect((await fetchSessionRecordingsEvents(teamId, noTokenUuid)).length).toBe(0) - expect((await fetchSessionRecordingsEvents(teamId, noAssociatedTeamUuid)).length).toBe(0) + expect((await fetchSessionReplayEvents(teamId, noTokenUuid)).length).toBe(0) + expect((await fetchSessionReplayEvents(teamId, noAssociatedTeamUuid)).length).toBe(0) }) // TODO: implement schema validation and add a test. diff --git a/plugin-server/src/config/kafka-topics.ts b/plugin-server/src/config/kafka-topics.ts index 78cfc76f65f98..96b5c23758e37 100644 --- a/plugin-server/src/config/kafka-topics.ts +++ b/plugin-server/src/config/kafka-topics.ts @@ -27,9 +27,6 @@ export const KAFKA_SCHEDULED_TASKS_DLQ = `${prefix}scheduled_tasks_dlq${suffix}` export const KAFKA_METRICS_TIME_TO_SEE_DATA = `${prefix}clickhouse_metrics_time_to_see_data${suffix}` export const KAFKA_PERSON_OVERRIDE = `${prefix}clickhouse_person_override${suffix}` -// read session recording events from Kafka -export const KAFKA_SESSION_RECORDING_EVENTS = `${prefix}session_recording_events${suffix}` -export const KAFKA_SESSION_RECORDING_EVENTS_DLQ = `${prefix}session_recording_events_dlq${suffix}` // read session recording snapshot items export const KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS = `${prefix}session_recording_snapshot_item_events${suffix}` // write session recording and replay events to ClickHouse diff --git a/plugin-server/src/types.ts b/plugin-server/src/types.ts index d25e3bb81e9b3..45b3c217605a6 100644 --- a/plugin-server/src/types.ts +++ b/plugin-server/src/types.ts @@ -929,115 +929,13 @@ export interface RawSessionRecordingEvent { created_at: string } -export interface RawPerformanceEvent { - uuid: string +/** Raw session replay event row from ClickHouse. */ +export interface RawSessionReplayEvent { + min_first_timestamp: string team_id: number distinct_id: string session_id: string - window_id: string - pageview_id: string - current_url: string - - // BASE_EVENT_COLUMNS - time_origin: number - timestamp: string - entry_type: string - name: string - - // RESOURCE_EVENT_COLUMNS - start_time: number - redirect_start: number - redirect_end: number - worker_start: number - fetch_start: number - domain_lookup_start: number - domain_lookup_end: number - connect_start: number - secure_connection_start: number - connect_end: number - request_start: number - response_start: number - response_end: number - decoded_body_size: number - encoded_body_size: number - duration: number - - initiator_type: string - next_hop_protocol: string - render_blocking_status: string - response_status: number - transfer_size: number - - // LARGEST_CONTENTFUL_PAINT_EVENT_COLUMNS - largest_contentful_paint_element: string - largest_contentful_paint_render_time: number - largest_contentful_paint_load_time: number - largest_contentful_paint_size: number - largest_contentful_paint_id: string - largest_contentful_paint_url: string - - // NAVIGATION_EVENT_COLUMNS - dom_complete: number - dom_content_loaded_event: number - dom_interactive: number - load_event_end: number - load_event_start: number - redirect_count: number - navigation_type: string - unload_event_end: number - unload_event_start: number -} - -export const PerformanceEventReverseMapping: { [key: number]: keyof RawPerformanceEvent } = { - // BASE_PERFORMANCE_EVENT_COLUMNS - 0: 'entry_type', - 1: 'time_origin', - 2: 'name', - - // RESOURCE_EVENT_COLUMNS - 3: 'start_time', - 4: 'redirect_start', - 5: 'redirect_end', - 6: 'worker_start', - 7: 'fetch_start', - 8: 'domain_lookup_start', - 9: 'domain_lookup_end', - 10: 'connect_start', - 11: 'secure_connection_start', - 12: 'connect_end', - 13: 'request_start', - 14: 'response_start', - 15: 'response_end', - 16: 'decoded_body_size', - 17: 'encoded_body_size', - 18: 'initiator_type', - 19: 'next_hop_protocol', - 20: 'render_blocking_status', - 21: 'response_status', - 22: 'transfer_size', - - // LARGEST_CONTENTFUL_PAINT_EVENT_COLUMNS - 23: 'largest_contentful_paint_element', - 24: 'largest_contentful_paint_render_time', - 25: 'largest_contentful_paint_load_time', - 26: 'largest_contentful_paint_size', - 27: 'largest_contentful_paint_id', - 28: 'largest_contentful_paint_url', - - // NAVIGATION_EVENT_COLUMNS - 29: 'dom_complete', - 30: 'dom_content_loaded_event', - 31: 'dom_interactive', - 32: 'load_event_end', - 33: 'load_event_start', - 34: 'redirect_count', - 35: 'navigation_type', - 36: 'unload_event_end', - 37: 'unload_event_start', - - // Added after v1 - 39: 'duration', - 40: 'timestamp', + /* TODO what columns do we need */ } export enum TimestampFormat { diff --git a/plugin-server/tests/helpers/kafka.ts b/plugin-server/tests/helpers/kafka.ts index d877805e293b5..775ae674ce86b 100644 --- a/plugin-server/tests/helpers/kafka.ts +++ b/plugin-server/tests/helpers/kafka.ts @@ -11,7 +11,7 @@ import { KAFKA_PERSON_DISTINCT_ID, KAFKA_PERSON_UNIQUE_ID, KAFKA_PLUGIN_LOG_ENTRIES, - KAFKA_SESSION_RECORDING_EVENTS, + KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS, } from '../../src/config/kafka-topics' import { PluginsServerConfig } from '../../src/types' import { KAFKA_EVENTS_DEAD_LETTER_QUEUE } from './../../src/config/kafka-topics' @@ -30,7 +30,7 @@ export async function resetKafka(extraServerConfig?: Partial Date: Thu, 21 Sep 2023 14:07:13 +0100 Subject: [PATCH 04/41] wat --- plugin-server/functional_tests/session-recordings.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin-server/functional_tests/session-recordings.test.ts b/plugin-server/functional_tests/session-recordings.test.ts index daec04c1b1fda..1ac127fff1bfc 100644 --- a/plugin-server/functional_tests/session-recordings.test.ts +++ b/plugin-server/functional_tests/session-recordings.test.ts @@ -1,3 +1,4 @@ +import fetch from 'node-fetch' import { v4 as uuidv4 } from 'uuid' import { KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS } from '../src/config/kafka-topics' From 42ffedac5162f91feec198b264ca9f955d506593 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 14:18:36 +0100 Subject: [PATCH 05/41] wat --- plugin-server/src/types.ts | 111 +++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/plugin-server/src/types.ts b/plugin-server/src/types.ts index 45b3c217605a6..5306a0c3dd4f8 100644 --- a/plugin-server/src/types.ts +++ b/plugin-server/src/types.ts @@ -938,6 +938,117 @@ export interface RawSessionReplayEvent { /* TODO what columns do we need */ } +export interface RawPerformanceEvent { + uuid: string + team_id: number + distinct_id: string + session_id: string + window_id: string + pageview_id: string + current_url: string + + // BASE_EVENT_COLUMNS + time_origin: number + timestamp: string + entry_type: string + name: string + + // RESOURCE_EVENT_COLUMNS + start_time: number + redirect_start: number + redirect_end: number + worker_start: number + fetch_start: number + domain_lookup_start: number + domain_lookup_end: number + connect_start: number + secure_connection_start: number + connect_end: number + request_start: number + response_start: number + response_end: number + decoded_body_size: number + encoded_body_size: number + duration: number + + initiator_type: string + next_hop_protocol: string + render_blocking_status: string + response_status: number + transfer_size: number + + // LARGEST_CONTENTFUL_PAINT_EVENT_COLUMNS + largest_contentful_paint_element: string + largest_contentful_paint_render_time: number + largest_contentful_paint_load_time: number + largest_contentful_paint_size: number + largest_contentful_paint_id: string + largest_contentful_paint_url: string + + // NAVIGATION_EVENT_COLUMNS + dom_complete: number + dom_content_loaded_event: number + dom_interactive: number + load_event_end: number + load_event_start: number + redirect_count: number + navigation_type: string + unload_event_end: number + unload_event_start: number +} + +export const PerformanceEventReverseMapping: { [key: number]: keyof RawPerformanceEvent } = { + // BASE_PERFORMANCE_EVENT_COLUMNS + 0: 'entry_type', + 1: 'time_origin', + 2: 'name', + + // RESOURCE_EVENT_COLUMNS + 3: 'start_time', + 4: 'redirect_start', + 5: 'redirect_end', + 6: 'worker_start', + 7: 'fetch_start', + 8: 'domain_lookup_start', + 9: 'domain_lookup_end', + 10: 'connect_start', + 11: 'secure_connection_start', + 12: 'connect_end', + 13: 'request_start', + 14: 'response_start', + 15: 'response_end', + 16: 'decoded_body_size', + 17: 'encoded_body_size', + 18: 'initiator_type', + 19: 'next_hop_protocol', + 20: 'render_blocking_status', + 21: 'response_status', + 22: 'transfer_size', + + // LARGEST_CONTENTFUL_PAINT_EVENT_COLUMNS + 23: 'largest_contentful_paint_element', + 24: 'largest_contentful_paint_render_time', + 25: 'largest_contentful_paint_load_time', + 26: 'largest_contentful_paint_size', + 27: 'largest_contentful_paint_id', + 28: 'largest_contentful_paint_url', + + // NAVIGATION_EVENT_COLUMNS + 29: 'dom_complete', + 30: 'dom_content_loaded_event', + 31: 'dom_interactive', + 32: 'load_event_end', + 33: 'load_event_start', + 34: 'redirect_count', + 35: 'navigation_type', + 36: 'unload_event_end', + 37: 'unload_event_start', + + // Added after v1 + 39: 'duration', + 40: 'timestamp', +} + export enum TimestampFormat { ClickHouseSecondPrecision = 'clickhouse-second-precision', ClickHouse = 'clickhouse', From 22e23c3b11a2ca090aee0f358d464d69a1ee7c2f Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 14:29:23 +0100 Subject: [PATCH 06/41] fi --- .../web-performance-events.test.ts | 52 ------------------- 1 file changed, 52 deletions(-) delete mode 100644 plugin-server/functional_tests/web-performance-events.test.ts diff --git a/plugin-server/functional_tests/web-performance-events.test.ts b/plugin-server/functional_tests/web-performance-events.test.ts deleted file mode 100644 index e05dad6bac9f4..0000000000000 --- a/plugin-server/functional_tests/web-performance-events.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { UUIDT } from '../src/utils/utils' -import { capture, createOrganization, createTeam, fetchEvents, fetchPerformanceEvents } from './api' -import { waitForExpect } from './expectations' - -let organizationId: string - -beforeAll(async () => { - organizationId = await createOrganization() -}) - -test.concurrent( - `peformance event ingestion: captured, processed, ingested`, - async () => { - const teamId = await createTeam(organizationId) - const distinctId = new UUIDT().toString() - const uuid = new UUIDT().toString() - - await capture({ - teamId, - distinctId, - uuid, - event: '$performance_event', - properties: { - '0': 'resource', - $session_id: '$session_id_1', - $window_id: '$window_id_1', - $pageview_id: '$pageview_id_1', - $current_url: '$current_url_1', - }, - }) - - const perfEvents = await waitForExpect(async () => { - const perfEvents = await fetchPerformanceEvents(teamId) - expect(perfEvents.length).toBe(1) - return perfEvents - }) - const events = await fetchEvents(teamId) - expect(events.length).toBe(0) - - expect(perfEvents.length).toBe(1) - - // processEvent did not modify - expect(perfEvents[0]).toMatchObject({ - entry_type: 'resource', - session_id: '$session_id_1', - window_id: '$window_id_1', - pageview_id: '$pageview_id_1', - current_url: '$current_url_1', - }) - }, - 20000 -) From c761a2c6d695576124003ffca9efc66132acad3e Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 14:37:03 +0100 Subject: [PATCH 07/41] fy --- plugin-server/functional_tests/session-recordings.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-server/functional_tests/session-recordings.test.ts b/plugin-server/functional_tests/session-recordings.test.ts index 1ac127fff1bfc..78a8e4f1a9d57 100644 --- a/plugin-server/functional_tests/session-recordings.test.ts +++ b/plugin-server/functional_tests/session-recordings.test.ts @@ -161,7 +161,7 @@ test.concurrent(`liveness check endpoint works`, async () => { const body = await response.json() expect(body).toEqual( expect.objectContaining({ - checks: expect.objectContaining({ 'session-recordings': 'ok' }), + checks: expect.objectContaining({ 'session-recordings-blob': 'ok' }), }) ) }) From 911e4b799902434b03b3d10b16e2cd6cf1f2c38b Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 14:38:42 +0100 Subject: [PATCH 08/41] fo --- plugin-server/functional_tests/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-server/functional_tests/api.ts b/plugin-server/functional_tests/api.ts index 51306752e9d03..c54b67ff9cb99 100644 --- a/plugin-server/functional_tests/api.ts +++ b/plugin-server/functional_tests/api.ts @@ -302,7 +302,7 @@ export const fetchPostgresPersons = async (teamId: number) => { export const fetchSessionReplayEvents = async (teamId: number, sessionId?: string) => { const queryResult = (await clickHouseClient.querying( - `SELECT min(min_first_timestamp), any(team_id), any(distinct_id), sessionId, any(window) FROM session_replay_events WHERE team_id = ${teamId} ${ + `SELECT min(min_first_timestamp), any(team_id), any(distinct_id), sessionId FROM session_replay_events WHERE team_id = ${teamId} ${ sessionId ? ` AND sessionId = '${sessionId}'` : '' } group by sessionId ORDER BY min_first_timestamp ASC` )) as unknown as ClickHouse.ObjectQueryResult From 1e92dd25b450ab588d47bbf9c07b843686646c83 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 14:52:26 +0100 Subject: [PATCH 09/41] fum --- plugin-server/functional_tests/api.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/plugin-server/functional_tests/api.ts b/plugin-server/functional_tests/api.ts index c54b67ff9cb99..0c876bf3a3983 100644 --- a/plugin-server/functional_tests/api.ts +++ b/plugin-server/functional_tests/api.ts @@ -13,7 +13,6 @@ import { PluginLogEntry, RawAction, RawClickHouseEvent, - RawPerformanceEvent, RawSessionReplayEvent, } from '../src/types' import { PostgresRouter, PostgresUse } from '../src/utils/db/postgres' @@ -302,8 +301,8 @@ export const fetchPostgresPersons = async (teamId: number) => { export const fetchSessionReplayEvents = async (teamId: number, sessionId?: string) => { const queryResult = (await clickHouseClient.querying( - `SELECT min(min_first_timestamp), any(team_id), any(distinct_id), sessionId FROM session_replay_events WHERE team_id = ${teamId} ${ - sessionId ? ` AND sessionId = '${sessionId}'` : '' + `SELECT min(min_first_timestamp), any(team_id), any(distinct_id), session_id FROM session_replay_events WHERE team_id = ${teamId} ${ + sessionId ? ` AND session_id = '${sessionId}'` : '' } group by sessionId ORDER BY min_first_timestamp ASC` )) as unknown as ClickHouse.ObjectQueryResult return queryResult.data.map((event) => { @@ -313,13 +312,6 @@ export const fetchSessionReplayEvents = async (teamId: number, sessionId?: strin }) } -export const fetchPerformanceEvents = async (teamId: number) => { - const queryResult = (await clickHouseClient.querying( - `SELECT * FROM performance_events WHERE team_id = ${teamId} ORDER BY timestamp ASC` - )) as unknown as ClickHouse.ObjectQueryResult - return queryResult.data -} - export const fetchPluginConsoleLogEntries = async (pluginConfigId: number) => { const { data: logEntries } = (await clickHouseClient.querying(` SELECT * FROM plugin_log_entries From a80784c89273425f57e4f338ed79bb41ef52dbf3 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 14:55:27 +0100 Subject: [PATCH 10/41] i --- plugin-server/functional_tests/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-server/functional_tests/api.ts b/plugin-server/functional_tests/api.ts index 0c876bf3a3983..29bf5c9a67b00 100644 --- a/plugin-server/functional_tests/api.ts +++ b/plugin-server/functional_tests/api.ts @@ -303,7 +303,7 @@ export const fetchSessionReplayEvents = async (teamId: number, sessionId?: strin const queryResult = (await clickHouseClient.querying( `SELECT min(min_first_timestamp), any(team_id), any(distinct_id), session_id FROM session_replay_events WHERE team_id = ${teamId} ${ sessionId ? ` AND session_id = '${sessionId}'` : '' - } group by sessionId ORDER BY min_first_timestamp ASC` + } group by session_id ORDER BY min_first_timestamp ASC` )) as unknown as ClickHouse.ObjectQueryResult return queryResult.data.map((event) => { return { From 8b309abb8523d1309e6cebc98668977d83225c61 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 15:07:12 +0100 Subject: [PATCH 11/41] smell --- plugin-server/functional_tests/api.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin-server/functional_tests/api.ts b/plugin-server/functional_tests/api.ts index 29bf5c9a67b00..6d16cdb41a498 100644 --- a/plugin-server/functional_tests/api.ts +++ b/plugin-server/functional_tests/api.ts @@ -301,9 +301,9 @@ export const fetchPostgresPersons = async (teamId: number) => { export const fetchSessionReplayEvents = async (teamId: number, sessionId?: string) => { const queryResult = (await clickHouseClient.querying( - `SELECT min(min_first_timestamp), any(team_id), any(distinct_id), session_id FROM session_replay_events WHERE team_id = ${teamId} ${ + `SELECT min(min_first_timestamp) as min_fs_ts, any(team_id), any(distinct_id), session_id FROM session_replay_events WHERE team_id = ${teamId} ${ sessionId ? ` AND session_id = '${sessionId}'` : '' - } group by session_id ORDER BY min_first_timestamp ASC` + } group by session_id ORDER BY min_fs_ts ASC` )) as unknown as ClickHouse.ObjectQueryResult return queryResult.data.map((event) => { return { From 773707724c1e6fbec286687c08d244d8a52867ce Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 15:22:52 +0100 Subject: [PATCH 12/41] the --- plugin-server/functional_tests/api.ts | 3 ++- plugin-server/functional_tests/session-recordings.test.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/plugin-server/functional_tests/api.ts b/plugin-server/functional_tests/api.ts index 6d16cdb41a498..89b1f7cd10698 100644 --- a/plugin-server/functional_tests/api.ts +++ b/plugin-server/functional_tests/api.ts @@ -5,6 +5,7 @@ import parsePrometheusTextFormat from 'parse-prometheus-text-format' import { PoolClient } from 'pg' import { defaultConfig } from '../src/config/config' +import { KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS } from '../src/config/kafka-topics' import { ActionStep, Hook, @@ -62,7 +63,7 @@ export const capture = async ({ $set = undefined, $set_once = undefined, topic = ['$performance_event', '$snapshot_items'].includes(event) - ? 'session_recording_events' + ? KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS : 'events_plugin_ingestion', }: { teamId: number | null diff --git a/plugin-server/functional_tests/session-recordings.test.ts b/plugin-server/functional_tests/session-recordings.test.ts index 78a8e4f1a9d57..b8063f896f59c 100644 --- a/plugin-server/functional_tests/session-recordings.test.ts +++ b/plugin-server/functional_tests/session-recordings.test.ts @@ -34,7 +34,7 @@ test.concurrent( }) const events = await waitForExpect(async () => { - const events = await fetchSessionReplayEvents(teamId) + const events = await fetchSessionReplayEvents(teamId, sessionId) expect(events.length).toBe(1) return events }) From 4ec0c9d82b3dd0ddbba28cfa60323ef3513f1c0c Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 15:47:05 +0100 Subject: [PATCH 13/41] blood --- plugin-server/functional_tests/api.ts | 2 +- plugin-server/functional_tests/kafka.ts | 2 +- .../session-recordings.test.ts | 146 +++++++++--------- 3 files changed, 71 insertions(+), 79 deletions(-) diff --git a/plugin-server/functional_tests/api.ts b/plugin-server/functional_tests/api.ts index 89b1f7cd10698..9c23f32ad3fac 100644 --- a/plugin-server/functional_tests/api.ts +++ b/plugin-server/functional_tests/api.ts @@ -80,7 +80,7 @@ export const capture = async ({ $set_once?: object }) => { // WARNING: this capture method is meant to simulate the ingestion of events - // from the capture endpoint, but there is no guarantee that is is 100% + // from the capture endpoint, but there is no guarantee that it is 100% // accurate. return await produce({ topic, diff --git a/plugin-server/functional_tests/kafka.ts b/plugin-server/functional_tests/kafka.ts index 4c33975ca69ca..9879f1a01d14e 100644 --- a/plugin-server/functional_tests/kafka.ts +++ b/plugin-server/functional_tests/kafka.ts @@ -38,5 +38,5 @@ export async function createKafkaProducer() { export async function produce({ topic, message, key }: { topic: string; message: Buffer | null; key: string }) { producer = producer ?? (await createKafkaProducer()) - await defaultProduce({ producer, topic, value: message, key: Buffer.from(key) }) + await defaultProduce({ producer, topic, value: message, key: Buffer.from(key), waitForAck: true }) } diff --git a/plugin-server/functional_tests/session-recordings.test.ts b/plugin-server/functional_tests/session-recordings.test.ts index b8063f896f59c..75147fffbfbf4 100644 --- a/plugin-server/functional_tests/session-recordings.test.ts +++ b/plugin-server/functional_tests/session-recordings.test.ts @@ -13,88 +13,80 @@ beforeAll(async () => { organizationId = await createOrganization() }) -test.concurrent( - `snapshot captured, processed, ingested`, - async () => { - const teamId = await createTeam(organizationId) - const distinctId = new UUIDT().toString() - const uuid = new UUIDT().toString() - const sessionId = new UUIDT().toString() +test.skip(`snapshot captured, processed, ingested`, async () => { + const teamId = await createTeam(organizationId) + const distinctId = new UUIDT().toString() + const uuid = new UUIDT().toString() + const sessionId = new UUIDT().toString() - await capture({ - teamId, - distinctId, - uuid, - event: '$snapshot_items', - properties: { - $session_id: sessionId, - $window_id: 'abc1234', - $snapshot_items: ['yes way'], - }, - }) + await capture({ + teamId, + distinctId, + uuid, + event: '$snapshot_items', + properties: { + $session_id: sessionId, + $window_id: 'abc1234', + $snapshot_items: ['yes way'], + }, + }) - const events = await waitForExpect(async () => { - const events = await fetchSessionReplayEvents(teamId, sessionId) - expect(events.length).toBe(1) - return events - }) + const events = await waitForExpect(async () => { + const events = await fetchSessionReplayEvents(teamId, sessionId) + expect(events.length).toBe(1) + return events + }) - expect(events[0]).toEqual({ - _offset: expect.any(Number), - _timestamp: expect.any(String), - click_count: 0, - created_at: expect.any(String), - distinct_id: distinctId, - events_summary: [], - first_event_timestamp: null, - has_full_snapshot: 0, - keypress_count: 0, - last_event_timestamp: null, - session_id: sessionId, - snapshot_data: 'yes way', - team_id: teamId, - timestamp: expect.any(String), - timestamps_summary: [], - urls: [], - uuid: uuid, - window_id: 'abc1234', - }) - }, - 20000 -) + expect(events[0]).toEqual({ + _offset: expect.any(Number), + _timestamp: expect.any(String), + click_count: 0, + created_at: expect.any(String), + distinct_id: distinctId, + events_summary: [], + first_event_timestamp: null, + has_full_snapshot: 0, + keypress_count: 0, + last_event_timestamp: null, + session_id: sessionId, + snapshot_data: 'yes way', + team_id: teamId, + timestamp: expect.any(String), + timestamps_summary: [], + urls: [], + uuid: uuid, + window_id: 'abc1234', + }) +}, 20000) -test.concurrent( - `snapshot captured, processed, ingested with no team_id set`, - async () => { - const token = uuidv4() - const teamId = await createTeam(organizationId, undefined, token) - const distinctId = new UUIDT().toString() - const uuid = new UUIDT().toString() +test.skip(`snapshot captured, processed, ingested with no team_id set`, async () => { + const token = uuidv4() + const teamId = await createTeam(organizationId, undefined, token) + const distinctId = new UUIDT().toString() + const uuid = new UUIDT().toString() - await capture({ - teamId: null, - distinctId, - uuid, - event: '$snapshot_items', - properties: { - $session_id: '1234abc', - $snapshot_items: ['yes way'], - }, - token, - sentAt: new Date(), - eventTime: new Date(), - now: new Date(), - }) + await capture({ + teamId: null, + distinctId, + uuid, + event: '$snapshot_items', + properties: { + $session_id: '1234abc', + $snapshot_items: ['yes way'], + }, + token, + sentAt: new Date(), + eventTime: new Date(), + now: new Date(), + }) - await waitForExpect(async () => { - const events = await fetchSessionReplayEvents(teamId) - expect(events.length).toBe(1) - }) - }, - 20000 -) + await waitForExpect(async () => { + const events = await fetchSessionReplayEvents(teamId) + expect(events.length).toBe(1) + }) +}, 20000) -test.concurrent(`recording events not ingested to ClickHouse if team is opted out`, async () => { +test.skip(`recording events not ingested to ClickHouse if team is opted out`, async () => { // NOTE: to have something we can assert on in the positive to ensure that // we had tried to ingest the recording for the team with the opted out // session recording status, we create a team that is opted in and then @@ -153,7 +145,7 @@ test.concurrent(`recording events not ingested to ClickHouse if team is opted ou expect(events.length).toBe(0) }) -test.concurrent(`liveness check endpoint works`, async () => { +test.skip(`liveness check endpoint works`, async () => { await waitForExpect(async () => { const response = await fetch('http://localhost:6738/_health') expect(response.status).toBe(200) @@ -167,7 +159,7 @@ test.concurrent(`liveness check endpoint works`, async () => { }) }) -test.concurrent('consumer updates timestamp exported to prometheus', async () => { +test.skip('consumer updates timestamp exported to prometheus', async () => { // NOTE: it may be another event other than the one we emit here that causes // the gauge to increase, but pushing this event through should at least // ensure that the gauge is updated. From b2ce96085c6f506cc122102639cf3a028dd887f7 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 15:52:10 +0100 Subject: [PATCH 14/41] of --- plugin-server/functional_tests/session-recordings.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-server/functional_tests/session-recordings.test.ts b/plugin-server/functional_tests/session-recordings.test.ts index 75147fffbfbf4..62075bc6bd10f 100644 --- a/plugin-server/functional_tests/session-recordings.test.ts +++ b/plugin-server/functional_tests/session-recordings.test.ts @@ -145,7 +145,7 @@ test.skip(`recording events not ingested to ClickHouse if team is opted out`, as expect(events.length).toBe(0) }) -test.skip(`liveness check endpoint works`, async () => { +test.concurrent(`liveness check endpoint works`, async () => { await waitForExpect(async () => { const response = await fetch('http://localhost:6738/_health') expect(response.status).toBe(200) From c69487fbe9b7e7216106c520074839adfb677290 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 18:10:34 +0100 Subject: [PATCH 15/41] an --- posthog/api/capture.py | 10 +---- .../session_recording_helpers.py | 39 ------------------- .../session_recordings/test/test_factory.py | 37 ------------------ 3 files changed, 2 insertions(+), 84 deletions(-) diff --git a/posthog/api/capture.py b/posthog/api/capture.py index 8b6a576012d9b..ba07e55f34900 100644 --- a/posthog/api/capture.py +++ b/posthog/api/capture.py @@ -35,7 +35,6 @@ from posthog.metrics import LABEL_RESOURCE_TYPE from posthog.models.utils import UUIDT from posthog.session_recordings.session_recording_helpers import ( - legacy_preprocess_session_recording_events_for_clickhouse, preprocess_replay_events_for_blob_ingestion, split_replay_events, ) @@ -367,14 +366,9 @@ def get_event(request): capture_exception(e) try: + # split the replay events off as they are passed to kafka separately replay_events, other_events = split_replay_events(events) - processed_replay_events = replay_events - - if len(replay_events) > 0: - # Legacy solution stays in place - processed_replay_events = legacy_preprocess_session_recording_events_for_clickhouse(replay_events) - - events = processed_replay_events + other_events + events = other_events except ValueError as e: return cors_response( diff --git a/posthog/session_recordings/session_recording_helpers.py b/posthog/session_recordings/session_recording_helpers.py index 960ac0021c817..8c7f1964a7d51 100644 --- a/posthog/session_recordings/session_recording_helpers.py +++ b/posthog/session_recordings/session_recording_helpers.py @@ -8,7 +8,6 @@ from dateutil.parser import ParserError, parse from sentry_sdk.api import capture_exception -from posthog.models import utils from posthog.session_recordings.models.metadata import ( DecompressedRecordingData, SessionRecordingEventSummary, @@ -88,44 +87,6 @@ class RRWEB_MAP_EVENT_DATA_TYPE: Event = Dict[str, Any] -def legacy_preprocess_session_recording_events_for_clickhouse( - events: List[Event], chunk_size=512 * 1024 -) -> List[Event]: - return _process_windowed_events(events, lambda x: legacy_compress_and_chunk_snapshots(x, chunk_size=chunk_size)) - - -def legacy_compress_and_chunk_snapshots(events: List[Event], chunk_size=512 * 1024) -> Generator[Event, None, None]: - data_list = list(flatten([event["properties"]["$snapshot_data"] for event in events], max_depth=1)) - session_id = events[0]["properties"]["$session_id"] - window_id = events[0]["properties"].get("$window_id") - has_full_snapshot = any(snapshot_data["type"] == RRWEB_MAP_EVENT_TYPE.FullSnapshot for snapshot_data in data_list) - compressed_data = compress_to_string(json.dumps(data_list)) - - id = str(utils.UUIDT()) - chunks = chunk_string(compressed_data, chunk_size) - - for index, chunk in enumerate(chunks): - yield { - **events[0], - "properties": { - **events[0]["properties"], - "$session_id": session_id, - "$window_id": window_id, - # If it is the first chunk we include all events - "$snapshot_data": { - "chunk_id": id, - "chunk_index": index, - "chunk_count": len(chunks), - "data": chunk, - "compression": "gzip-base64", - "has_full_snapshot": has_full_snapshot, - # We only store this field on the first chunk as it contains all events, not just this chunk - "events_summary": get_events_summary_from_snapshot_data(data_list) if index == 0 else None, - }, - }, - } - - def split_replay_events(events: List[Event]) -> Tuple[List[Event], List[Event]]: replay, other = [], [] diff --git a/posthog/session_recordings/test/test_factory.py b/posthog/session_recordings/test/test_factory.py index 4213ff02f5566..195286683d0de 100644 --- a/posthog/session_recordings/test/test_factory.py +++ b/posthog/session_recordings/test/test_factory.py @@ -12,7 +12,6 @@ from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary from posthog.session_recordings.session_recording_helpers import ( RRWEB_MAP_EVENT_TYPE, - legacy_preprocess_session_recording_events_for_clickhouse, ) from posthog.utils import cast_timestamp_or_now @@ -73,42 +72,6 @@ def create_session_recording_events( last_timestamp=timestamp, ) - if use_recording_table: - if window_id is None: - window_id = session_id - - if not snapshots: - snapshots = [ - { - "type": RRWEB_MAP_EVENT_TYPE.FullSnapshot, - "data": {}, - "timestamp": round(timestamp.timestamp() * 1000), # NOTE: rrweb timestamps are milliseconds - } - ] - - # We use the same code path for chunking events by mocking this as an typical posthog event - mock_events = [ - { - "event": "$snapshot", - "properties": { - "$session_id": session_id, - "$window_id": window_id, - "$snapshot_data": snapshot, - }, - } - for snapshot in snapshots - ] - - for event in legacy_preprocess_session_recording_events_for_clickhouse(mock_events, chunk_size=chunk_size): - _insert_session_recording_event( - team_id=team_id, - distinct_id=distinct_id, - session_id=session_id, - window_id=window_id, - timestamp=timestamp, - snapshot_data=event["properties"]["$snapshot_data"], - ) - # Pre-compression and events_summary additions which potentially existed for some self-hosted instances def create_uncompressed_session_recording_event( From 92004c960db0206c29656f4ae90ea8cd0a9cfd57 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 18:59:25 +0100 Subject: [PATCH 16/41] english --- posthog/helpers/tests/test_session_recording_helpers.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/posthog/helpers/tests/test_session_recording_helpers.py b/posthog/helpers/tests/test_session_recording_helpers.py index ee6a3c6ccada2..f2f73a7fee15e 100644 --- a/posthog/helpers/tests/test_session_recording_helpers.py +++ b/posthog/helpers/tests/test_session_recording_helpers.py @@ -16,7 +16,6 @@ decompress_chunked_snapshot_data, get_events_summary_from_snapshot_data, is_active_event, - legacy_preprocess_session_recording_events_for_clickhouse, preprocess_replay_events_for_blob_ingestion, split_replay_events, ) @@ -37,12 +36,11 @@ def mock_capture_flow(events: List[dict], max_size_bytes=512 * 1024) -> Tuple[Li Returns the legacy events and the new flow ones """ replay_events, other_events = split_replay_events(events) - legacy_replay_events = legacy_preprocess_session_recording_events_for_clickhouse( - replay_events, chunk_size=max_size_bytes - ) + new_replay_events = preprocess_replay_events_for_blob_ingestion(replay_events, max_size_bytes=max_size_bytes) - return legacy_replay_events + other_events, new_replay_events + other_events + # TODO this should only be returning the second part of the tuple, it used to return legacy snapshot data too + return other_events, new_replay_events + other_events def test_preprocess_with_no_recordings(): From 1f6bad1403b35f1c6a00e938e34faa29b773fe8f Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 21 Sep 2023 20:44:48 +0100 Subject: [PATCH 17/41] man --- .../session_recording_extensions.py | 49 +- .../test/test_session_recording_extensions.py | 99 +- .../test/test_session_recording_playlist.py | 6 +- .../models/session_recording.py | 19 +- .../queries/session_recording_events.py | 87 - .../queries/test/test_session_recording.py | 221 --- .../test_session_recordings.ambr | 1541 +++++++---------- .../test/test_lts_session_recordings.py | 45 +- .../test/test_session_recordings.py | 123 +- 9 files changed, 632 insertions(+), 1558 deletions(-) delete mode 100644 posthog/session_recordings/queries/session_recording_events.py delete mode 100644 posthog/session_recordings/queries/test/test_session_recording.py diff --git a/ee/session_recordings/session_recording_extensions.py b/ee/session_recordings/session_recording_extensions.py index cb67977b0c3ba..5c44106ff2a1c 100644 --- a/ee/session_recordings/session_recording_extensions.py +++ b/ee/session_recordings/session_recording_extensions.py @@ -10,10 +10,9 @@ from sentry_sdk import capture_exception, capture_message from posthog import settings -from posthog.event_usage import report_team_action from posthog.session_recordings.models.metadata import PersistedRecordingV1 from posthog.session_recordings.models.session_recording import SessionRecording -from posthog.session_recordings.session_recording_helpers import compress_to_string, decompress +from posthog.session_recordings.session_recording_helpers import decompress from posthog.storage import object_storage logger = structlog.get_logger(__name__) @@ -60,8 +59,6 @@ def persist_recording(recording_id: str, team_id: int) -> None: logger.info("Persisting recording: init", recording_id=recording_id, team_id=team_id) - start_time = timezone.now() - if not settings.OBJECT_STORAGE_ENABLED: return @@ -104,49 +101,7 @@ def persist_recording(recording_id: str, team_id: int) -> None: logger.info("Persisting recording: done!", recording_id=recording_id, team_id=team_id, source="s3") return else: - # TODO this can be removed when we're happy with the new storage version - with SNAPSHOT_PERSIST_TIME_HISTOGRAM.labels(source="ClickHouse").time(): - recording.load_snapshots(100_000) # TODO: Paginate rather than hardcode a limit - - content: PersistedRecordingV1 = { - "version": "2022-12-22", - "distinct_id": recording.distinct_id, - "snapshot_data_by_window_id": recording.snapshot_data_by_window_id, - } - - string_content = json.dumps(content, default=str) - string_content = compress_to_string(string_content) - - logger.info("Persisting recording: writing to S3...", recording_id=recording_id, team_id=team_id) - - try: - object_path = recording.build_object_storage_path("2022-12-22") - object_storage.write(object_path, string_content.encode("utf-8")) - recording.object_storage_path = object_path - recording.save() - - report_team_action( - recording.team, - "session recording persisted", - {"total_time_ms": (timezone.now() - start_time).total_seconds() * 1000}, - ) - - logger.info( - "Persisting recording: done!", recording_id=recording_id, team_id=team_id, source="ClickHouse" - ) - except object_storage.ObjectStorageError as ose: - capture_exception(ose) - report_team_action( - recording.team, - "session recording persist failed", - {"total_time_ms": (timezone.now() - start_time).total_seconds() * 1000, "error": str(ose)}, - ) - logger.error( - "session_recording.object-storage-error", - recording_id=recording.session_id, - exception=ose, - exc_info=True, - ) + raise NotImplementedError("ClickHouse backed recordings are not supported") def load_persisted_recording(recording: SessionRecording) -> Optional[PersistedRecordingV1]: diff --git a/ee/session_recordings/test/test_session_recording_extensions.py b/ee/session_recordings/test/test_session_recording_extensions.py index 86b5b5ba2134d..4583f7dacdd9e 100644 --- a/ee/session_recordings/test/test_session_recording_extensions.py +++ b/ee/session_recordings/test/test_session_recording_extensions.py @@ -13,9 +13,8 @@ persist_recording, save_recording_with_new_content, ) +from posthog.models.signals import mute_selected_signals from posthog.session_recordings.models.session_recording import SessionRecording -from posthog.session_recordings.models.session_recording_playlist import SessionRecordingPlaylist -from posthog.session_recordings.models.session_recording_playlist_item import SessionRecordingPlaylistItem from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary from posthog.session_recordings.test.test_factory import create_session_recording_events from posthog.settings import ( @@ -64,8 +63,8 @@ def create_snapshot(self, session_id, timestamp): session_id=session_id, window_id="window_1", snapshots=[snapshot], - use_recording_table=True, - use_replay_table=False, + use_recording_table=False, + use_replay_table=True, ) def test_does_not_persist_too_recent_recording(self): @@ -78,62 +77,6 @@ def test_does_not_persist_too_recent_recording(self): assert not recording.object_storage_path - def test_persists_recording_with_original_version_when_not_in_blob_storage(self): - two_minutes_ago = (datetime.now() - timedelta(minutes=2)).replace(tzinfo=timezone.utc) - with freeze_time(two_minutes_ago): - recording = SessionRecording.objects.create( - team=self.team, session_id=f"test_persists_recording-s1-{uuid4()}" - ) - - self.create_snapshot(recording.session_id, recording.created_at - timedelta(hours=48)) - self.create_snapshot(recording.session_id, recording.created_at - timedelta(hours=46)) - - produce_replay_summary( - session_id=recording.session_id, - team_id=self.team.pk, - first_timestamp=(recording.created_at - timedelta(hours=48)).isoformat(), - last_timestamp=(recording.created_at - timedelta(hours=46)).isoformat(), - distinct_id="distinct_id_1", - first_url="https://app.posthog.com/my-url", - ) - - persist_recording(recording.session_id, recording.team_id) - recording.refresh_from_db() - - assert ( - recording.object_storage_path - == f"session_recordings_lts/team-{self.team.pk}/session-{recording.session_id}" - ) - assert recording.start_time == recording.created_at - timedelta(hours=48) - assert recording.end_time == recording.created_at - timedelta(hours=46) - - assert recording.distinct_id == "distinct_id_1" - assert recording.duration == 7200 - assert recording.click_count == 0 - assert recording.keypress_count == 0 - assert recording.start_url == "https://app.posthog.com/my-url" - - assert load_persisted_recording(recording) == { - "version": "2022-12-22", - "distinct_id": "distinct_id_1", - "snapshot_data_by_window_id": { - "window_1": [ - { - "timestamp": (recording.created_at - timedelta(hours=48)).timestamp() * 1000, - "has_full_snapshot": 1, - "type": 2, - "data": {"source": 0, "href": long_url}, - }, - { - "timestamp": (recording.created_at - timedelta(hours=46)).timestamp() * 1000, - "has_full_snapshot": 1, - "type": 2, - "data": {"source": 0, "href": long_url}, - }, - ] - }, - } - def test_can_build_different_object_storage_paths(self) -> None: produce_replay_summary( session_id="test_can_build_different_object_storage_paths-s1", @@ -205,42 +148,10 @@ def test_persists_recording_from_blob_ingested_storage(self): f"{recording.build_object_storage_path('2023-08-01')}/c", ] - @patch("ee.session_recordings.session_recording_extensions.report_team_action") - def test_persist_tracks_correct_to_posthog(self, mock_capture): - two_minutes_ago = (datetime.now() - timedelta(minutes=2)).replace(tzinfo=timezone.utc) - - with freeze_time(two_minutes_ago): - playlist = SessionRecordingPlaylist.objects.create(team=self.team, name="playlist", created_by=self.user) - recording = SessionRecording.objects.create( - team=self.team, session_id=f"test_persist_tracks_correct_to_posthog-s1-{uuid4()}" - ) - SessionRecordingPlaylistItem.objects.create(playlist=playlist, recording=recording) - - self.create_snapshot(recording.session_id, recording.created_at - timedelta(hours=48)) - self.create_snapshot(recording.session_id, recording.created_at - timedelta(hours=46)) - - produce_replay_summary( - session_id=recording.session_id, - team_id=self.team.pk, - first_timestamp=(recording.created_at - timedelta(hours=48)).isoformat(), - last_timestamp=(recording.created_at - timedelta(hours=46)).isoformat(), - distinct_id="distinct_id_1", - first_url="https://app.posthog.com/my-url", - ) - - persist_recording(recording.session_id, recording.team_id) - - assert mock_capture.call_args_list[0][0][0] == recording.team - assert mock_capture.call_args_list[0][0][1] == "session recording persisted" - - for x in [ - "total_time_ms", - ]: - assert mock_capture.call_args_list[0][0][2][x] > 0 - @patch("ee.session_recordings.session_recording_extensions.object_storage.write") def test_can_save_content_to_new_location(self, mock_write: MagicMock): - with self.settings(OBJECT_STORAGE_SESSION_RECORDING_BLOB_INGESTION_FOLDER=TEST_BUCKET): + # mute selected signals so the post create signal does not try to persist the recording + with self.settings(OBJECT_STORAGE_SESSION_RECORDING_BLOB_INGESTION_FOLDER=TEST_BUCKET), mute_selected_signals(): session_id = f"{uuid4()}" recording = SessionRecording.objects.create( diff --git a/ee/session_recordings/test/test_session_recording_playlist.py b/ee/session_recordings/test/test_session_recording_playlist.py index ddbb4d1195bca..ac233d6f3a380 100644 --- a/ee/session_recordings/test/test_session_recording_playlist.py +++ b/ee/session_recordings/test/test_session_recording_playlist.py @@ -166,14 +166,16 @@ def test_filters_based_on_params(self): assert len(results) == 1 assert results[0]["short_id"] == playlist3.short_id - def test_get_pinned_recordings_for_playlist(self): + @patch("ee.session_recordings.session_recording_extensions.object_storage.copy_objects") + def test_get_pinned_recordings_for_playlist(self, mock_copy_objects: MagicMock) -> None: + mock_copy_objects.return_value = 2 + playlist = SessionRecordingPlaylist.objects.create(team=self.team, name="playlist", created_by=self.user) session_one = f"test_fetch_playlist_recordings-session1-{uuid4()}" session_two = f"test_fetch_playlist_recordings-session2-{uuid4()}" three_days_ago = (datetime.now() - timedelta(days=3)).replace(tzinfo=timezone.utc) - # can't immediately switch playlists to replay table create_session_recording_events( team_id=self.team.id, distinct_id="123", diff --git a/posthog/session_recordings/models/session_recording.py b/posthog/session_recordings/models/session_recording.py index 65dd13b913257..ed7be73c2c208 100644 --- a/posthog/session_recordings/models/session_recording.py +++ b/posthog/session_recordings/models/session_recording.py @@ -1,21 +1,21 @@ from typing import Any, List, Optional, Literal +from django.conf import settings from django.db import models from django.db.models import Count -from django.dispatch import receiver from posthog.celery import ee_persist_single_recording from posthog.models.person.person import Person +from posthog.models.signals import mutable_receiver +from posthog.models.team.team import Team +from posthog.models.utils import UUIDModel from posthog.session_recordings.models.metadata import ( DecompressedRecordingData, RecordingMatchingEvents, RecordingMetadata, ) from posthog.session_recordings.models.session_recording_event import SessionRecordingViewed -from posthog.models.team.team import Team -from posthog.models.utils import UUIDModel from posthog.session_recordings.queries.session_replay_events import SessionReplayEvents -from django.conf import settings class SessionRecording(UUIDModel): @@ -98,19 +98,14 @@ def load_metadata(self) -> bool: return True def load_snapshots(self, limit=20, offset=0) -> None: - from posthog.session_recordings.queries.session_recording_events import SessionRecordingEvents - if self._snapshots: return if self.object_storage_path: self.load_object_data() else: - snapshots = SessionRecordingEvents( - team=self.team, session_recording_id=self.session_id, recording_start_time=self.start_time - ).get_snapshots(limit, offset) - - self._snapshots = snapshots + # TODO this can be removed + raise NotImplementedError("Clickhouse backed snapshots are not supported") def load_object_data(self) -> None: """ @@ -245,7 +240,7 @@ def set_start_url_from_urls(self, urls: Optional[List[str]] = None, first_url: O self.start_url = url.split("?")[0][:512] if url else None -@receiver(models.signals.post_save, sender=SessionRecording) +@mutable_receiver(models.signals.post_save, sender=SessionRecording) def attempt_persist_recording(sender, instance: SessionRecording, created: bool, **kwargs): if created: ee_persist_single_recording.delay(instance.session_id, instance.team_id) diff --git a/posthog/session_recordings/queries/session_recording_events.py b/posthog/session_recordings/queries/session_recording_events.py deleted file mode 100644 index 826fb2a770ab0..0000000000000 --- a/posthog/session_recordings/queries/session_recording_events.py +++ /dev/null @@ -1,87 +0,0 @@ -import json -from datetime import datetime -from typing import Dict, List, Optional, Tuple - -from posthog.client import sync_execute -from posthog.models import Team -from posthog.session_recordings.models.metadata import ( - DecompressedRecordingData, - SessionRecordingEvent, - SnapshotDataTaggedWithWindowId, -) -from posthog.session_recordings.session_recording_helpers import ( - decompress_chunked_snapshot_data, -) - - -class SessionRecordingEvents: - _session_recording_id: str - _recording_start_time: Optional[datetime] - _team: Team - - def __init__(self, session_recording_id: str, team: Team, recording_start_time: Optional[datetime] = None) -> None: - self._session_recording_id = session_recording_id - self._team = team - self._recording_start_time = recording_start_time - - _recording_snapshot_query = """ - SELECT {fields} - FROM session_recording_events - PREWHERE - team_id = %(team_id)s - AND session_id = %(session_id)s - {date_clause} - ORDER BY timestamp - {limit_param} - """ - - def _get_recording_snapshot_date_clause(self) -> Tuple[str, Dict]: - if self._recording_start_time: - # If we can, we want to limit the time range being queried. - # Theoretically, we shouldn't have to look before the recording start time, - # but until we straighten out the recording start time logic, we should have a buffer - return ( - """ - AND toTimeZone(toDateTime(timestamp, 'UTC'), %(timezone)s) >= toDateTime(%(start_time)s, %(timezone)s) - INTERVAL 1 DAY - AND toTimeZone(toDateTime(timestamp, 'UTC'), %(timezone)s) <= toDateTime(%(start_time)s, %(timezone)s) + INTERVAL 2 DAY - """, - {"start_time": self._recording_start_time, "timezone": self._team.timezone}, - ) - return ("", {}) - - def _query_recording_snapshots(self, include_snapshots=False) -> List[SessionRecordingEvent]: - fields = ["session_id", "window_id", "distinct_id", "timestamp", "events_summary"] - if include_snapshots: - fields.append("snapshot_data") - - date_clause, date_clause_params = self._get_recording_snapshot_date_clause() - query = self._recording_snapshot_query.format(date_clause=date_clause, fields=", ".join(fields), limit_param="") - - response = sync_execute( - query, {"team_id": self._team.id, "session_id": self._session_recording_id, **date_clause_params} - ) - - return [ - SessionRecordingEvent( - session_id=columns[0], - window_id=columns[1], - distinct_id=columns[2], - timestamp=columns[3], - events_summary=[json.loads(x) for x in columns[4]] if columns[4] else [], - snapshot_data=json.loads(columns[5]) if len(columns) > 5 else None, - ) - for columns in response - ] - - def get_snapshots(self, limit, offset) -> Optional[DecompressedRecordingData]: - all_snapshots = [ - SnapshotDataTaggedWithWindowId( - window_id=recording_snapshot["window_id"], snapshot_data=recording_snapshot["snapshot_data"] - ) - for recording_snapshot in self._query_recording_snapshots(include_snapshots=True) - ] - decompressed = decompress_chunked_snapshot_data(all_snapshots, limit, offset) - - if decompressed["snapshot_data_by_window_id"] == {}: - return None - return decompressed diff --git a/posthog/session_recordings/queries/test/test_session_recording.py b/posthog/session_recordings/queries/test/test_session_recording.py deleted file mode 100644 index 28f992fabebd8..0000000000000 --- a/posthog/session_recordings/queries/test/test_session_recording.py +++ /dev/null @@ -1,221 +0,0 @@ -from urllib.parse import urlencode - -from dateutil.relativedelta import relativedelta -from django.http import HttpRequest -from django.utils.timezone import now -from freezegun import freeze_time -from rest_framework.request import Request - -from posthog.models import Filter -from posthog.models.team import Team -from posthog.session_recordings.queries.session_recording_events import SessionRecordingEvents -from posthog.session_recordings.session_recording_helpers import ( - DecompressedRecordingData, -) -from posthog.session_recordings.test.test_factory import create_snapshots, create_snapshot -from posthog.test.base import APIBaseTest, ClickhouseTestMixin - - -def create_recording_filter(session_recording_id, limit=None, offset=None) -> Filter: - params = {} - if limit: - params["limit"] = limit - if offset: - params["offset"] = offset - build_req = HttpRequest() - build_req.META = {"HTTP_HOST": "www.testserver"} - - req = Request( - build_req, f"/api/event/session_recording?session_recording_id={session_recording_id}{urlencode(params)}" # type: ignore - ) - return Filter(request=req, data=params) - - -class TestClickhouseSessionRecording(ClickhouseTestMixin, APIBaseTest): - - maxDiff = None - - def test_get_snapshots(self): - with freeze_time("2020-09-13T12:26:40.000Z"): - create_snapshot( - has_full_snapshot=False, - distinct_id="user", - session_id="1", - timestamp=now(), - team_id=self.team.id, - use_replay_table=False, - use_recording_table=True, - ) - create_snapshot( - has_full_snapshot=False, - distinct_id="user", - session_id="1", - timestamp=now() + relativedelta(seconds=10), - team_id=self.team.id, - use_replay_table=False, - use_recording_table=True, - ) - create_snapshot( - has_full_snapshot=False, - distinct_id="user2", - session_id="2", - timestamp=now() + relativedelta(seconds=20), - team_id=self.team.id, - use_replay_table=False, - use_recording_table=True, - ) - create_snapshot( - has_full_snapshot=False, - distinct_id="user", - session_id="1", - timestamp=now() + relativedelta(seconds=30), - team_id=self.team.id, - use_replay_table=False, - use_recording_table=True, - ) - - filter = create_recording_filter("1") - recording: DecompressedRecordingData | None = SessionRecordingEvents( - team=self.team, session_recording_id="1" - ).get_snapshots(filter.limit, filter.offset) - - assert recording is not None - self.assertEqual( - recording["snapshot_data_by_window_id"], - { - "": [ - {"timestamp": 1600000000000, "type": 3, "data": {"source": 0}}, - {"timestamp": 1600000010000, "type": 3, "data": {"source": 0}}, - {"timestamp": 1600000030000, "type": 3, "data": {"source": 0}}, - ] - }, - ) - self.assertEqual(recording["has_next"], False) - - def test_get_snapshots_does_not_leak_teams(self): - with freeze_time("2020-09-13T12:26:40.000Z"): - another_team = Team.objects.create(organization=self.organization) - create_snapshot( - has_full_snapshot=False, - distinct_id="user1", - session_id="1", - timestamp=now() + relativedelta(seconds=10), - team_id=another_team.pk, - data={"source": "other team"}, - use_replay_table=False, - use_recording_table=True, - ) - create_snapshot( - has_full_snapshot=False, - distinct_id="user2", - session_id="1", - timestamp=now(), - team_id=self.team.id, - data={"source": 0}, - use_replay_table=False, - use_recording_table=True, - ) - - filter = create_recording_filter("1") - recording: DecompressedRecordingData | None = SessionRecordingEvents( - team=self.team, session_recording_id="1" - ).get_snapshots(filter.limit, filter.offset) - - assert recording is not None - self.assertEqual( - recording["snapshot_data_by_window_id"], - {"": [{"data": {"source": 0}, "timestamp": 1600000000000, "type": 3}]}, - ) - - def test_get_snapshots_with_no_such_session(self): - filter = create_recording_filter("xxx") - recording: DecompressedRecordingData | None = SessionRecordingEvents( - team=self.team, session_recording_id="xxx" - ).get_snapshots(filter.limit, filter.offset) - - assert recording is None - - def test_get_chunked_snapshots(self): - with freeze_time("2020-09-13T12:26:40.000Z"): - chunked_session_id = "7" - snapshots_per_chunk = 2 - limit = 20 - for _ in range(30): - create_snapshots( - snapshot_count=snapshots_per_chunk, - distinct_id="user", - session_id=chunked_session_id, - timestamp=now(), - team_id=self.team.id, - use_replay_table=False, - use_recording_table=True, - ) - - filter = create_recording_filter(chunked_session_id) - recording: DecompressedRecordingData | None = SessionRecordingEvents( - team=self.team, session_recording_id=chunked_session_id - ).get_snapshots(limit, filter.offset) - - assert recording is not None - self.assertEqual(len(recording["snapshot_data_by_window_id"][""]), limit * snapshots_per_chunk) - self.assertTrue(recording["has_next"]) - - def test_get_chunked_snapshots_with_specific_limit_and_offset(self): - with freeze_time("2020-09-13T12:26:40.000Z"): - chunked_session_id = "7" - limit = 10 - offset = 5 - snapshots_per_chunk = 2 - for index in range(16): - create_snapshots( - snapshot_count=snapshots_per_chunk, - distinct_id="user", - session_id=chunked_session_id, - timestamp=now() + relativedelta(minutes=index), - team_id=self.team.id, - use_replay_table=False, - use_recording_table=True, - ) - - filter = create_recording_filter(chunked_session_id, limit, offset) - recording: DecompressedRecordingData | None = SessionRecordingEvents( - team=self.team, session_recording_id=chunked_session_id - ).get_snapshots(limit, filter.offset) - - assert recording is not None - self.assertEqual(len(recording["snapshot_data_by_window_id"][""]), limit * snapshots_per_chunk) - self.assertEqual(recording["snapshot_data_by_window_id"][""][0]["timestamp"], 1_600_000_300_000) - self.assertTrue(recording["has_next"]) - - def test_get_snapshots_with_date_filter(self): - with freeze_time("2020-09-13T12:26:40.000Z"): - # This snapshot should be filtered out - create_snapshot( - has_full_snapshot=False, - distinct_id="user", - session_id="1", - timestamp=now() - relativedelta(days=2), - team_id=self.team.id, - use_replay_table=False, - use_recording_table=True, - ) - # This snapshot should appear - create_snapshot( - has_full_snapshot=False, - distinct_id="user", - session_id="1", - timestamp=now(), - team_id=self.team.id, - use_replay_table=False, - use_recording_table=True, - ) - - filter = create_recording_filter( - "1", - ) - recording: DecompressedRecordingData | None = SessionRecordingEvents( - team=self.team, session_recording_id="1", recording_start_time=now() - ).get_snapshots(filter.limit, filter.offset) - - assert recording is not None - self.assertEqual(len(recording["snapshot_data_by_window_id"][""]), 1) diff --git a/posthog/session_recordings/test/__snapshots__/test_session_recordings.ambr b/posthog/session_recordings/test/__snapshots__/test_session_recordings.ambr index 78ea1c1d6f5b6..a9f66096059e3 100644 --- a/posthog/session_recordings/test/__snapshots__/test_session_recordings.ambr +++ b/posthog/session_recordings/test/__snapshots__/test_session_recordings.ambr @@ -83,6 +83,59 @@ ' --- # name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.100 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.101 + ' + SELECT "posthog_sessionrecording"."id", + "posthog_sessionrecording"."session_id", + "posthog_sessionrecording"."team_id", + "posthog_sessionrecording"."created_at", + "posthog_sessionrecording"."deleted", + "posthog_sessionrecording"."object_storage_path", + "posthog_sessionrecording"."distinct_id", + "posthog_sessionrecording"."duration", + "posthog_sessionrecording"."active_seconds", + "posthog_sessionrecording"."inactive_seconds", + "posthog_sessionrecording"."start_time", + "posthog_sessionrecording"."end_time", + "posthog_sessionrecording"."click_count", + "posthog_sessionrecording"."keypress_count", + "posthog_sessionrecording"."mouse_activity_count", + "posthog_sessionrecording"."console_log_count", + "posthog_sessionrecording"."console_warn_count", + "posthog_sessionrecording"."console_error_count", + "posthog_sessionrecording"."start_url", + "posthog_sessionrecording"."storage_version", + COUNT("posthog_sessionrecordingplaylistitem"."id") AS "pinned_count" + FROM "posthog_sessionrecording" + LEFT OUTER JOIN "posthog_sessionrecordingplaylistitem" ON ("posthog_sessionrecording"."session_id" = "posthog_sessionrecordingplaylistitem"."recording_id") + WHERE ("posthog_sessionrecording"."session_id" IN ('5', + '4', + '1', + '3', + '2') + AND "posthog_sessionrecording"."team_id" = 2) + GROUP BY "posthog_sessionrecording"."id" /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.102 + ' + SELECT "posthog_sessionrecordingviewed"."session_id" + FROM "posthog_sessionrecordingviewed" + WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 + AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.103 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -104,11 +157,12 @@ WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', 'user2', 'user3', - 'user4') + 'user4', + 'user5') AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.101 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.104 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -123,7 +177,7 @@ 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.102 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.105 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -174,7 +228,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.103 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.106 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -203,7 +257,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.104 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.107 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -247,7 +301,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.105 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.108 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -276,46 +330,13 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.106 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.107 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.108 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- # name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.109 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' @@ -326,7 +347,7 @@ "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' @@ -337,7 +358,7 @@ "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' @@ -348,7 +369,7 @@ "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' @@ -359,7 +380,7 @@ "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' @@ -370,7 +391,7 @@ "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' @@ -381,7 +402,7 @@ "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' @@ -403,7 +424,7 @@ "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' @@ -425,7 +446,7 @@ "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' @@ -459,7 +480,8 @@ '4', '1', '3', - '2') + '2', + '6') AND "posthog_sessionrecording"."team_id" = 2) GROUP BY "posthog_sessionrecording"."id" /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' @@ -470,7 +492,7 @@ "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' @@ -506,7 +528,8 @@ 'user2', 'user3', 'user4', - 'user5') + 'user5', + 'user6') AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- @@ -772,7 +795,7 @@ "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' @@ -783,7 +806,7 @@ "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' @@ -800,50 +823,6 @@ ' --- # name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.137 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.138 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.139 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.14 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.140 ' SELECT "posthog_sessionrecording"."id", "posthog_sessionrecording"."session_id", @@ -873,12 +852,13 @@ '1', '3', '2', + '7', '6') AND "posthog_sessionrecording"."team_id" = 2) GROUP BY "posthog_sessionrecording"."id" /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.141 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.138 ' SELECT "posthog_sessionrecordingviewed"."session_id" FROM "posthog_sessionrecordingviewed" @@ -886,7 +866,7 @@ AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.142 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.139 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -910,11 +890,20 @@ 'user3', 'user4', 'user5', - 'user6') + 'user6', + 'user7') AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.143 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.14 + ' + SELECT "posthog_sessionrecordingviewed"."session_id" + FROM "posthog_sessionrecordingviewed" + WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 + AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.140 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -929,7 +918,7 @@ 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.144 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.141 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -980,7 +969,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.145 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.142 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -1009,7 +998,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.146 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.143 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1053,7 +1042,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.147 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.144 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -1082,7 +1071,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.148 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.145 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1093,7 +1082,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.149 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.146 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1104,18 +1093,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.15 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.150 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.147 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1126,7 +1104,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.151 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.148 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1137,7 +1115,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.152 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.149 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1148,106 +1126,113 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.153 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.154 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.155 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.156 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.15 ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.157 + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."plugins_opt_in", + "posthog_team"."opt_out_capture", + "posthog_team"."event_names", + "posthog_team"."event_names_with_usage", + "posthog_team"."event_properties", + "posthog_team"."event_properties_with_usage", + "posthog_team"."event_properties_numerical" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.150 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.158 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.151 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.159 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.152 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.16 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.153 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.160 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.154 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.161 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.155 ' SELECT "posthog_sessionrecording"."id", "posthog_sessionrecording"."session_id", @@ -1275,6 +1260,7 @@ WHERE ("posthog_sessionrecording"."session_id" IN ('5', '4', '1', + '8', '3', '2', '7', @@ -1283,7 +1269,7 @@ GROUP BY "posthog_sessionrecording"."id" /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.162 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.156 ' SELECT "posthog_sessionrecordingviewed"."session_id" FROM "posthog_sessionrecordingviewed" @@ -1291,7 +1277,7 @@ AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.163 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.157 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -1316,11 +1302,12 @@ 'user4', 'user5', 'user6', - 'user7') + 'user7', + 'user8') AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.164 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.158 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -1335,7 +1322,7 @@ 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.165 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.159 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1386,7 +1373,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.166 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.16 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -1415,7 +1402,36 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.167 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.160 + ' + SELECT "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."email_opt_in", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."events_column_config" + FROM "posthog_user" + WHERE "posthog_user"."id" = 2 + LIMIT 21 /**/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.161 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1459,7 +1475,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.168 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.162 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -1488,7 +1504,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.169 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.163 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1499,15 +1515,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.17 - ' - SELECT "posthog_sessionrecordingviewed"."session_id" - FROM "posthog_sessionrecordingviewed" - WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 - AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.170 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.164 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1518,7 +1526,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.171 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.165 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1529,7 +1537,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.172 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.166 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1540,7 +1548,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.173 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.167 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1551,7 +1559,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.174 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.168 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1562,40 +1570,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.175 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.176 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.177 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.178 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.169 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1606,18 +1581,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.179 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.18 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.17 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1655,20 +1619,24 @@ "posthog_team"."primary_dashboard_id", "posthog_team"."extra_settings", "posthog_team"."correlation_config", - "posthog_team"."session_recording_retention_period_days", - "posthog_team"."plugins_opt_in", - "posthog_team"."opt_out_capture", - "posthog_team"."event_names", - "posthog_team"."event_names_with_usage", - "posthog_team"."event_properties", - "posthog_team"."event_properties_with_usage", - "posthog_team"."event_properties_numerical" + "posthog_team"."session_recording_retention_period_days" FROM "posthog_team" WHERE "posthog_team"."id" = 2 - LIMIT 21 + LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.180 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.170 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.171 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1679,18 +1647,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.181 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.172 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.182 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.173 ' SELECT "posthog_sessionrecording"."id", "posthog_sessionrecording"."session_id", @@ -1722,12 +1690,13 @@ '3', '2', '7', + '9', '6') AND "posthog_sessionrecording"."team_id" = 2) GROUP BY "posthog_sessionrecording"."id" /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.183 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.174 ' SELECT "posthog_sessionrecordingviewed"."session_id" FROM "posthog_sessionrecordingviewed" @@ -1735,7 +1704,7 @@ AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.184 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.175 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -1761,11 +1730,12 @@ 'user5', 'user6', 'user7', - 'user8') + 'user8', + 'user9') AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.185 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.176 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -1780,7 +1750,7 @@ 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.186 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.177 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1831,7 +1801,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.187 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.178 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -1860,7 +1830,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.188 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.179 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1904,7 +1874,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.189 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.18 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -1933,36 +1903,36 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.19 - ' - SELECT "posthog_user"."id", - "posthog_user"."password", - "posthog_user"."last_login", - "posthog_user"."first_name", - "posthog_user"."last_name", - "posthog_user"."is_staff", - "posthog_user"."is_active", - "posthog_user"."date_joined", - "posthog_user"."uuid", - "posthog_user"."current_organization_id", - "posthog_user"."current_team_id", - "posthog_user"."email", - "posthog_user"."pending_email", - "posthog_user"."temporary_token", - "posthog_user"."distinct_id", - "posthog_user"."is_email_verified", - "posthog_user"."has_seen_product_intro_for", - "posthog_user"."email_opt_in", - "posthog_user"."partial_notification_settings", - "posthog_user"."anonymize_data", - "posthog_user"."toolbar_mode", - "posthog_user"."events_column_config" - FROM "posthog_user" - WHERE "posthog_user"."id" = 2 - LIMIT 21 /**/ +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.180 ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.190 + SELECT "posthog_organizationmembership"."id", + "posthog_organizationmembership"."organization_id", + "posthog_organizationmembership"."user_id", + "posthog_organizationmembership"."level", + "posthog_organizationmembership"."joined_at", + "posthog_organizationmembership"."updated_at", + "posthog_organization"."id", + "posthog_organization"."name", + "posthog_organization"."slug", + "posthog_organization"."created_at", + "posthog_organization"."updated_at", + "posthog_organization"."plugins_access_level", + "posthog_organization"."for_internal_metrics", + "posthog_organization"."is_member_join_email_enabled", + "posthog_organization"."enforce_2fa", + "posthog_organization"."customer_id", + "posthog_organization"."available_features", + "posthog_organization"."available_product_features", + "posthog_organization"."usage", + "posthog_organization"."setup_section_2_completed", + "posthog_organization"."personalization", + "posthog_organization"."domain_whitelist" + FROM "posthog_organizationmembership" + INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") + WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.181 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1973,7 +1943,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.191 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.182 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1984,7 +1954,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.192 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.183 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1995,7 +1965,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.193 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.184 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2006,7 +1976,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.194 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.185 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2017,7 +1987,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.195 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.186 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2028,7 +1998,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.196 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.187 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2039,18 +2009,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.197 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.198 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.188 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2061,7 +2020,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.199 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.189 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2072,91 +2031,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.2 - ' - SELECT "posthog_organizationmembership"."id", - "posthog_organizationmembership"."organization_id", - "posthog_organizationmembership"."user_id", - "posthog_organizationmembership"."level", - "posthog_organizationmembership"."joined_at", - "posthog_organizationmembership"."updated_at", - "posthog_organization"."id", - "posthog_organization"."name", - "posthog_organization"."slug", - "posthog_organization"."created_at", - "posthog_organization"."updated_at", - "posthog_organization"."plugins_access_level", - "posthog_organization"."for_internal_metrics", - "posthog_organization"."is_member_join_email_enabled", - "posthog_organization"."enforce_2fa", - "posthog_organization"."customer_id", - "posthog_organization"."available_features", - "posthog_organization"."available_product_features", - "posthog_organization"."usage", - "posthog_organization"."setup_section_2_completed", - "posthog_organization"."personalization", - "posthog_organization"."domain_whitelist" - FROM "posthog_organizationmembership" - INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") - WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.20 - ' - SELECT "posthog_team"."id", - "posthog_team"."uuid", - "posthog_team"."organization_id", - "posthog_team"."api_token", - "posthog_team"."app_urls", - "posthog_team"."name", - "posthog_team"."slack_incoming_webhook", - "posthog_team"."created_at", - "posthog_team"."updated_at", - "posthog_team"."anonymize_ips", - "posthog_team"."completed_snippet_onboarding", - "posthog_team"."has_completed_onboarding_for", - "posthog_team"."ingested_event", - "posthog_team"."autocapture_opt_out", - "posthog_team"."autocapture_exceptions_opt_in", - "posthog_team"."autocapture_exceptions_errors_to_ignore", - "posthog_team"."session_recording_opt_in", - "posthog_team"."capture_console_log_opt_in", - "posthog_team"."capture_performance_opt_in", - "posthog_team"."session_recording_version", - "posthog_team"."signup_token", - "posthog_team"."is_demo", - "posthog_team"."access_control", - "posthog_team"."week_start_day", - "posthog_team"."inject_web_apps", - "posthog_team"."test_account_filters", - "posthog_team"."test_account_filters_default_checked", - "posthog_team"."path_cleaning_filters", - "posthog_team"."timezone", - "posthog_team"."data_attributes", - "posthog_team"."person_display_name_properties", - "posthog_team"."live_events_columns", - "posthog_team"."recording_domains", - "posthog_team"."primary_dashboard_id", - "posthog_team"."extra_settings", - "posthog_team"."correlation_config", - "posthog_team"."session_recording_retention_period_days" - FROM "posthog_team" - WHERE "posthog_team"."id" = 2 - LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.200 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.19 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.201 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.190 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2167,18 +2053,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.202 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.203 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.191 ' SELECT "posthog_sessionrecording"."id", "posthog_sessionrecording"."session_id", @@ -2211,12 +2086,13 @@ '2', '7', '9', - '6') + '6', + '10') AND "posthog_sessionrecording"."team_id" = 2) GROUP BY "posthog_sessionrecording"."id" /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.204 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.192 ' SELECT "posthog_sessionrecordingviewed"."session_id" FROM "posthog_sessionrecordingviewed" @@ -2224,7 +2100,7 @@ AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.205 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.193 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -2244,6 +2120,7 @@ FROM "posthog_persondistinctid" INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', + 'user10', 'user2', 'user3', 'user4', @@ -2255,7 +2132,7 @@ AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.206 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.194 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -2270,160 +2147,7 @@ 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.207 - ' - SELECT "posthog_team"."id", - "posthog_team"."uuid", - "posthog_team"."organization_id", - "posthog_team"."api_token", - "posthog_team"."app_urls", - "posthog_team"."name", - "posthog_team"."slack_incoming_webhook", - "posthog_team"."created_at", - "posthog_team"."updated_at", - "posthog_team"."anonymize_ips", - "posthog_team"."completed_snippet_onboarding", - "posthog_team"."has_completed_onboarding_for", - "posthog_team"."ingested_event", - "posthog_team"."autocapture_opt_out", - "posthog_team"."autocapture_exceptions_opt_in", - "posthog_team"."autocapture_exceptions_errors_to_ignore", - "posthog_team"."session_recording_opt_in", - "posthog_team"."capture_console_log_opt_in", - "posthog_team"."capture_performance_opt_in", - "posthog_team"."session_recording_version", - "posthog_team"."signup_token", - "posthog_team"."is_demo", - "posthog_team"."access_control", - "posthog_team"."week_start_day", - "posthog_team"."inject_web_apps", - "posthog_team"."test_account_filters", - "posthog_team"."test_account_filters_default_checked", - "posthog_team"."path_cleaning_filters", - "posthog_team"."timezone", - "posthog_team"."data_attributes", - "posthog_team"."person_display_name_properties", - "posthog_team"."live_events_columns", - "posthog_team"."recording_domains", - "posthog_team"."primary_dashboard_id", - "posthog_team"."extra_settings", - "posthog_team"."correlation_config", - "posthog_team"."session_recording_retention_period_days", - "posthog_team"."plugins_opt_in", - "posthog_team"."opt_out_capture", - "posthog_team"."event_names", - "posthog_team"."event_names_with_usage", - "posthog_team"."event_properties", - "posthog_team"."event_properties_with_usage", - "posthog_team"."event_properties_numerical" - FROM "posthog_team" - WHERE "posthog_team"."id" = 2 - LIMIT 21 - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.208 - ' - SELECT "posthog_user"."id", - "posthog_user"."password", - "posthog_user"."last_login", - "posthog_user"."first_name", - "posthog_user"."last_name", - "posthog_user"."is_staff", - "posthog_user"."is_active", - "posthog_user"."date_joined", - "posthog_user"."uuid", - "posthog_user"."current_organization_id", - "posthog_user"."current_team_id", - "posthog_user"."email", - "posthog_user"."pending_email", - "posthog_user"."temporary_token", - "posthog_user"."distinct_id", - "posthog_user"."is_email_verified", - "posthog_user"."has_seen_product_intro_for", - "posthog_user"."email_opt_in", - "posthog_user"."partial_notification_settings", - "posthog_user"."anonymize_data", - "posthog_user"."toolbar_mode", - "posthog_user"."events_column_config" - FROM "posthog_user" - WHERE "posthog_user"."id" = 2 - LIMIT 21 /**/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.209 - ' - SELECT "posthog_team"."id", - "posthog_team"."uuid", - "posthog_team"."organization_id", - "posthog_team"."api_token", - "posthog_team"."app_urls", - "posthog_team"."name", - "posthog_team"."slack_incoming_webhook", - "posthog_team"."created_at", - "posthog_team"."updated_at", - "posthog_team"."anonymize_ips", - "posthog_team"."completed_snippet_onboarding", - "posthog_team"."has_completed_onboarding_for", - "posthog_team"."ingested_event", - "posthog_team"."autocapture_opt_out", - "posthog_team"."autocapture_exceptions_opt_in", - "posthog_team"."autocapture_exceptions_errors_to_ignore", - "posthog_team"."session_recording_opt_in", - "posthog_team"."capture_console_log_opt_in", - "posthog_team"."capture_performance_opt_in", - "posthog_team"."session_recording_version", - "posthog_team"."signup_token", - "posthog_team"."is_demo", - "posthog_team"."access_control", - "posthog_team"."week_start_day", - "posthog_team"."inject_web_apps", - "posthog_team"."test_account_filters", - "posthog_team"."test_account_filters_default_checked", - "posthog_team"."path_cleaning_filters", - "posthog_team"."timezone", - "posthog_team"."data_attributes", - "posthog_team"."person_display_name_properties", - "posthog_team"."live_events_columns", - "posthog_team"."recording_domains", - "posthog_team"."primary_dashboard_id", - "posthog_team"."extra_settings", - "posthog_team"."correlation_config", - "posthog_team"."session_recording_retention_period_days" - FROM "posthog_team" - WHERE "posthog_team"."id" = 2 - LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.21 - ' - SELECT "posthog_organizationmembership"."id", - "posthog_organizationmembership"."organization_id", - "posthog_organizationmembership"."user_id", - "posthog_organizationmembership"."level", - "posthog_organizationmembership"."joined_at", - "posthog_organizationmembership"."updated_at", - "posthog_organization"."id", - "posthog_organization"."name", - "posthog_organization"."slug", - "posthog_organization"."created_at", - "posthog_organization"."updated_at", - "posthog_organization"."plugins_access_level", - "posthog_organization"."for_internal_metrics", - "posthog_organization"."is_member_join_email_enabled", - "posthog_organization"."enforce_2fa", - "posthog_organization"."customer_id", - "posthog_organization"."available_features", - "posthog_organization"."available_product_features", - "posthog_organization"."usage", - "posthog_organization"."setup_section_2_completed", - "posthog_organization"."personalization", - "posthog_organization"."domain_whitelist" - FROM "posthog_organizationmembership" - INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") - WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.210 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.2 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -2452,18 +2176,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.211 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.212 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.20 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2474,7 +2187,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.213 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.21 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2485,7 +2198,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.214 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.22 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2496,7 +2209,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.215 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.23 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2507,7 +2220,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.216 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.24 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2518,7 +2231,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.217 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.25 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2529,18 +2242,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.218 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.219 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.26 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2551,18 +2253,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.22 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.220 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.27 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2573,18 +2264,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.221 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.222 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.28 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2595,18 +2275,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.223 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.224 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.29 ' SELECT "posthog_sessionrecording"."id", "posthog_sessionrecording"."session_id", @@ -2631,21 +2300,23 @@ COUNT("posthog_sessionrecordingplaylistitem"."id") AS "pinned_count" FROM "posthog_sessionrecording" LEFT OUTER JOIN "posthog_sessionrecordingplaylistitem" ON ("posthog_sessionrecording"."session_id" = "posthog_sessionrecordingplaylistitem"."recording_id") - WHERE ("posthog_sessionrecording"."session_id" IN ('5', - '4', - '1', - '8', - '3', - '2', - '7', - '9', - '6', - '10') + WHERE ("posthog_sessionrecording"."session_id" IN ('1') AND "posthog_sessionrecording"."team_id" = 2) GROUP BY "posthog_sessionrecording"."id" /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.225 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.3 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RATE_LIMIT_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.30 ' SELECT "posthog_sessionrecordingviewed"."session_id" FROM "posthog_sessionrecordingviewed" @@ -2653,7 +2324,7 @@ AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.226 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.31 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -2672,134 +2343,256 @@ "posthog_person"."version" FROM "posthog_persondistinctid" INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") - WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', - 'user10', - 'user2', - 'user3', - 'user4', - 'user5', - 'user6', - 'user7', - 'user8', - 'user9') + WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1') AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.227 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.32 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version" + FROM "posthog_persondistinctid" + WHERE "posthog_persondistinctid"."person_id" IN (1, + 2, + 3, + 4, + 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.33 + ' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."plugins_opt_in", + "posthog_team"."opt_out_capture", + "posthog_team"."event_names", + "posthog_team"."event_names_with_usage", + "posthog_team"."event_properties", + "posthog_team"."event_properties_with_usage", + "posthog_team"."event_properties_numerical" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.34 ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version" - FROM "posthog_persondistinctid" - WHERE "posthog_persondistinctid"."person_id" IN (1, - 2, - 3, - 4, - 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + SELECT "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."email_opt_in", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."events_column_config" + FROM "posthog_user" + WHERE "posthog_user"."id" = 2 + LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.23 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.35 ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.24 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.36 ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + SELECT "posthog_organizationmembership"."id", + "posthog_organizationmembership"."organization_id", + "posthog_organizationmembership"."user_id", + "posthog_organizationmembership"."level", + "posthog_organizationmembership"."joined_at", + "posthog_organizationmembership"."updated_at", + "posthog_organization"."id", + "posthog_organization"."name", + "posthog_organization"."slug", + "posthog_organization"."created_at", + "posthog_organization"."updated_at", + "posthog_organization"."plugins_access_level", + "posthog_organization"."for_internal_metrics", + "posthog_organization"."is_member_join_email_enabled", + "posthog_organization"."enforce_2fa", + "posthog_organization"."customer_id", + "posthog_organization"."available_features", + "posthog_organization"."available_product_features", + "posthog_organization"."usage", + "posthog_organization"."setup_section_2_completed", + "posthog_organization"."personalization", + "posthog_organization"."domain_whitelist" + FROM "posthog_organizationmembership" + INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") + WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.25 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.37 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.26 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.38 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.27 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.39 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.28 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.4 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.29 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.40 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.3 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.41 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:RATE_LIMIT_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.30 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.42 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.31 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.43 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2810,18 +2603,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.32 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.44 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.33 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.45 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2832,18 +2625,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.34 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.46 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.35 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.47 ' SELECT "posthog_sessionrecording"."id", "posthog_sessionrecording"."session_id", @@ -2868,12 +2661,13 @@ COUNT("posthog_sessionrecordingplaylistitem"."id") AS "pinned_count" FROM "posthog_sessionrecording" LEFT OUTER JOIN "posthog_sessionrecordingplaylistitem" ON ("posthog_sessionrecording"."session_id" = "posthog_sessionrecordingplaylistitem"."recording_id") - WHERE ("posthog_sessionrecording"."session_id" IN ('1') + WHERE ("posthog_sessionrecording"."session_id" IN ('1', + '2') AND "posthog_sessionrecording"."team_id" = 2) GROUP BY "posthog_sessionrecording"."id" /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.36 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.48 ' SELECT "posthog_sessionrecordingviewed"."session_id" FROM "posthog_sessionrecordingviewed" @@ -2881,7 +2675,7 @@ AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.37 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.49 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -2900,11 +2694,23 @@ "posthog_person"."version" FROM "posthog_persondistinctid" INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") - WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1') + WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', + 'user2') AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.38 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.5 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.50 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -2919,7 +2725,7 @@ 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.39 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.51 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2970,18 +2776,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.4 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.40 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.52 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -3010,7 +2805,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.41 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.53 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -3054,7 +2849,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.42 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.54 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -3083,7 +2878,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.43 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.55 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3094,7 +2889,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.44 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.56 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3105,7 +2900,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.45 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.57 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3116,7 +2911,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.46 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.58 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3127,7 +2922,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.47 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.59 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3138,29 +2933,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.48 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.49 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.6 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.5 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.60 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3171,29 +2955,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.50 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.51 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.52 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.61 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3204,18 +2966,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.53 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.62 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.54 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.63 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3226,18 +2988,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.55 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.64 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.56 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.65 ' SELECT "posthog_sessionrecording"."id", "posthog_sessionrecording"."session_id", @@ -3263,12 +3025,13 @@ FROM "posthog_sessionrecording" LEFT OUTER JOIN "posthog_sessionrecordingplaylistitem" ON ("posthog_sessionrecording"."session_id" = "posthog_sessionrecordingplaylistitem"."recording_id") WHERE ("posthog_sessionrecording"."session_id" IN ('1', + '3', '2') AND "posthog_sessionrecording"."team_id" = 2) GROUP BY "posthog_sessionrecording"."id" /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.57 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.66 ' SELECT "posthog_sessionrecordingviewed"."session_id" FROM "posthog_sessionrecordingviewed" @@ -3276,7 +3039,7 @@ AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.58 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.67 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -3296,11 +3059,12 @@ FROM "posthog_persondistinctid" INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', - 'user2') + 'user2', + 'user3') AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.59 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.68 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -3315,18 +3079,7 @@ 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.6 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.60 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.69 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -3377,7 +3130,18 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.61 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.7 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.70 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -3406,7 +3170,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.62 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.71 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -3450,7 +3214,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.63 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.72 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -3479,7 +3243,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.64 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.73 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3490,7 +3254,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.65 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.74 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3501,7 +3265,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.66 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.75 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3512,7 +3276,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.67 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.76 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3523,7 +3287,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.68 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.77 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3534,18 +3298,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.69 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.7 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.78 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3556,7 +3309,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.70 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.79 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3567,18 +3320,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.71 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.8 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.72 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.80 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3589,7 +3342,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.73 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.81 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3600,18 +3353,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.74 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.75 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.82 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3622,18 +3364,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.76 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.77 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.83 ' SELECT "posthog_sessionrecording"."id", "posthog_sessionrecording"."session_id", @@ -3658,14 +3389,15 @@ COUNT("posthog_sessionrecordingplaylistitem"."id") AS "pinned_count" FROM "posthog_sessionrecording" LEFT OUTER JOIN "posthog_sessionrecordingplaylistitem" ON ("posthog_sessionrecording"."session_id" = "posthog_sessionrecordingplaylistitem"."recording_id") - WHERE ("posthog_sessionrecording"."session_id" IN ('1', + WHERE ("posthog_sessionrecording"."session_id" IN ('4', + '1', '3', '2') AND "posthog_sessionrecording"."team_id" = 2) GROUP BY "posthog_sessionrecording"."id" /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.78 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.84 ' SELECT "posthog_sessionrecordingviewed"."session_id" FROM "posthog_sessionrecordingviewed" @@ -3673,7 +3405,7 @@ AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.79 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.85 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -3694,22 +3426,12 @@ INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', 'user2', - 'user3') + 'user3', + 'user4') AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.8 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.80 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.86 ' SELECT "posthog_persondistinctid"."id", "posthog_persondistinctid"."team_id", @@ -3724,7 +3446,7 @@ 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.81 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.87 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -3775,7 +3497,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.82 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.88 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -3804,7 +3526,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.83 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.89 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -3848,7 +3570,18 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.84 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.9 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.90 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -3877,7 +3610,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.85 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.91 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3888,7 +3621,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.86 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.92 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3899,7 +3632,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.87 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.93 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3910,7 +3643,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.88 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.94 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3921,7 +3654,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.89 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.95 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3932,18 +3665,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.9 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.90 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.96 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3954,7 +3676,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.91 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.97 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3965,18 +3687,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.92 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.93 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.98 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3987,29 +3698,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.94 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.95 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.96 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.99 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -4020,55 +3709,3 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.97 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:MATERIALIZED_COLUMNS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.98 - ' - SELECT "posthog_sessionrecording"."id", - "posthog_sessionrecording"."session_id", - "posthog_sessionrecording"."team_id", - "posthog_sessionrecording"."created_at", - "posthog_sessionrecording"."deleted", - "posthog_sessionrecording"."object_storage_path", - "posthog_sessionrecording"."distinct_id", - "posthog_sessionrecording"."duration", - "posthog_sessionrecording"."active_seconds", - "posthog_sessionrecording"."inactive_seconds", - "posthog_sessionrecording"."start_time", - "posthog_sessionrecording"."end_time", - "posthog_sessionrecording"."click_count", - "posthog_sessionrecording"."keypress_count", - "posthog_sessionrecording"."mouse_activity_count", - "posthog_sessionrecording"."console_log_count", - "posthog_sessionrecording"."console_warn_count", - "posthog_sessionrecording"."console_error_count", - "posthog_sessionrecording"."start_url", - "posthog_sessionrecording"."storage_version", - COUNT("posthog_sessionrecordingplaylistitem"."id") AS "pinned_count" - FROM "posthog_sessionrecording" - LEFT OUTER JOIN "posthog_sessionrecordingplaylistitem" ON ("posthog_sessionrecording"."session_id" = "posthog_sessionrecordingplaylistitem"."recording_id") - WHERE ("posthog_sessionrecording"."session_id" IN ('4', - '1', - '3', - '2') - AND "posthog_sessionrecording"."team_id" = 2) - GROUP BY "posthog_sessionrecording"."id" /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.99 - ' - SELECT "posthog_sessionrecordingviewed"."session_id" - FROM "posthog_sessionrecordingviewed" - WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 - AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- diff --git a/posthog/session_recordings/test/test_lts_session_recordings.py b/posthog/session_recordings/test/test_lts_session_recordings.py index b98286e045f25..57cd3e8cba18d 100644 --- a/posthog/session_recordings/test/test_lts_session_recordings.py +++ b/posthog/session_recordings/test/test_lts_session_recordings.py @@ -3,6 +3,7 @@ from unittest.mock import patch, MagicMock, call, Mock from posthog.models import Team +from posthog.models.signals import mute_selected_signals from posthog.session_recordings.models.session_recording import SessionRecording from posthog.test.base import APIBaseTest, ClickhouseTestMixin, QueryMatchingTest @@ -78,19 +79,15 @@ def list_objects_func(path: str) -> List[str]: mock_list_objects.side_effect = list_objects_func - recording = SessionRecording.objects.create( - team=self.team, - session_id=session_id, - # to avoid auto-persistence kicking in when this is None - storage_version="not a know version", - object_storage_path=lts_storage_path, - start_time="1970-01-01T00:00:00.001000Z", - end_time="1970-01-01T00:00:00.002000Z", - ) - # why is this necessary? I don't know... - # but without it, the object has the default storage path 🤷️ - recording.object_storage_path = lts_storage_path - recording.save() + with mute_selected_signals(): + SessionRecording.objects.create( + team=self.team, + session_id=session_id, + storage_version=None, + object_storage_path=lts_storage_path, + start_time="1970-01-01T00:00:00.001000Z", + end_time="1970-01-01T00:00:00.002000Z", + ) response = self.client.get(f"/api/projects/{self.team.id}/session_recordings/{session_id}/snapshots?version=2") response_data = response.json() @@ -198,18 +195,16 @@ def list_objects_func(path: str) -> List[str]: mock_requests.return_value.__enter__.return_value = mock_response mock_requests.return_value.__exit__.return_value = None - recording = SessionRecording.objects.create( - team=self.team, - session_id=session_id, - # to avoid auto-persistence kicking in when this is None - storage_version="not a know version", - object_storage_path=lts_storage_path, - start_time="1970-01-01T00:00:00.001000Z", - end_time="1970-01-01T00:00:00.002000Z", - ) - # something in the setup is triggering a path that saves the recording without the provided path so - recording.object_storage_path = lts_storage_path - recording.save() + with mute_selected_signals(): + SessionRecording.objects.create( + team=self.team, + session_id=session_id, + # to avoid auto-persistence kicking in when this is None + storage_version="not a know version", + object_storage_path=lts_storage_path, + start_time="1970-01-01T00:00:00.001000Z", + end_time="1970-01-01T00:00:00.002000Z", + ) query_parameters = [ "source=blob", diff --git a/posthog/session_recordings/test/test_session_recordings.py b/posthog/session_recordings/test/test_session_recordings.py index a535fba873f09..14820ba9df997 100644 --- a/posthog/session_recordings/test/test_session_recordings.py +++ b/posthog/session_recordings/test/test_session_recordings.py @@ -369,82 +369,6 @@ def test_get_single_session_recording_metadata(self): "storage": "clickhouse", } - def test_get_default_limit_of_chunks(self): - # TODO import causes circular reference... but we're going to delete this soon so... - from posthog.session_recordings.session_recording_api import DEFAULT_RECORDING_CHUNK_LIMIT - - base_time = now() - num_snapshots = DEFAULT_RECORDING_CHUNK_LIMIT + 10 - - for _ in range(num_snapshots): - self.create_snapshot("user", "1", base_time, use_recording_table=True, use_replay_table=False) - - response = self.client.get(f"/api/projects/{self.team.id}/session_recordings/1/snapshots") - response_data = response.json() - self.assertEqual(len(response_data["snapshot_data_by_window_id"][""]), DEFAULT_RECORDING_CHUNK_LIMIT) - - def test_get_snapshots_is_compressed(self): - base_time = now() - num_snapshots = 2 # small contents aren't compressed, needs to be enough data to trigger compression - - for _ in range(num_snapshots): - self.create_snapshot("user", "1", base_time, use_recording_table=True) - - custom_headers = {"HTTP_ACCEPT_ENCODING": "gzip"} - response = self.client.get( - f"/api/projects/{self.team.id}/session_recordings/1/snapshots", - data=None, - follow=False, - secure=False, - **custom_headers, - ) - - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.headers.get("Content-Encoding", None), "gzip") - - def test_get_snapshots_for_chunked_session_recording(self): - # TODO import causes circular reference... but we're going to delete this soon so... - from posthog.session_recordings.session_recording_api import DEFAULT_RECORDING_CHUNK_LIMIT - - chunked_session_id = "chunk_id" - expected_num_requests = 3 - num_chunks = 60 - snapshots_per_chunk = 2 - - with freeze_time("2020-09-13T12:26:40.000Z"): - start_time = now() - for index, s in enumerate(range(num_chunks)): - self.create_snapshots( - snapshots_per_chunk, - "user", - chunked_session_id, - start_time + relativedelta(minutes=s), - window_id="1" if index % 2 == 0 else "2", - use_recording_table=True, - use_replay_table=False, - ) - - next_url = f"/api/projects/{self.team.id}/session_recordings/{chunked_session_id}/snapshots" - - for i in range(expected_num_requests): - response = self.client.get(next_url) - response_data = response.json() - - self.assertEqual( - len(response_data["snapshot_data_by_window_id"]["1"]), - snapshots_per_chunk * DEFAULT_RECORDING_CHUNK_LIMIT / 2, - ) - self.assertEqual( - len(response_data["snapshot_data_by_window_id"]["2"]), - snapshots_per_chunk * DEFAULT_RECORDING_CHUNK_LIMIT / 2, - ) - if i == expected_num_requests - 1: - self.assertIsNone(response_data["next"]) - else: - self.assertIsNotNone(response_data["next"]) - - next_url = response_data["next"] - def test_single_session_recording_doesnt_leak_teams(self): another_team = Team.objects.create(organization=self.organization) self.create_snapshot("user", "id_no_team_leaking", now() - relativedelta(days=1), team_id=another_team.pk) @@ -524,38 +448,6 @@ def test_empty_list_session_ids_filter_returns_no_recordings(self): self.assertEqual(len(response_data["results"]), 0) - def test_regression_encoded_emojis_dont_crash(self): - - Person.objects.create( - team=self.team, distinct_ids=["user"], properties={"$some_prop": "something", "email": "bob@bob.com"} - ) - with freeze_time("2022-01-01T12:00:00.000Z"): - self.create_snapshot( - "user", - "1", - now() - relativedelta(days=1), - # TODO do we need a version of this that writes to blob storage? - snapshot_data={"texts": ["\\ud83d\udc83\\ud83c\\udffb"]}, # This is an invalid encoded emoji - use_recording_table=True, - ) - - response = self.client.get(f"/api/projects/{self.team.id}/session_recordings/1/snapshots") - self.assertEqual(response.status_code, status.HTTP_200_OK) - response_data = response.json() - - assert not response_data["next"] - assert response_data["snapshot_data_by_window_id"] == { - "": [ - { - "texts": ["\\ud83d\udc83\\ud83c\\udffb"], - "timestamp": 1640952000000.0, - "has_full_snapshot": True, - "type": 2, - "data": {"source": 0}, - } - ] - } - def test_delete_session_recording(self): self.create_snapshot("user", "1", now() - relativedelta(days=1), team_id=self.team.pk) response = self.client.delete(f"/api/projects/{self.team.id}/session_recordings/1") @@ -759,13 +651,10 @@ def test_can_not_get_session_recording_blob_that_does_not_exist(self, mock_presi response = self.client.get(url) assert response.status_code == status.HTTP_404_NOT_FOUND - @parameterized.expand( - [ - (False, 3), - (True, 1), - ] - ) - def test_get_via_sharing_token(self, use_recording_events: bool, api_version: int) -> None: + @patch("ee.session_recordings.session_recording_extensions.object_storage.copy_objects") + def test_get_via_sharing_token(self, mock_copy_objects: MagicMock) -> None: + mock_copy_objects.return_value = 2 + other_team = create_team(organization=self.organization) session_id = str(uuid.uuid4()) @@ -775,7 +664,6 @@ def test_get_via_sharing_token(self, use_recording_events: bool, api_version: in session_id, now() - relativedelta(days=1), team_id=self.team.pk, - use_recording_table=use_recording_events, ) token = self.client.patch( @@ -808,9 +696,8 @@ def test_get_via_sharing_token(self, use_recording_events: bool, api_version: in "end_time": "2022-12-31T12:00:00Z", } - # if api_version is three then we should request snapshots with version 2 response = self.client.get( - f"/api/projects/{self.team.id}/session_recordings/{session_id}/snapshots?sharing_access_token={token}&version={api_version-1}" + f"/api/projects/{self.team.id}/session_recordings/{session_id}/snapshots?sharing_access_token={token}&version=2" ) self.assertEqual(response.status_code, status.HTTP_200_OK) From 9a4b1adcaf883f9e71a03f7055356bb152c7d1f9 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Fri, 22 Sep 2023 00:10:16 +0100 Subject: [PATCH 18/41] be --- posthog/api/test/test_capture.py | 98 ++++++++++++-------------------- 1 file changed, 37 insertions(+), 61 deletions(-) diff --git a/posthog/api/test/test_capture.py b/posthog/api/test/test_capture.py index 8d5be14170913..4f3b504b70135 100644 --- a/posthog/api/test/test_capture.py +++ b/posthog/api/test/test_capture.py @@ -37,7 +37,6 @@ from posthog.kafka_client.client import KafkaProducer, sessionRecordingKafkaProducer from posthog.kafka_client.topics import ( KAFKA_EVENTS_PLUGIN_INGESTION_HISTORICAL, - KAFKA_SESSION_RECORDING_EVENTS, KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS, ) from posthog.settings import ( @@ -1178,9 +1177,9 @@ def test_cors_allows_tracing_headers(self, _: str, path: str, headers: List[str] def test_legacy_recording_ingestion_data_sent_to_kafka(self, kafka_produce) -> None: session_id = "some_session_id" self._send_session_recording_event(session_id=session_id) - self.assertEqual(kafka_produce.call_count, 2) + self.assertEqual(kafka_produce.call_count, 1) kafka_topic_used = kafka_produce.call_args_list[0][1]["topic"] - self.assertEqual(kafka_topic_used, KAFKA_SESSION_RECORDING_EVENTS) + self.assertEqual(kafka_topic_used, KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS) key = kafka_produce.call_args_list[0][1]["key"] self.assertEqual(key, session_id) @@ -1205,48 +1204,28 @@ def test_legacy_recording_ingestion_compression_and_transformation(self, kafka_p window_id=window_id, event_data=event_data, ) - self.assertEqual(kafka_produce.call_count, 2) - self.assertEqual(kafka_produce.call_args_list[0][1]["topic"], KAFKA_SESSION_RECORDING_EVENTS) + self.assertEqual(kafka_produce.call_count, 1) + self.assertEqual(kafka_produce.call_args_list[0][1]["topic"], KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS) key = kafka_produce.call_args_list[0][1]["key"] self.assertEqual(key, session_id) data_sent_to_kafka = json.loads(kafka_produce.call_args_list[0][1]["data"]["data"]) - self.assertEqual( - data_sent_to_kafka, - { - "event": "$snapshot", - "properties": { - "$snapshot_data": { - "chunk_count": 1, - "chunk_id": "fake-uuid", - "chunk_index": 0, - "data": "H4sIAIB3mGAC/42NSwqAQAxD31Fk1m4GUUavIi78ggtR/CxEvLoaPweQQJu2SXoeKRuGmZWBWizBw+GrGipyXfJve+smehZGyh/aRtr+mw2FbqP6LryOmZZOOdPj6/T/1VoiQuWGD4sFq8kRyJlxAaIGxIyyAAAA", - "compression": "gzip-base64", - "has_full_snapshot": False, - "events_summary": [ - { - "type": snapshot_type, - "data": {"source": snapshot_source}, - "timestamp": timestamp, - } - ], - }, - "$session_id": session_id, - "$window_id": window_id, - "distinct_id": distinct_id, - }, - "offset": 1993, + assert data_sent_to_kafka == { + "event": "$snapshot_items", + "properties": { + "$snapshot_items": [ + { + "type": snapshot_type, + "timestamp": timestamp, + "data": {"data": event_data, "source": snapshot_source}, + } + ], + "$session_id": session_id, + "$window_id": window_id, + "distinct_id": distinct_id, }, - ) - - @patch("posthog.kafka_client.client._KafkaProducer.produce") - def test_legacy_recording_ingestion_large_is_split_into_multiple_messages(self, kafka_produce) -> None: - self._send_session_recording_event(event_data=large_data_array) - topic_counter = Counter([call[1]["topic"] for call in kafka_produce.call_args_list]) - - assert topic_counter == Counter( - {KAFKA_SESSION_RECORDING_EVENTS: 3, KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS: 1} - ) + "offset": 1993, + } @patch("posthog.kafka_client.client._KafkaProducer.produce") def test_recording_ingestion_can_write_to_blob_ingestion_topic_with_usual_size_limit(self, kafka_produce) -> None: @@ -1256,10 +1235,7 @@ def test_recording_ingestion_can_write_to_blob_ingestion_topic_with_usual_size_l self._send_session_recording_event(event_data=large_data_array) topic_counter = Counter([call[1]["topic"] for call in kafka_produce.call_args_list]) - # this fake data doesn't split, so we send one huge message to the item events topic - assert topic_counter == Counter( - {KAFKA_SESSION_RECORDING_EVENTS: 3, KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS: 1} - ) + assert topic_counter == Counter({KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS: 1}) @patch("posthog.kafka_client.client._KafkaProducer.produce") def test_recording_ingestion_can_write_to_blob_ingestion_topic(self, kafka_produce) -> None: @@ -1269,9 +1245,7 @@ def test_recording_ingestion_can_write_to_blob_ingestion_topic(self, kafka_produ self._send_session_recording_event(event_data=large_data_array) topic_counter = Counter([call[1]["topic"] for call in kafka_produce.call_args_list]) - assert topic_counter == Counter( - {KAFKA_SESSION_RECORDING_EVENTS: 3, KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS: 1} - ) + assert topic_counter == Counter({KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS: 1}) @patch("posthog.kafka_client.client.SessionRecordingKafkaProducer") def test_create_session_recording_kafka_with_expected_hosts( @@ -1320,20 +1294,15 @@ def test_can_redirect_session_recordings_to_alternative_kafka( data = "example" session_id = "test_can_redirect_session_recordings_to_alternative_kafka" self._send_session_recording_event(event_data=data, session_id=session_id) - default_kafka_producer_mock.assert_called() + # session events don't get routed through the default kafka producer + default_kafka_producer_mock.assert_not_called() session_recording_producer_factory_mock.assert_called() - assert len(kafka_produce.call_args_list) == 2 + assert len(kafka_produce.call_args_list) == 1 call_one = kafka_produce.call_args_list[0][1] assert call_one["key"] == session_id - data_sent_to_default_kafka = json.loads(call_one["data"]["data"]) - assert data_sent_to_default_kafka["event"] == "$snapshot" - assert data_sent_to_default_kafka["properties"]["$snapshot_data"]["chunk_count"] == 1 - - call_two = kafka_produce.call_args_list[1][1] - assert call_two["key"] == session_id - data_sent_to_recording_kafka = json.loads(call_two["data"]["data"]) + data_sent_to_recording_kafka = json.loads(call_one["data"]["data"]) assert data_sent_to_recording_kafka["event"] == "$snapshot_items" assert len(data_sent_to_recording_kafka["properties"]["$snapshot_items"]) == 1 @@ -1390,11 +1359,11 @@ def test_quota_limits_ignored_if_disabled(self, kafka_produce) -> None: replace_limited_team_tokens(QuotaResource.RECORDINGS, {self.team.api_token: timezone.now().timestamp() + 10000}) replace_limited_team_tokens(QuotaResource.EVENTS, {self.team.api_token: timezone.now().timestamp() + 10000}) self._send_session_recording_event() - self.assertEqual(kafka_produce.call_count, 2) + self.assertEqual(kafka_produce.call_count, 1) @patch("posthog.kafka_client.client._KafkaProducer.produce") @pytest.mark.ee - def test_quota_limits(self, kafka_produce) -> None: + def test_quota_limits(self, kafka_produce: MagicMock) -> None: from ee.billing.quota_limiting import QuotaResource, replace_limited_team_tokens def _produce_events(): @@ -1415,11 +1384,18 @@ def _produce_events(): with self.settings(QUOTA_LIMITING_ENABLED=True): _produce_events() - self.assertEqual(kafka_produce.call_count, 4) + self.assertEqual( + [c[1]["topic"] for c in kafka_produce.call_args_list], + [ + "session_recording_snapshot_item_events_test", + "events_plugin_ingestion_test", + "events_plugin_ingestion_test", + ], + ) replace_limited_team_tokens(QuotaResource.EVENTS, {self.team.api_token: timezone.now().timestamp() + 10000}) _produce_events() - self.assertEqual(kafka_produce.call_count, 2) # Only the recording event + self.assertEqual(kafka_produce.call_count, 1) # Only the recording event replace_limited_team_tokens( QuotaResource.RECORDINGS, {self.team.api_token: timezone.now().timestamp() + 10000} @@ -1432,7 +1408,7 @@ def _produce_events(): ) replace_limited_team_tokens(QuotaResource.EVENTS, {self.team.api_token: timezone.now().timestamp() - 10000}) _produce_events() - self.assertEqual(kafka_produce.call_count, 4) # All events as limit-until timestamp is in the past + self.assertEqual(kafka_produce.call_count, 3) # All events as limit-until timestamp is in the past @patch("posthog.kafka_client.client._KafkaProducer.produce") def test_capture_historical_analytics_events(self, kafka_produce) -> None: From 95e594fb43efb325fe264ff53a80699a92d83d7d Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 23:18:38 +0000 Subject: [PATCH 19/41] Update query snapshots --- posthog/api/test/__snapshots__/test_cohort.ambr | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/posthog/api/test/__snapshots__/test_cohort.ambr b/posthog/api/test/__snapshots__/test_cohort.ambr index c5a2452e76e4e..65eab54465605 100644 --- a/posthog/api/test/__snapshots__/test_cohort.ambr +++ b/posthog/api/test/__snapshots__/test_cohort.ambr @@ -1,6 +1,6 @@ # name: TestCohort.test_async_deletion_of_cohort ' - /* user_id:116 celery:posthog.tasks.calculate_cohort.calculate_cohort_ch */ + /* user_id:115 celery:posthog.tasks.calculate_cohort.calculate_cohort_ch */ SELECT count(DISTINCT person_id) FROM cohortpeople WHERE team_id = 2 @@ -10,7 +10,7 @@ --- # name: TestCohort.test_async_deletion_of_cohort.1 ' - /* user_id:116 celery:posthog.tasks.calculate_cohort.calculate_cohort_ch */ + /* user_id:115 celery:posthog.tasks.calculate_cohort.calculate_cohort_ch */ INSERT INTO cohortpeople SELECT id, 2 as cohort_id, @@ -83,7 +83,7 @@ --- # name: TestCohort.test_async_deletion_of_cohort.2 ' - /* user_id:116 celery:posthog.tasks.calculate_cohort.calculate_cohort_ch */ + /* user_id:115 celery:posthog.tasks.calculate_cohort.calculate_cohort_ch */ SELECT count(DISTINCT person_id) FROM cohortpeople WHERE team_id = 2 @@ -93,7 +93,7 @@ --- # name: TestCohort.test_async_deletion_of_cohort.3 ' - /* user_id:116 celery:posthog.tasks.calculate_cohort.clear_stale_cohort */ + /* user_id:115 celery:posthog.tasks.calculate_cohort.clear_stale_cohort */ SELECT count() FROM cohortpeople WHERE team_id = 2 @@ -103,7 +103,7 @@ --- # name: TestCohort.test_async_deletion_of_cohort.4 ' - /* user_id:116 celery:posthog.tasks.calculate_cohort.calculate_cohort_ch */ + /* user_id:115 celery:posthog.tasks.calculate_cohort.calculate_cohort_ch */ SELECT count(DISTINCT person_id) FROM cohortpeople WHERE team_id = 2 @@ -113,7 +113,7 @@ --- # name: TestCohort.test_async_deletion_of_cohort.5 ' - /* user_id:116 celery:posthog.tasks.calculate_cohort.calculate_cohort_ch */ + /* user_id:115 celery:posthog.tasks.calculate_cohort.calculate_cohort_ch */ INSERT INTO cohortpeople SELECT id, 2 as cohort_id, @@ -147,7 +147,7 @@ --- # name: TestCohort.test_async_deletion_of_cohort.6 ' - /* user_id:116 celery:posthog.tasks.calculate_cohort.calculate_cohort_ch */ + /* user_id:115 celery:posthog.tasks.calculate_cohort.calculate_cohort_ch */ SELECT count(DISTINCT person_id) FROM cohortpeople WHERE team_id = 2 @@ -157,7 +157,7 @@ --- # name: TestCohort.test_async_deletion_of_cohort.7 ' - /* user_id:116 celery:posthog.tasks.calculate_cohort.clear_stale_cohort */ + /* user_id:115 celery:posthog.tasks.calculate_cohort.clear_stale_cohort */ SELECT count() FROM cohortpeople WHERE team_id = 2 From 36b59c82268f37b5719ab2d360d2a3b350332682 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Fri, 22 Sep 2023 08:10:15 +0100 Subject: [PATCH 20/41] he --- .../tests/test_session_recording_helpers.py | 296 +----------------- .../session_recording_helpers.py | 107 +------ 2 files changed, 3 insertions(+), 400 deletions(-) diff --git a/posthog/helpers/tests/test_session_recording_helpers.py b/posthog/helpers/tests/test_session_recording_helpers.py index f2f73a7fee15e..806f749c28537 100644 --- a/posthog/helpers/tests/test_session_recording_helpers.py +++ b/posthog/helpers/tests/test_session_recording_helpers.py @@ -3,7 +3,7 @@ import random import string from datetime import datetime -from typing import Any, List, Tuple, cast +from typing import Any, List, Tuple import pytest from pytest_mock import MockerFixture @@ -12,8 +12,6 @@ RRWEB_MAP_EVENT_TYPE, SessionRecordingEventSummary, SnapshotData, - SnapshotDataTaggedWithWindowId, - decompress_chunked_snapshot_data, get_events_summary_from_snapshot_data, is_active_event, preprocess_replay_events_for_blob_ingestion, @@ -48,273 +46,6 @@ def test_preprocess_with_no_recordings(): assert mock_capture_flow(events)[0] == events -def test_preprocess_recording_event_groups_snapshots_split_by_session_and_window_id(): - events = [ - { - "event": "$snapshot", - "properties": { - "$session_id": "1234", - "$snapshot_data": {"type": 2, "timestamp": MILLISECOND_TIMESTAMP}, - "distinct_id": "abc123", - }, - }, - { - "event": "$snapshot", - "properties": { - "$session_id": "1234", - "$snapshot_data": {"type": 1, "timestamp": MILLISECOND_TIMESTAMP}, - "distinct_id": "abc123", - }, - }, - { - "event": "$snapshot", - "properties": { - "$session_id": "5678", - "$window_id": "1", - "$snapshot_data": {"type": 1, "timestamp": MILLISECOND_TIMESTAMP}, - "distinct_id": "abc123", - }, - }, - { - "event": "$snapshot", - "properties": { - "$session_id": "5678", - "$window_id": "2", - "$snapshot_data": {"type": 1, "timestamp": MILLISECOND_TIMESTAMP}, - "distinct_id": "abc123", - }, - }, - ] - - preprocessed, _ = mock_capture_flow(events) - assert preprocessed != events - assert len(preprocessed) == 3 - expected_session_ids = ["1234", "5678", "5678"] - expected_window_ids = [None, "1", "2"] - for index, result in enumerate(preprocessed): - assert result["event"] == "$snapshot" - assert result["properties"]["$session_id"] == expected_session_ids[index] - assert result["properties"].get("$window_id") == expected_window_ids[index] - assert result["properties"]["distinct_id"] == "abc123" - assert "chunk_id" in result["properties"]["$snapshot_data"] - assert result["event"] == "$snapshot" - - # it does not rechunk already chunked events - assert mock_capture_flow(preprocessed)[0] == preprocessed - - -def test_compression_and_grouping(raw_snapshot_events, mocker: MockerFixture): - mocker.patch("posthog.models.utils.UUIDT", return_value="0178495e-8521-0000-8e1c-2652fa57099b") - mocker.patch("time.time", return_value=0) - - assert list(mock_capture_flow(raw_snapshot_events)[0]) == [ - { - "event": "$snapshot", - "properties": { - "$session_id": "1234", - "$window_id": "1", - "$snapshot_data": { - "chunk_id": "0178495e-8521-0000-8e1c-2652fa57099b", - "chunk_index": 0, - "chunk_count": 1, - "compression": "gzip-base64", - "data": "H4sIAAAAAAAC//v/L5qhmkGJoYShkqGAIRXIsmJQYDBi0AGSINFMhlygaDGQlQhkFUDlDRlMGUwYzBiMGQyA0AJMQmAtWCemicYUmBjLAAABQ+l7pgAAAA==", - "has_full_snapshot": True, - "events_summary": [ - {"timestamp": MILLISECOND_TIMESTAMP, "type": 2, "data": {}}, - {"timestamp": MILLISECOND_TIMESTAMP, "type": 3, "data": {}}, - ], - }, - "distinct_id": "abc123", - }, - } - ] - - -def test_decompression_results_in_same_data(raw_snapshot_events): - assert len(list(mock_capture_flow(raw_snapshot_events, 1000)[0])) == 1 - assert compress_decompress_and_extract(raw_snapshot_events, 1000) == [ - raw_snapshot_events[0]["properties"]["$snapshot_data"], - raw_snapshot_events[1]["properties"]["$snapshot_data"], - ] - assert len(list(mock_capture_flow(raw_snapshot_events, 100)[0])) == 2 - assert compress_decompress_and_extract(raw_snapshot_events, 100) == [ - raw_snapshot_events[0]["properties"]["$snapshot_data"], - raw_snapshot_events[1]["properties"]["$snapshot_data"], - ] - - -def test_has_full_snapshot_property(raw_snapshot_events): - compressed = list(mock_capture_flow(raw_snapshot_events)[0]) - assert len(compressed) == 1 - assert compressed[0]["properties"]["$snapshot_data"]["has_full_snapshot"] - - raw_snapshot_events[0]["properties"]["$snapshot_data"]["type"] = 0 - compressed = list(mock_capture_flow(raw_snapshot_events)[0]) - assert len(compressed) == 1 - assert not compressed[0]["properties"]["$snapshot_data"]["has_full_snapshot"] - - -def test_decompress_uncompressed_events_returns_unmodified_events(raw_snapshot_events): - snapshot_data_tagged_with_window_id = [] - raw_snapshot_data = [] - for event in raw_snapshot_events: - snapshot_data_tagged_with_window_id.append( - SnapshotDataTaggedWithWindowId(snapshot_data=event["properties"]["$snapshot_data"], window_id="1") - ) - raw_snapshot_data.append(event["properties"]["$snapshot_data"]) - - assert ( - decompress_chunked_snapshot_data(snapshot_data_tagged_with_window_id)["snapshot_data_by_window_id"]["1"] - == raw_snapshot_data - ) - - -def test_decompress_ignores_if_not_enough_chunks(raw_snapshot_events): - raw_snapshot_data = [event["properties"]["$snapshot_data"] for event in raw_snapshot_events] - snapshot_data_list = [ - event["properties"]["$snapshot_data"] for event in mock_capture_flow(raw_snapshot_events, 100)[0] - ] - window_id = "abc123" - snapshot_list = [] - for snapshot_data in snapshot_data_list: - snapshot_list.append(SnapshotDataTaggedWithWindowId(window_id=window_id, snapshot_data=snapshot_data)) - - snapshot_list.append( - SnapshotDataTaggedWithWindowId( - snapshot_data={ - "chunk_id": "unique_id", - "chunk_index": 1, - "chunk_count": 2, - "data": {}, - "compression": "gzip", - "has_full_snapshot": False, - }, - window_id=window_id, - ) - ) - - assert decompress_chunked_snapshot_data(snapshot_list)["snapshot_data_by_window_id"][window_id] == raw_snapshot_data - - -def test_decompress_deduplicates_if_duplicate_chunks(raw_snapshot_events): - raw_snapshot_data = [event["properties"]["$snapshot_data"] for event in raw_snapshot_events] - snapshot_data_list = [ - event["properties"]["$snapshot_data"] for event in mock_capture_flow(raw_snapshot_events, 10)[0] - ] # makes 12 chunks - # take the first four chunks twice, then the remainder, and then again the first four chunks twice from snapshot_data_list - snapshot_data_list = ( - snapshot_data_list[:4] - + snapshot_data_list[:4] - + snapshot_data_list[4:] - + snapshot_data_list[:4] - + snapshot_data_list[:4] - ) - - window_id = "abc123" - snapshot_list = [] - for snapshot_data in snapshot_data_list: - snapshot_list.append(SnapshotDataTaggedWithWindowId(window_id=window_id, snapshot_data=snapshot_data)) - - assert decompress_chunked_snapshot_data(snapshot_list)["snapshot_data_by_window_id"][window_id] == raw_snapshot_data - - -def test_decompress_ignores_if_too_few_chunks_even_after_deduplication(raw_snapshot_events): - snapshot_data_list = [ - event["properties"]["$snapshot_data"] for event in mock_capture_flow(raw_snapshot_events, 20)[0] - ] # makes 6 chunks - - assert len(snapshot_data_list) == 6 - # take the first four chunks four times, then not quite all the remainder - # leaves more than 12 chunks in total, but not enough to decompress - snapshot_data_list = ( - snapshot_data_list[:2] - + snapshot_data_list[:2] - + snapshot_data_list[:2] - + snapshot_data_list[:2] - + snapshot_data_list[4:-1] - ) - - window_id = "abc123" - snapshot_list = [] - for snapshot_data in snapshot_data_list: - snapshot_list.append(SnapshotDataTaggedWithWindowId(window_id=window_id, snapshot_data=snapshot_data)) - - assert decompress_chunked_snapshot_data(snapshot_list)["snapshot_data_by_window_id"][window_id] == [] - - -def test_paginate_decompression(chunked_and_compressed_snapshot_events): - snapshot_data = [ - SnapshotDataTaggedWithWindowId( - snapshot_data=event["properties"]["$snapshot_data"], window_id=event["properties"].get("$window_id") - ) - for event in chunked_and_compressed_snapshot_events - ] - - # Get the first chunk - paginated_events = decompress_chunked_snapshot_data(snapshot_data, 1, 0) - assert paginated_events["has_next"] is True - assert cast(SnapshotData, paginated_events["snapshot_data_by_window_id"][None][0])["type"] == 4 - assert len(paginated_events["snapshot_data_by_window_id"][None]) == 2 # 2 events in a chunk - - # Get the second chunk - paginated_events = decompress_chunked_snapshot_data(snapshot_data, 1, 1) - assert paginated_events["has_next"] is False - assert cast(SnapshotData, paginated_events["snapshot_data_by_window_id"]["1"][0])["type"] == 3 - assert len(paginated_events["snapshot_data_by_window_id"]["1"]) == 2 # 2 events in a chunk - - # Limit exceeds the length - paginated_events = decompress_chunked_snapshot_data(snapshot_data, 10, 0) - assert paginated_events["has_next"] is False - assert len(paginated_events["snapshot_data_by_window_id"]["1"]) == 2 - assert len(paginated_events["snapshot_data_by_window_id"][None]) == 2 - - # Offset exceeds the length - paginated_events = decompress_chunked_snapshot_data(snapshot_data, 10, 2) - assert paginated_events["has_next"] is False - assert paginated_events["snapshot_data_by_window_id"] == {} - - # Non sequential snapshots - snapshot_data = snapshot_data[-3:] + snapshot_data[0:-3] - paginated_events = decompress_chunked_snapshot_data(snapshot_data, 10, 0) - assert paginated_events["has_next"] is False - assert len(paginated_events["snapshot_data_by_window_id"]["1"]) == 2 - assert len(paginated_events["snapshot_data_by_window_id"][None]) == 2 - - # No limit or offset provided - paginated_events = decompress_chunked_snapshot_data(snapshot_data) - assert paginated_events["has_next"] is False - assert len(paginated_events["snapshot_data_by_window_id"]["1"]) == 2 - assert len(paginated_events["snapshot_data_by_window_id"][None]) == 2 - - -def test_decompress_empty_list(chunked_and_compressed_snapshot_events): - paginated_events = decompress_chunked_snapshot_data([]) - assert paginated_events["has_next"] is False - assert paginated_events["snapshot_data_by_window_id"] == {} - - -def test_decompress_data_returning_only_activity_info(chunked_and_compressed_snapshot_events): - snapshot_data = [ - SnapshotDataTaggedWithWindowId( - snapshot_data=event["properties"]["$snapshot_data"], window_id=event["properties"].get("$window_id") - ) - for event in chunked_and_compressed_snapshot_events - ] - paginated_events = decompress_chunked_snapshot_data(snapshot_data, return_only_activity_data=True) - - assert paginated_events["snapshot_data_by_window_id"] == { - None: [ - {"timestamp": 1546300800000, "type": 4, "data": {}}, - {"timestamp": 1546300800000, "type": 2, "data": {}}, - ], - "1": [ - {"timestamp": 1546300800000, "type": 3, "data": {}}, - {"timestamp": 1546300800000, "type": 3, "data": {"source": 2}}, - ], - } - - def test_get_events_summary_from_snapshot_data(): timestamp = round(datetime.now().timestamp() * 1000) @@ -471,31 +202,6 @@ def chunked_and_compressed_snapshot_events(): return list(mock_capture_flow(chunk_1_events)[0]) + list(mock_capture_flow(chunk_2_events)[0]) -def compress_decompress_and_extract(events, chunk_size): - snapshot_data_list = [event["properties"]["$snapshot_data"] for event in mock_capture_flow(events, chunk_size)[0]] - window_id = "abc123" - snapshot_list = [] - for snapshot_data in snapshot_data_list: - snapshot_list.append(SnapshotDataTaggedWithWindowId(window_id=window_id, snapshot_data=snapshot_data)) - - return decompress_chunked_snapshot_data(snapshot_list)["snapshot_data_by_window_id"][window_id] - - -# def test_get_events_summary_from_snapshot_data(): -# timestamp = round(datetime.now().timestamp() * 1000) -# snapshot_events = [ -# {"type": 2, "foo": "bar", "timestamp": timestamp}, -# {"type": 1, "foo": "bar", "timestamp": timestamp}, -# {"type": 1, "foo": "bar", "timestamp": timestamp, "data": {"source": 3}}, -# ] - -# assert get_events_summary_from_snapshot_data(snapshot_events) == [ -# {"timestamp": timestamp, "type": 2, "data": {}}, -# {"timestamp": timestamp, "type": 1, "data": {}}, -# {"timestamp": timestamp, "type": 1, "data": {"source": 3}}, -# ] - - def test_is_active_event(): timestamp = round(datetime.now().timestamp() * 1000) assert is_active_event({"timestamp": timestamp, "type": 3, "data": {}}) is False diff --git a/posthog/session_recordings/session_recording_helpers.py b/posthog/session_recordings/session_recording_helpers.py index 8c7f1964a7d51..e84cab58cfdb0 100644 --- a/posthog/session_recordings/session_recording_helpers.py +++ b/posthog/session_recordings/session_recording_helpers.py @@ -3,16 +3,14 @@ import json from collections import defaultdict from datetime import datetime, timezone -from typing import Any, Callable, DefaultDict, Dict, Generator, List, Optional, Tuple +from typing import Any, Callable, Dict, Generator, List, Tuple from dateutil.parser import ParserError, parse from sentry_sdk.api import capture_exception from posthog.session_recordings.models.metadata import ( - DecompressedRecordingData, SessionRecordingEventSummary, SnapshotData, - SnapshotDataTaggedWithWindowId, ) from posthog.utils import flatten @@ -96,6 +94,7 @@ def split_replay_events(events: List[Event]) -> Tuple[List[Event], List[Event]]: return replay, other +# TODO is this covered by enough tests post-blob ingester rollout def preprocess_replay_events_for_blob_ingestion(events: List[Event], max_size_bytes=1024 * 1024) -> List[Event]: return _process_windowed_events(events, lambda x: preprocess_replay_events(x, max_size_bytes=max_size_bytes)) @@ -235,113 +234,11 @@ def is_unprocessed_snapshot_event(event: Dict) -> bool: raise ValueError('$snapshot events must contain property "$snapshot_data"!') -def compress_to_string(json_string: str) -> str: - compressed_data = gzip.compress(json_string.encode("utf-16", "surrogatepass")) - return base64.b64encode(compressed_data).decode("utf-8") - - def decompress(base64data: str) -> str: compressed_bytes = base64.b64decode(base64data) return gzip.decompress(compressed_bytes).decode("utf-16", "surrogatepass") -def decompress_chunked_snapshot_data( - all_recording_events: List[SnapshotDataTaggedWithWindowId], - limit: Optional[int] = None, - offset: int = 0, - return_only_activity_data: bool = False, -) -> DecompressedRecordingData: - """ - Before data is stored in clickhouse, it is compressed and then chunked. This function - gets back to the original data by unchunking the events and then decompressing the data. - - If limit + offset is provided, then it will paginate the decompression by chunks (not by events, because - you can't decompress an incomplete chunk). - - Depending on the size of the recording, this function can return a lot of data. To decrease the - memory used, you should either use the pagination parameters or pass in 'return_only_activity_data' which - drastically reduces the size of the data returned if you only want the activity data (used for metadata calculation) - """ - - if len(all_recording_events) == 0: - return DecompressedRecordingData(has_next=False, snapshot_data_by_window_id={}) - - snapshot_data_by_window_id = defaultdict(list) - chunks_collector: DefaultDict[str, List[SnapshotDataTaggedWithWindowId]] = defaultdict(list) - processed_chunk_ids = set() - count = 0 - - for event in all_recording_events: - # Handle unchunked snapshots - if "chunk_id" not in event["snapshot_data"]: - count += 1 - - if offset >= count: - continue - - if event["snapshot_data"].get("data_items"): - decompressed_items = [json.loads(decompress(x)) for x in event["snapshot_data"]["data_items"]] - - # New format where the event is a list of raw rrweb events - snapshot_data_by_window_id[event["window_id"]].extend( - event["snapshot_data"]["events_summary"] if return_only_activity_data else decompressed_items - ) - else: - # Old format where the event is just a single raw rrweb event - snapshot_data_by_window_id[event["window_id"]].append( - get_events_summary_from_snapshot_data([event["snapshot_data"]])[0] - if return_only_activity_data - else event["snapshot_data"] - ) - else: - # Handle chunked snapshots - if event["snapshot_data"]["chunk_id"] in processed_chunk_ids: - continue - - chunks = chunks_collector[event["snapshot_data"]["chunk_id"]] - chunks.append(event) - - deduplicated_chunks = {} - for chunk in chunks: - # reduce the chunks into deduplicated chunks by chunk_id taking only the first seen for each chunk_id - if chunk["snapshot_data"]["chunk_index"] not in deduplicated_chunks: - deduplicated_chunks[chunk["snapshot_data"]["chunk_index"]] = chunk - - chunks = chunks_collector[event["snapshot_data"]["chunk_id"]] = list(deduplicated_chunks.values()) - - if len(chunks) == event["snapshot_data"]["chunk_count"]: - count += 1 - chunks_collector[event["snapshot_data"]["chunk_id"]] = [] - - # Somehow mark this chunk_id as processed... - processed_chunk_ids.add(event["snapshot_data"]["chunk_id"]) - - if offset >= count: - continue - - b64_compressed_data = "".join( - chunk["snapshot_data"]["data"] - for chunk in sorted(chunks, key=lambda c: c["snapshot_data"]["chunk_index"]) - ) - decompressed_data = json.loads(decompress(b64_compressed_data)) - - if type(decompressed_data) is dict: - decompressed_data = [decompressed_data] - - if return_only_activity_data: - events_with_only_activity_data = get_events_summary_from_snapshot_data(decompressed_data) - snapshot_data_by_window_id[event["window_id"]].extend(events_with_only_activity_data) - else: - snapshot_data_by_window_id[event["window_id"]].extend(decompressed_data) - - if limit and count >= offset + limit: - break - - has_next = count < len(all_recording_events) - - return DecompressedRecordingData(has_next=has_next, snapshot_data_by_window_id=snapshot_data_by_window_id) - - def is_active_event(event: SessionRecordingEventSummary) -> bool: """ Determines which rr-web events are "active" - meaning user generated From 2fe9fd5d4e2bd47b3cc78baef178d6f3f459c68f Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Fri, 22 Sep 2023 08:56:36 +0100 Subject: [PATCH 21/41] alive --- plugin-server/functional_tests/kafka.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-server/functional_tests/kafka.ts b/plugin-server/functional_tests/kafka.ts index 9879f1a01d14e..4c33975ca69ca 100644 --- a/plugin-server/functional_tests/kafka.ts +++ b/plugin-server/functional_tests/kafka.ts @@ -38,5 +38,5 @@ export async function createKafkaProducer() { export async function produce({ topic, message, key }: { topic: string; message: Buffer | null; key: string }) { producer = producer ?? (await createKafkaProducer()) - await defaultProduce({ producer, topic, value: message, key: Buffer.from(key), waitForAck: true }) + await defaultProduce({ producer, topic, value: message, key: Buffer.from(key) }) } From ef34e52e1eade61bf2ad503e76b5ad5eecf624e7 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Fri, 22 Sep 2023 19:53:05 +0100 Subject: [PATCH 22/41] a little front end deleting --- frontend/src/lib/constants.tsx | 3 - .../player/sessionRecordingDataLogic.ts | 103 +----------------- frontend/src/types.ts | 4 - 3 files changed, 5 insertions(+), 105 deletions(-) diff --git a/frontend/src/lib/constants.tsx b/frontend/src/lib/constants.tsx index 1842e4f2adb4f..2f3fe398cdb36 100644 --- a/frontend/src/lib/constants.tsx +++ b/frontend/src/lib/constants.tsx @@ -145,7 +145,6 @@ export const FEATURE_FLAGS = { EARLY_ACCESS_FEATURE_SITE_BUTTON: 'early-access-feature-site-button', // owner: @neilkakkar HEDGEHOG_MODE_DEBUG: 'hedgehog-mode-debug', // owner: @benjackwhite AUTO_REDIRECT: 'auto-redirect', // owner: @lharries - SESSION_RECORDING_BLOB_REPLAY: 'session-recording-blob-replay', // owner: #team-monitoring SURVEYS: 'surveys', // owner: @liyiy GENERIC_SIGNUP_BENEFITS: 'generic-signup-benefits', // experiment, owner: @raquelmsmith // owner: team monitoring, only to be enabled for PostHog team testing @@ -161,8 +160,6 @@ export const FEATURE_FLAGS = { REDIRECT_SIGNUPS_TO_INSTANCE: 'redirect-signups-to-instance', // owner: @raquelmsmith APPS_AND_EXPORTS_UI: 'apps-and-exports-ui', // owner: @benjackwhite SURVEY_NPS_RESULTS: 'survey-nps-results', // owner: @liyiy - // owner: #team-monitoring - SESSION_RECORDING_ALLOW_V1_SNAPSHOTS: 'session-recording-allow-v1-snapshots', SESSION_REPLAY_CORS_PROXY: 'session-replay-cors-proxy', // owner: #team-monitoring HOGQL_INSIGHTS: 'hogql-insights', // owner: @mariusandra WEBHOOKS_DENYLIST: 'webhooks-denylist', // owner: #team-pipeline diff --git a/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.ts b/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.ts index d74828f8de776..17a3e0c6cb56a 100644 --- a/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.ts +++ b/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.ts @@ -12,7 +12,6 @@ import { SessionPlayerData, SessionPlayerSnapshotData, SessionRecordingId, - SessionRecordingSnapshotResponse, SessionRecordingSnapshotSource, SessionRecordingType, SessionRecordingUsageType, @@ -26,10 +25,7 @@ import { userLogic } from 'scenes/userLogic' import { chainToElements } from 'lib/utils/elements-chain' import { captureException } from '@sentry/react' import { createSegments, mapSnapshotsToWindowId } from './utils/segmenter' -import { featureFlagLogic } from 'lib/logic/featureFlagLogic' -import { FEATURE_FLAGS } from 'lib/constants' import posthog from 'posthog-js' -import { getCurrentExporterData } from '~/exporter/exporterViewLogic' const IS_TEST_MODE = process.env.NODE_ENV === 'test' const BUFFER_MS = 60000 // +- before and after start and end of a recording to query for. @@ -143,7 +139,7 @@ export const sessionRecordingDataLogic = kea([ key(({ sessionRecordingId }) => sessionRecordingId || 'no-session-recording-id'), connect({ logic: [eventUsageLogic], - values: [teamLogic, ['currentTeamId'], userLogic, ['hasAvailableFeature'], featureFlagLogic, ['featureFlags']], + values: [teamLogic, ['currentTeamId'], userLogic, ['hasAvailableFeature']], }), defaults({ sessionPlayerMetaData: null as SessionRecordingType | null, @@ -153,7 +149,6 @@ export const sessionRecordingDataLogic = kea([ loadRecordingMeta: true, maybeLoadRecordingMeta: true, addDiffToRecordingMetaPinnedCount: (diffCount: number) => ({ diffCount }), - loadRecordingSnapshotsV1: (nextUrl?: string) => ({ nextUrl }), loadRecordingSnapshotsV2: (source?: SessionRecordingSnapshotSource) => ({ source }), loadRecordingSnapshots: true, loadRecordingSnapshotsSuccess: true, @@ -176,12 +171,6 @@ export const sessionRecordingDataLogic = kea([ loadRecordingSnapshotsSuccess: (state) => state + 1, }, ], - loadedFromBlobStorage: [ - false as boolean, - { - loadRecordingSnapshotsV2Success: () => true, - }, - ], isNotFound: [ false as boolean, { @@ -209,30 +198,18 @@ export const sessionRecordingDataLogic = kea([ return } if (!values.sessionPlayerSnapshotData?.snapshots) { - // if `getCurrentExporterData` has a value then we're embedded/exported - // so, we always want to use blob replay - if (values.featureFlags[FEATURE_FLAGS.SESSION_RECORDING_BLOB_REPLAY] || getCurrentExporterData()) { - actions.loadRecordingSnapshotsV2() - } else { - actions.loadRecordingSnapshotsV1() - } + actions.loadRecordingSnapshotsV2() } actions.loadEvents() }, loadRecordingSnapshotsV2Success: () => { const { snapshots, sources } = values.sessionPlayerSnapshotData ?? {} if (snapshots && !snapshots.length && sources?.length === 1) { - const canFallbackToClickHouse = values.canFallbackToClickHouseForData - // We got the snapshot response for realtime, and it was empty, so we fall back to the old API - // Until we migrate over we need to fall back to the old API if the new one returns no snapshots + // We got only a snapshot response for realtime, and it was empty posthog.capture('recording_snapshots_v2_empty_response', { source: sources[0], - canFallbackToClickHouse, }) - if (canFallbackToClickHouse) { - actions.loadRecordingSnapshotsV1() - } return } @@ -244,18 +221,7 @@ export const sessionRecordingDataLogic = kea([ actions.loadRecordingSnapshotsV2(nextSourceToLoad) } }, - loadRecordingSnapshotsV1Success: ({ sessionPlayerSnapshotData }) => { - if (sessionPlayerSnapshotData?.sources?.length) { - // v1 request was force-upgraded to v2 - actions.loadRecordingSnapshotsV2Success(sessionPlayerSnapshotData, undefined) - return - } - - actions.loadRecordingSnapshotsSuccess() - - if (values.sessionPlayerSnapshotData?.next) { - actions.loadRecordingSnapshotsV1(values.sessionPlayerSnapshotData?.next) - } + loadRecordingSnapshotsSuccess: () => { if (values.chunkPaginationIndex === 1 || values.loadedFromBlobStorage) { // Not always accurate that recording is playable after first chunk is loaded, but good guesstimate for now // when loading from blob storage by the time this is hit the chunkPaginationIndex is already > 1 @@ -265,14 +231,10 @@ export const sessionRecordingDataLogic = kea([ duration: Math.round(performance.now() - cache.snapshotsStartTime), } } - }, - loadRecordingSnapshotsSuccess: () => { + actions.reportViewed() actions.reportUsageIfFullyLoaded() }, - loadRecordingSnapshotsV1Failure: () => { - actions.loadRecordingSnapshotsFailure() - }, loadRecordingSnapshotsV2Failure: () => { actions.loadRecordingSnapshotsFailure() }, @@ -346,55 +308,6 @@ export const sessionRecordingDataLogic = kea([ sessionPlayerSnapshotData: [ null as SessionPlayerSnapshotData | null, { - loadRecordingSnapshotsV1: async ( - { nextUrl }, - breakpoint - ): Promise => { - cache.snapshotsStartTime = performance.now() - - if (!props.sessionRecordingId) { - return values.sessionPlayerSnapshotData - } - await breakpoint(1) - - const params = toParams({ - recording_start_time: props.recordingStartTime, - }) - const apiUrl = - nextUrl || - `api/projects/${values.currentTeamId}/session_recordings/${props.sessionRecordingId}/snapshots?${params}` - - const response: SessionRecordingSnapshotResponse = await api.get(apiUrl) - breakpoint() - - if (response.snapshot_data_by_window_id) { - // NOTE: This might seem backwards as we translate the snapshotsByWindowId to an array and then derive it again later but - // this is for future support of the API that will return them as a simple array - const snapshots = convertSnapshotsResponse( - response.snapshot_data_by_window_id, - nextUrl ? values.sessionPlayerSnapshotData?.snapshots ?? [] : [] - ) - - posthog.capture('recording_snapshot_loaded', { - source: 'clickhouse', - }) - - return { - snapshots, - next: response.next, - } - } else if (response.sources) { - // we've been force-upgraded to V2 by 302 redirect - const data: SessionPlayerSnapshotData = { - ...(values.sessionPlayerSnapshotData || {}), - } - data.sources = response.sources - return data - } else { - throw new Error('Invalid response from snapshots API') - } - }, - loadRecordingSnapshotsV2: async ({ source }, breakpoint): Promise => { if (!props.sessionRecordingId) { return values.sessionPlayerSnapshotData @@ -568,12 +481,6 @@ export const sessionRecordingDataLogic = kea([ ], })), selectors({ - canFallbackToClickHouseForData: [ - (s) => [s.featureFlags], - (featureFlags) => { - return featureFlags[FEATURE_FLAGS.SESSION_RECORDING_ALLOW_V1_SNAPSHOTS] - }, - ], sessionPlayerData: [ (s) => [ s.sessionPlayerMetaData, diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 32e0e2862ca3f..05d6c9fb1a809 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -670,10 +670,6 @@ export interface SessionRecordingSnapshotResponse { // legacy interface next?: string - // When loaded from S3 - blob_keys?: string[] - // When loaded from Clickhouse (legacy) - snapshot_data_by_window_id?: Record } export type RecordingSnapshot = eventWithTime & { From 93da94a6c0ee5ea7cd24e717a699a0438b94f42f Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Fri, 22 Sep 2023 20:00:24 +0100 Subject: [PATCH 23/41] a little front end deleting --- frontend/src/lib/utils/eventUsageLogic.ts | 8 ++--- .../player/sessionRecordingDataLogic.ts | 30 +++++-------------- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/frontend/src/lib/utils/eventUsageLogic.ts b/frontend/src/lib/utils/eventUsageLogic.ts index fb6a7f022dd31..4a26612f27328 100644 --- a/frontend/src/lib/utils/eventUsageLogic.ts +++ b/frontend/src/lib/utils/eventUsageLogic.ts @@ -351,9 +351,8 @@ export const eventUsageLogic = kea({ playerData: SessionPlayerData, durations: RecordingReportLoadTimes, type: SessionRecordingUsageType, - delay?: number, - loadedFromBlobStorage?: boolean - ) => ({ playerData, durations, type, delay, loadedFromBlobStorage }), + delay?: number + ) => ({ playerData, durations, type, delay }), reportHelpButtonViewed: true, reportHelpButtonUsed: (help_type: HelpType) => ({ help_type }), reportRecordingsListFetched: (loadTime: number) => ({ @@ -831,7 +830,7 @@ export const eventUsageLogic = kea({ reportSavedInsightNewInsightClicked: ({ insightType }) => { posthog.capture('saved insights new insight clicked', { insight_type: insightType }) }, - reportRecording: ({ playerData, durations, type, loadedFromBlobStorage }) => { + reportRecording: ({ playerData, durations, type }) => { // @ts-expect-error const eventIndex = new EventIndex(playerData?.snapshots || []) const payload: Partial = { @@ -845,7 +844,6 @@ export const eventUsageLogic = kea({ page_change_events_length: eventIndex.pageChangeEvents().length, recording_width: eventIndex.getRecordingScreenMetadata(0)[0]?.width, load_time: durations.firstPaint?.duration ?? 0, // TODO: DEPRECATED field. Keep around so dashboards don't break - loadedFromBlobStorage, } posthog.capture(`recording ${type}`, payload) }, diff --git a/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.ts b/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.ts index 17a3e0c6cb56a..8fc5d25ee4c02 100644 --- a/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.ts +++ b/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.ts @@ -30,8 +30,8 @@ import posthog from 'posthog-js' const IS_TEST_MODE = process.env.NODE_ENV === 'test' const BUFFER_MS = 60000 // +- before and after start and end of a recording to query for. -const parseEncodedSnapshots = (items: (EncodedRecordingSnapshot | string)[]): RecordingSnapshot[] => { - const snapshots: RecordingSnapshot[] = items.flatMap((l) => { +const parseEncodedSnapshots = (items: (EncodedRecordingSnapshot | string)[]): RecordingSnapshot[] => + items.flatMap((l) => { try { const snapshotLine = typeof l === 'string' ? (JSON.parse(l) as EncodedRecordingSnapshot) : l const snapshotData = snapshotLine['data'] @@ -46,9 +46,6 @@ const parseEncodedSnapshots = (items: (EncodedRecordingSnapshot | string)[]): Re } }) - return snapshots -} - const getHrefFromSnapshot = (snapshot: RecordingSnapshot): string | undefined => { return (snapshot.data as any)?.href || (snapshot.data as any)?.payload?.href } @@ -165,12 +162,6 @@ export const sessionRecordingDataLogic = kea([ setFilters: (state, { filters }) => ({ ...state, ...filters }), }, ], - chunkPaginationIndex: [ - 0, - { - loadRecordingSnapshotsSuccess: (state) => state + 1, - }, - ], isNotFound: [ false as boolean, { @@ -222,14 +213,9 @@ export const sessionRecordingDataLogic = kea([ } }, loadRecordingSnapshotsSuccess: () => { - if (values.chunkPaginationIndex === 1 || values.loadedFromBlobStorage) { - // Not always accurate that recording is playable after first chunk is loaded, but good guesstimate for now - // when loading from blob storage by the time this is hit the chunkPaginationIndex is already > 1 - // when loading from the API the chunkPaginationIndex is 1 for the first success that reaches this point - cache.firstPaintDurationRow = { - size: (values.sessionPlayerSnapshotData?.snapshots ?? []).length, - duration: Math.round(performance.now() - cache.snapshotsStartTime), - } + cache.firstPaintDurationRow = { + size: (values.sessionPlayerSnapshotData?.snapshots ?? []).length, + duration: Math.round(performance.now() - cache.snapshotsStartTime), } actions.reportViewed() @@ -265,16 +251,14 @@ export const sessionRecordingDataLogic = kea([ values.sessionPlayerData, durations, SessionRecordingUsageType.VIEWED, - 0, - values.loadedFromBlobStorage + 0 ) await breakpoint(IS_TEST_MODE ? 1 : 10000) eventUsageLogic.actions.reportRecording( values.sessionPlayerData, durations, SessionRecordingUsageType.ANALYZED, - 10, - values.loadedFromBlobStorage + 10 ) }, })), From 4b7f77352bdd89b30e4f2f03a7b5941e5e7973b2 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Fri, 22 Sep 2023 22:14:41 +0100 Subject: [PATCH 24/41] fix one test --- .../__mocks__/recording_snapshots.json | 1321 ----------------- .../__mocks__/recording_snapshots.jsonl | 2 + .../player/sessionRecordingDataLogic.test.ts | 309 ++-- 3 files changed, 164 insertions(+), 1468 deletions(-) delete mode 100644 frontend/src/scenes/session-recordings/__mocks__/recording_snapshots.json create mode 100644 frontend/src/scenes/session-recordings/__mocks__/recording_snapshots.jsonl diff --git a/frontend/src/scenes/session-recordings/__mocks__/recording_snapshots.json b/frontend/src/scenes/session-recordings/__mocks__/recording_snapshots.json deleted file mode 100644 index e33e115c9241b..0000000000000 --- a/frontend/src/scenes/session-recordings/__mocks__/recording_snapshots.json +++ /dev/null @@ -1,1321 +0,0 @@ -{ - "next": null, - "snapshot_data_by_window_id": { - "187d7c761a0525d-05f175487d4b65-1d525634-384000-187d7c761a149d0": [ - { - "type": 4, - "data": { "href": "http://localhost:3000/", "width": 2560, "height": 1304 }, - "timestamp": 1682952380877 - }, - { - "type": 2, - "data": { - "node": { - "type": 0, - "childNodes": [ - { "type": 1, "name": "html", "publicId": "", "systemId": "", "id": 2 }, - { - "type": 2, - "tagName": "html", - "attributes": { "lang": "en" }, - "childNodes": [ - { - "type": 2, - "tagName": "head", - "attributes": {}, - "childNodes": [ - { - "type": 2, - "tagName": "meta", - "attributes": { "charset": "utf-8" }, - "childNodes": [], - "id": 5 - }, - { - "type": 2, - "tagName": "title", - "attributes": {}, - "childNodes": [{ "type": 3, "textContent": "PostHog", "id": 7 }], - "id": 6 - }, - { - "type": 2, - "tagName": "meta", - "attributes": { - "name": "viewport", - "content": "width=device-width, initial-scale=1" - }, - "childNodes": [], - "id": 8 - }, - { - "type": 2, - "tagName": "meta", - "attributes": { "name": "next-head-count", "content": "3" }, - "childNodes": [], - "id": 9 - }, - { - "type": 2, - "tagName": "noscript", - "attributes": { "data-n-css": "" }, - "childNodes": [], - "id": 10 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "defer": "", - "nomodule": "", - "src": "http://localhost:3000/_next/static/chunks/polyfills.js?ts=1682952380635" - }, - "childNodes": [], - "id": 11 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "src": "http://localhost:3000/_next/static/chunks/webpack.js?ts=1682952380635", - "defer": "" - }, - "childNodes": [], - "id": 12 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "src": "http://localhost:3000/_next/static/chunks/main.js?ts=1682952380635", - "defer": "" - }, - "childNodes": [], - "id": 13 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "src": "http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1682952380635", - "defer": "" - }, - "childNodes": [], - "id": 14 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "src": "http://localhost:3000/_next/static/chunks/pages/index.js?ts=1682952380635", - "defer": "" - }, - "childNodes": [], - "id": 15 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "src": "http://localhost:3000/_next/static/development/_buildManifest.js?ts=1682952380635", - "defer": "" - }, - "childNodes": [], - "id": 16 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "src": "http://localhost:3000/_next/static/development/_ssgManifest.js?ts=1682952380635", - "defer": "" - }, - "childNodes": [], - "id": 17 - }, - { - "type": 2, - "tagName": "style", - "attributes": {}, - "childNodes": [ - { - "type": 3, - "textContent": "main { margin: 0px auto; max-width: 1200px; padding: 2rem; font-family: helvetica, arial, sans-serif; }.buttons { display: flex; gap: 0.5rem; }", - "isStyle": true, - "id": 19 - } - ], - "id": 18 - }, - { - "type": 2, - "tagName": "noscript", - "attributes": { "id": "__next_css__DO_NOT_USE__" }, - "childNodes": [], - "id": 20 - } - ], - "id": 4 - }, - { - "type": 2, - "tagName": "body", - "attributes": {}, - "childNodes": [ - { - "type": 2, - "tagName": "div", - "attributes": { "id": "__next" }, - "childNodes": [ - { - "type": 2, - "tagName": "main", - "attributes": {}, - "childNodes": [ - { - "type": 2, - "tagName": "h1", - "attributes": {}, - "childNodes": [ - { - "type": 3, - "textContent": "PostHog React", - "id": 25 - } - ], - "id": 24 - }, - { - "type": 2, - "tagName": "div", - "attributes": { "class": "buttons" }, - "childNodes": [ - { - "type": 2, - "tagName": "button", - "attributes": {}, - "childNodes": [ - { - "type": 3, - "textContent": "Capture event", - "id": 28 - } - ], - "id": 27 - }, - { - "type": 2, - "tagName": "button", - "attributes": { - "data-attr": "autocapture-button" - }, - "childNodes": [ - { - "type": 3, - "textContent": "Autocapture buttons", - "id": 30 - } - ], - "id": 29 - }, - { - "type": 2, - "tagName": "button", - "attributes": { - "class": "ph-no-capture", - "rr_width": "155.3046875px", - "rr_height": "21.5px" - }, - "childNodes": [], - "id": 31 - } - ], - "id": 26 - }, - { - "type": 2, - "tagName": "p", - "attributes": {}, - "childNodes": [ - { - "type": 3, - "textContent": "Feature flag response: ", - "id": 33 - }, - { "type": 3, "textContent": "false", "id": 34 } - ], - "id": 32 - } - ], - "id": 23 - } - ], - "id": 22 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "type": "text/javascript", - "src": "http://localhost:8000/static/recorder-v2.js?v=1.53.1" - }, - "childNodes": [], - "id": 35 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "src": "http://localhost:3000/_next/static/chunks/react-refresh.js?ts=1682952380635" - }, - "childNodes": [], - "id": 36 - }, - { - "type": 2, - "tagName": "script", - "attributes": { "id": "__NEXT_DATA__", "type": "application/json" }, - "childNodes": [ - { "type": 3, "textContent": "SCRIPT_PLACEHOLDER", "id": 38 } - ], - "id": 37 - }, - { - "type": 2, - "tagName": "div", - "attributes": { - "id": "__next-build-watcher", - "style": "position: fixed; bottom: 10px; right: 20px; width: 0px; height: 0px; z-index: 99999;" - }, - "childNodes": [ - { - "type": 2, - "tagName": "div", - "attributes": { "id": "container" }, - "childNodes": [ - { "type": 3, "textContent": "\n ", "id": 41 }, - { - "type": 2, - "tagName": "div", - "attributes": { "id": "icon-wrapper" }, - "childNodes": [ - { "type": 3, "textContent": "\n ", "id": 43 }, - { - "type": 2, - "tagName": "svg", - "attributes": { "viewBox": "0 0 226 200" }, - "childNodes": [ - { - "type": 3, - "textContent": "\n ", - "id": 45 - }, - { - "type": 2, - "tagName": "defs", - "attributes": {}, - "childNodes": [ - { - "type": 3, - "textContent": "\n ", - "id": 47 - }, - { - "type": 2, - "tagName": "lineargradient", - "attributes": { - "x1": "114.720775%", - "y1": "181.283245%", - "x2": "39.5399306%", - "y2": "100%", - "id": "linear-gradient" - }, - "childNodes": [ - { - "type": 3, - "textContent": "\n ", - "id": 49 - }, - { - "type": 2, - "tagName": "stop", - "attributes": { - "stop-color": "#000000", - "offset": "0%" - }, - "childNodes": [], - "isSVG": true, - "id": 50 - }, - { - "type": 3, - "textContent": "\n ", - "id": 51 - }, - { - "type": 2, - "tagName": "stop", - "attributes": { - "stop-color": "#FFFFFF", - "offset": "100%" - }, - "childNodes": [], - "isSVG": true, - "id": 52 - }, - { - "type": 3, - "textContent": "\n ", - "id": 53 - } - ], - "isSVG": true, - "id": 48 - }, - { - "type": 3, - "textContent": "\n ", - "id": 54 - } - ], - "isSVG": true, - "id": 46 - }, - { - "type": 3, - "textContent": "\n ", - "id": 55 - }, - { - "type": 2, - "tagName": "g", - "attributes": { - "id": "icon-group", - "fill": "none", - "stroke": "url(#linear-gradient)", - "stroke-width": "18" - }, - "childNodes": [ - { - "type": 3, - "textContent": "\n ", - "id": 57 - }, - { - "type": 2, - "tagName": "path", - "attributes": { - "d": "M113,5.08219117 L4.28393801,197.5 L221.716062,197.5 L113,5.08219117 Z" - }, - "childNodes": [], - "isSVG": true, - "id": 58 - }, - { - "type": 3, - "textContent": "\n ", - "id": 59 - } - ], - "isSVG": true, - "id": 56 - }, - { - "type": 3, - "textContent": "\n ", - "id": 60 - } - ], - "isSVG": true, - "id": 44 - }, - { "type": 3, "textContent": "\n ", "id": 61 } - ], - "id": 42 - }, - { "type": 3, "textContent": "\n ", "id": 62 } - ], - "id": 40, - "isShadow": true - }, - { - "type": 2, - "tagName": "style", - "attributes": {}, - "childNodes": [ - { - "type": 3, - "textContent": "#container { position: absolute; bottom: 10px; right: 30px; border-radius: 3px; background: rgb(0, 0, 0); color: rgb(255, 255, 255); font: initial; cursor: initial; letter-spacing: initial; text-shadow: initial; text-transform: initial; visibility: initial; padding: 7px 10px 8px; align-items: center; box-shadow: rgba(0, 0, 0, 0.25) 0px 11px 40px 0px, rgba(0, 0, 0, 0.12) 0px 2px 10px 0px; display: none; opacity: 0; transition: opacity 0.1s ease 0s, bottom 0.1s ease 0s; animation: 0.1s ease-in-out 0s 1 normal none running fade-in; }#container.visible { display: flex; }#container.building { bottom: 20px; opacity: 1; }#icon-wrapper { width: 16px; height: 16px; }#icon-wrapper > svg { width: 100%; height: 100%; }#icon-group { animation: 1s ease-in-out 0s infinite normal both running strokedash; }@keyframes fade-in { \n 0% { bottom: 10px; opacity: 0; }\n 100% { bottom: 20px; opacity: 1; }\n}@keyframes strokedash { \n 0% { stroke-dasharray: 0, 226; }\n 80%, 100% { stroke-dasharray: 659, 226; }\n}", - "isStyle": true, - "id": 64 - } - ], - "id": 63, - "isShadow": true - } - ], - "id": 39, - "isShadowHost": true - }, - { - "type": 2, - "tagName": "next-route-announcer", - "attributes": {}, - "childNodes": [ - { - "type": 2, - "tagName": "p", - "attributes": { - "aria-live": "assertive", - "id": "__next-route-announcer__", - "role": "alert", - "style": "border: 0px; clip: rect(0px, 0px, 0px, 0px); height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap; overflow-wrap: normal;" - }, - "childNodes": [], - "id": 66 - } - ], - "id": 65 - } - ], - "id": 21 - } - ], - "id": 3 - } - ], - "id": 1 - }, - "initialOffset": { "left": 0, "top": 0 } - }, - "timestamp": 1682952380882 - }, - { - "type": 3, - "data": { "source": 1, "positions": [{ "x": 2027, "y": 120, "id": 22, "timeOffset": 0 }] }, - "timestamp": 1682952383040 - }, - { - "type": 3, - "data": { "source": 2, "type": 1, "id": 3, "x": 1618.84765625, "y": 299.01953125 }, - "timestamp": 1682952383262 - }, - { - "type": 3, - "data": { "source": 2, "type": 0, "id": 3, "x": 1618.84765625, "y": 299.01953125 }, - "timestamp": 1682952383263 - }, - { - "type": 3, - "data": { "source": 2, "type": 2, "id": 3, "x": 1618, "y": 299, "pointerType": 0 }, - "timestamp": 1682952383264 - }, - { - "type": 3, - "data": { - "source": 1, - "positions": [ - { "x": 1618, "y": 299, "id": 3, "timeOffset": -435 }, - { "x": 1609, "y": 296, "id": 3, "timeOffset": -4 } - ] - }, - "timestamp": 1682952383543 - }, - { - "type": 3, - "data": { - "source": 1, - "positions": [ - { "x": 1239, "y": 216, "id": 23, "timeOffset": -460 }, - { "x": 847, "y": 210, "id": 23, "timeOffset": -409 }, - { "x": 788, "y": 215, "id": 23, "timeOffset": -142 }, - { "x": 754, "y": 163, "id": 32, "timeOffset": -77 }, - { "x": 735, "y": 135, "id": 27, "timeOffset": -25 } - ] - }, - "timestamp": 1682952384050 - }, - { - "type": 3, - "data": { "source": 2, "type": 1, "id": 27, "x": 729.30859375, "y": 124.6875 }, - "timestamp": 1682952384230 - }, - { "type": 3, "data": { "source": 2, "type": 5, "id": 27 }, "timestamp": 1682952384231 }, - { - "type": 3, - "data": { "source": 2, "type": 0, "id": 27, "x": 729.30859375, "y": 124.5546875 }, - "timestamp": 1682952384310 - }, - { - "type": 3, - "data": { "source": 2, "type": 2, "id": 27, "x": 729, "y": 124, "pointerType": 0 }, - "timestamp": 1682952384313 - }, - { - "type": 3, - "data": { "source": 2, "type": 1, "id": 27, "x": 729.30859375, "y": 124.0546875 }, - "timestamp": 1682952384447 - }, - { - "type": 3, - "data": { "source": 2, "type": 0, "id": 27, "x": 729.30859375, "y": 124.0546875 }, - "timestamp": 1682952384460 - }, - { - "type": 3, - "data": { "source": 2, "type": 2, "id": 27, "x": 729, "y": 124, "pointerType": 0 }, - "timestamp": 1682952384463 - }, - { "type": 3, "data": { "source": 2, "type": 4, "id": 27, "x": 729, "y": 124 }, "timestamp": 1682952384464 }, - { - "type": 3, - "data": { - "source": 1, - "positions": [ - { "x": 729, "y": 125, "id": 27, "timeOffset": -466 }, - { "x": 729, "y": 125, "id": 27, "timeOffset": -399 }, - { "x": 729, "y": 124, "id": 27, "timeOffset": -346 }, - { "x": 729, "y": 124, "id": 27, "timeOffset": -231 } - ] - }, - "timestamp": 1682952384555 - }, - { - "type": 3, - "data": { "source": 2, "type": 1, "id": 27, "x": 729.30859375, "y": 124.0546875 }, - "timestamp": 1682952384559 - }, - { - "type": 3, - "data": { "source": 2, "type": 0, "id": 27, "x": 729.30859375, "y": 124.0546875 }, - "timestamp": 1682952384675 - }, - { - "type": 3, - "data": { "source": 2, "type": 2, "id": 27, "x": 729, "y": 124, "pointerType": 0 }, - "timestamp": 1682952384676 - }, - { - "type": 3, - "data": { "source": 2, "type": 1, "id": 27, "x": 729.30859375, "y": 124.0546875 }, - "timestamp": 1682952384709 - }, - { - "type": 3, - "data": { "source": 2, "type": 0, "id": 27, "x": 729.30859375, "y": 124.0546875 }, - "timestamp": 1682952384810 - }, - { - "type": 3, - "data": { "source": 2, "type": 2, "id": 27, "x": 729, "y": 124, "pointerType": 0 }, - "timestamp": 1682952384811 - }, - { - "type": 3, - "data": { "source": 1, "positions": [{ "x": 713, "y": 137, "id": 27, "timeOffset": -49 }] }, - "timestamp": 1682952385058 - }, - { - "type": 3, - "data": { "source": 1, "positions": [{ "x": 605, "y": 266, "id": 3, "timeOffset": -487 }] }, - "timestamp": 1682952385562 - }, - { "type": 3, "data": { "source": 2, "type": 6, "id": 27 }, "timestamp": 1682952385719 }, - { "type": 3, "data": { "source": 4, "width": 2560, "height": 476 }, "timestamp": 1682952385738 }, - { - "type": 3, - "data": { "source": 1, "positions": [{ "x": 604, "y": 266, "id": 3, "timeOffset": -22 }] }, - "timestamp": 1682952386063 - }, - { - "type": 3, - "data": { - "source": 1, - "positions": [ - { "x": 453, "y": 173, "id": 22, "timeOffset": -475 }, - { "x": 265, "y": 32, "id": 22, "timeOffset": -418 } - ] - }, - "timestamp": 1682952386571 - } - ], - "187d7c77dfe1d45-08bdcaf91135a2-1d525634-384000-187d7c77dff39a6": [ - { - "type": 4, - "data": { "href": "http://localhost:3000/", "width": 2560, "height": 1304 }, - "timestamp": 1682952388104 - }, - { - "type": 2, - "data": { - "node": { - "type": 0, - "childNodes": [ - { "type": 1, "name": "html", "publicId": "", "systemId": "", "id": 2 }, - { - "type": 2, - "tagName": "html", - "attributes": { "lang": "en" }, - "childNodes": [ - { - "type": 2, - "tagName": "head", - "attributes": {}, - "childNodes": [ - { - "type": 2, - "tagName": "style", - "attributes": { "data-next-hide-fouc": "true" }, - "childNodes": [ - { - "type": 3, - "textContent": "body { display: none; }", - "isStyle": true, - "id": 6 - } - ], - "id": 5 - }, - { - "type": 2, - "tagName": "noscript", - "attributes": { "data-next-hide-fouc": "true" }, - "childNodes": [ - { - "type": 3, - "textContent": "", - "id": 8 - } - ], - "id": 7 - }, - { - "type": 2, - "tagName": "meta", - "attributes": { "charset": "utf-8" }, - "childNodes": [], - "id": 9 - }, - { - "type": 2, - "tagName": "title", - "attributes": {}, - "childNodes": [{ "type": 3, "textContent": "PostHog", "id": 11 }], - "id": 10 - }, - { - "type": 2, - "tagName": "meta", - "attributes": { - "name": "viewport", - "content": "width=device-width, initial-scale=1" - }, - "childNodes": [], - "id": 12 - }, - { - "type": 2, - "tagName": "meta", - "attributes": { "name": "next-head-count", "content": "3" }, - "childNodes": [], - "id": 13 - }, - { - "type": 2, - "tagName": "noscript", - "attributes": { "data-n-css": "" }, - "childNodes": [], - "id": 14 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "defer": "", - "nomodule": "", - "src": "http://localhost:3000/_next/static/chunks/polyfills.js?ts=1682952387901" - }, - "childNodes": [], - "id": 15 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "src": "http://localhost:3000/_next/static/chunks/webpack.js?ts=1682952387901", - "defer": "" - }, - "childNodes": [], - "id": 16 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "src": "http://localhost:3000/_next/static/chunks/main.js?ts=1682952387901", - "defer": "" - }, - "childNodes": [], - "id": 17 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "src": "http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1682952387901", - "defer": "" - }, - "childNodes": [], - "id": 18 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "src": "http://localhost:3000/_next/static/chunks/pages/index.js?ts=1682952387901", - "defer": "" - }, - "childNodes": [], - "id": 19 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "src": "http://localhost:3000/_next/static/development/_buildManifest.js?ts=1682952387901", - "defer": "" - }, - "childNodes": [], - "id": 20 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "src": "http://localhost:3000/_next/static/development/_ssgManifest.js?ts=1682952387901", - "defer": "" - }, - "childNodes": [], - "id": 21 - }, - { - "type": 2, - "tagName": "style", - "attributes": {}, - "childNodes": [ - { - "type": 3, - "textContent": "main { margin: 0px auto; max-width: 1200px; padding: 2rem; font-family: helvetica, arial, sans-serif; }.buttons { display: flex; gap: 0.5rem; }", - "isStyle": true, - "id": 23 - } - ], - "id": 22 - }, - { - "type": 2, - "tagName": "noscript", - "attributes": { "id": "__next_css__DO_NOT_USE__" }, - "childNodes": [], - "id": 24 - } - ], - "id": 4 - }, - { - "type": 2, - "tagName": "body", - "attributes": {}, - "childNodes": [ - { - "type": 2, - "tagName": "div", - "attributes": { "id": "__next" }, - "childNodes": [ - { - "type": 2, - "tagName": "main", - "attributes": {}, - "childNodes": [ - { - "type": 2, - "tagName": "h1", - "attributes": {}, - "childNodes": [ - { - "type": 3, - "textContent": "PostHog React", - "id": 29 - } - ], - "id": 28 - }, - { - "type": 2, - "tagName": "div", - "attributes": { "class": "buttons" }, - "childNodes": [ - { - "type": 2, - "tagName": "button", - "attributes": {}, - "childNodes": [ - { - "type": 3, - "textContent": "Capture event", - "id": 32 - } - ], - "id": 31 - }, - { - "type": 2, - "tagName": "button", - "attributes": { - "data-attr": "autocapture-button" - }, - "childNodes": [ - { - "type": 3, - "textContent": "Autocapture buttons", - "id": 34 - } - ], - "id": 33 - }, - { - "type": 2, - "tagName": "button", - "attributes": { - "class": "ph-no-capture", - "rr_width": "0px", - "rr_height": "0px" - }, - "childNodes": [], - "id": 35 - } - ], - "id": 30 - }, - { - "type": 2, - "tagName": "p", - "attributes": {}, - "childNodes": [ - { - "type": 3, - "textContent": "Feature flag response: ", - "id": 37 - } - ], - "id": 36 - } - ], - "id": 27 - } - ], - "id": 26 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "type": "text/javascript", - "src": "http://localhost:8000/static/recorder-v2.js?v=1.53.1" - }, - "childNodes": [], - "id": 38 - }, - { - "type": 2, - "tagName": "script", - "attributes": { - "src": "http://localhost:3000/_next/static/chunks/react-refresh.js?ts=1682952387901" - }, - "childNodes": [], - "id": 39 - }, - { - "type": 2, - "tagName": "script", - "attributes": { "id": "__NEXT_DATA__", "type": "application/json" }, - "childNodes": [ - { "type": 3, "textContent": "SCRIPT_PLACEHOLDER", "id": 41 } - ], - "id": 40 - } - ], - "id": 25 - } - ], - "id": 3 - } - ], - "id": 1 - }, - "initialOffset": { "left": 0, "top": 0 } - }, - "timestamp": 1682952388106 - }, - { - "type": 3, - "data": { - "source": 0, - "texts": [], - "attributes": [], - "removes": [ - { "parentId": 4, "id": 7 }, - { "parentId": 4, "id": 5 } - ], - "adds": [] - }, - "timestamp": 1682952388108 - }, - { - "type": 3, - "data": { - "source": 0, - "texts": [], - "attributes": [], - "removes": [], - "adds": [ - { - "parentId": 25, - "nextId": null, - "node": { - "type": 2, - "tagName": "div", - "attributes": { - "id": "__next-build-watcher", - "style": "position: fixed; bottom: 10px; right: 20px; width: 0px; height: 0px; z-index: 99999;" - }, - "childNodes": [], - "id": 42, - "isShadowHost": true - } - }, - { - "parentId": 42, - "nextId": null, - "node": { - "type": 2, - "tagName": "style", - "attributes": {}, - "childNodes": [], - "id": 43, - "isShadow": true - } - }, - { - "parentId": 43, - "nextId": null, - "node": { - "type": 3, - "textContent": "#container { position: absolute; bottom: 10px; right: 30px; border-radius: 3px; background: rgb(0, 0, 0); color: rgb(255, 255, 255); font: initial; cursor: initial; letter-spacing: initial; text-shadow: initial; text-transform: initial; visibility: initial; padding: 7px 10px 8px; align-items: center; box-shadow: rgba(0, 0, 0, 0.25) 0px 11px 40px 0px, rgba(0, 0, 0, 0.12) 0px 2px 10px 0px; display: none; opacity: 0; transition: opacity 0.1s ease 0s, bottom 0.1s ease 0s; animation: 0.1s ease-in-out 0s 1 normal none running fade-in; }#container.visible { display: flex; }#container.building { bottom: 20px; opacity: 1; }#icon-wrapper { width: 16px; height: 16px; }#icon-wrapper > svg { width: 100%; height: 100%; }#icon-group { animation: 1s ease-in-out 0s infinite normal both running strokedash; }@keyframes fade-in { \n 0% { bottom: 10px; opacity: 0; }\n 100% { bottom: 20px; opacity: 1; }\n}@keyframes strokedash { \n 0% { stroke-dasharray: 0, 226; }\n 80%, 100% { stroke-dasharray: 659, 226; }\n}", - "isStyle": true, - "id": 44 - } - }, - { - "parentId": 42, - "nextId": 43, - "node": { - "type": 2, - "tagName": "div", - "attributes": { "id": "container" }, - "childNodes": [], - "id": 45, - "isShadow": true - } - }, - { "parentId": 45, "nextId": null, "node": { "type": 3, "textContent": "\n ", "id": 46 } }, - { - "parentId": 45, - "nextId": 46, - "node": { - "type": 2, - "tagName": "div", - "attributes": { "id": "icon-wrapper" }, - "childNodes": [], - "id": 47 - } - }, - { "parentId": 45, "nextId": 47, "node": { "type": 3, "textContent": "\n ", "id": 48 } }, - { "parentId": 47, "nextId": null, "node": { "type": 3, "textContent": "\n ", "id": 49 } }, - { - "parentId": 47, - "nextId": 49, - "node": { - "type": 2, - "tagName": "svg", - "attributes": { "viewBox": "0 0 226 200" }, - "childNodes": [], - "isSVG": true, - "id": 50 - } - }, - { "parentId": 47, "nextId": 50, "node": { "type": 3, "textContent": "\n ", "id": 51 } }, - { "parentId": 50, "nextId": null, "node": { "type": 3, "textContent": "\n ", "id": 52 } }, - { - "parentId": 50, - "nextId": 52, - "node": { - "type": 2, - "tagName": "g", - "attributes": { - "id": "icon-group", - "fill": "none", - "stroke": "url(#linear-gradient)", - "stroke-width": "18" - }, - "childNodes": [], - "isSVG": true, - "id": 53 - } - }, - { "parentId": 50, "nextId": 53, "node": { "type": 3, "textContent": "\n ", "id": 54 } }, - { - "parentId": 50, - "nextId": 54, - "node": { - "type": 2, - "tagName": "defs", - "attributes": {}, - "childNodes": [], - "isSVG": true, - "id": 55 - } - }, - { "parentId": 50, "nextId": 55, "node": { "type": 3, "textContent": "\n ", "id": 56 } }, - { - "parentId": 55, - "nextId": null, - "node": { "type": 3, "textContent": "\n ", "id": 57 } - }, - { - "parentId": 55, - "nextId": 57, - "node": { - "type": 2, - "tagName": "lineargradient", - "attributes": { - "x1": "114.720775%", - "y1": "181.283245%", - "x2": "39.5399306%", - "y2": "100%", - "id": "linear-gradient" - }, - "childNodes": [], - "isSVG": true, - "id": 58 - } - }, - { - "parentId": 55, - "nextId": 58, - "node": { "type": 3, "textContent": "\n ", "id": 59 } - }, - { - "parentId": 58, - "nextId": null, - "node": { "type": 3, "textContent": "\n ", "id": 60 } - }, - { - "parentId": 58, - "nextId": 60, - "node": { - "type": 2, - "tagName": "stop", - "attributes": { "stop-color": "#FFFFFF", "offset": "100%" }, - "childNodes": [], - "isSVG": true, - "id": 61 - } - }, - { - "parentId": 58, - "nextId": 61, - "node": { "type": 3, "textContent": "\n ", "id": 62 } - }, - { - "parentId": 58, - "nextId": 62, - "node": { - "type": 2, - "tagName": "stop", - "attributes": { "stop-color": "#000000", "offset": "0%" }, - "childNodes": [], - "isSVG": true, - "id": 63 - } - }, - { - "parentId": 58, - "nextId": 63, - "node": { "type": 3, "textContent": "\n ", "id": 64 } - }, - { - "parentId": 53, - "nextId": null, - "node": { "type": 3, "textContent": "\n ", "id": 65 } - }, - { - "parentId": 53, - "nextId": 65, - "node": { - "type": 2, - "tagName": "path", - "attributes": { - "d": "M113,5.08219117 L4.28393801,197.5 L221.716062,197.5 L113,5.08219117 Z" - }, - "childNodes": [], - "isSVG": true, - "id": 66 - } - }, - { "parentId": 53, "nextId": 66, "node": { "type": 3, "textContent": "\n ", "id": 67 } } - ] - }, - "timestamp": 1682952388117 - }, - { - "type": 3, - "data": { - "source": 0, - "texts": [], - "attributes": [], - "removes": [ - { "parentId": 10, "id": 11 }, - { "parentId": 4, "id": 12 } - ], - "adds": [ - { "parentId": 10, "nextId": null, "node": { "type": 3, "textContent": "PostHog", "id": 68 } }, - { - "parentId": 4, - "nextId": 13, - "node": { - "type": 2, - "tagName": "meta", - "attributes": { "name": "viewport", "content": "width=device-width, initial-scale=1" }, - "childNodes": [], - "id": 69 - } - }, - { - "parentId": 25, - "nextId": null, - "node": { - "type": 2, - "tagName": "next-route-announcer", - "attributes": {}, - "childNodes": [], - "id": 70 - } - }, - { - "parentId": 70, - "nextId": null, - "node": { - "type": 2, - "tagName": "p", - "attributes": { - "aria-live": "assertive", - "id": "__next-route-announcer__", - "role": "alert", - "style": "border: 0px; clip: rect(0px, 0px, 0px, 0px); height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap; overflow-wrap: normal;" - }, - "childNodes": [], - "id": 71 - } - }, - { "parentId": 36, "nextId": null, "node": { "type": 3, "textContent": "false", "id": 72 } } - ] - }, - "timestamp": 1682952388132 - }, - { - "type": 3, - "data": { "source": 1, "positions": [{ "x": 294, "y": 7, "id": 26, "timeOffset": 0 }] }, - "timestamp": 1682952388659 - }, - { - "type": 3, - "data": { - "source": 1, - "positions": [ - { "x": 577, "y": 269, "id": 3, "timeOffset": -438 }, - { "x": 684, "y": 304, "id": 3, "timeOffset": -239 }, - { "x": 762, "y": 244, "id": 3, "timeOffset": -174 }, - { "x": 815, "y": 203, "id": 27, "timeOffset": -123 } - ] - }, - "timestamp": 1682952389163 - }, - { - "type": 3, - "data": { - "source": 1, - "positions": [ - { "x": 819, "y": 197, "id": 27, "timeOffset": -427 }, - { "x": 831, "y": 176, "id": 27, "timeOffset": -362 }, - { "x": 842, "y": 157, "id": 36, "timeOffset": -312 }, - { "x": 850, "y": 142, "id": 27, "timeOffset": -261 }, - { "x": 852, "y": 137, "id": 33, "timeOffset": -176 }, - { "x": 852, "y": 133, "id": 33, "timeOffset": -111 }, - { "x": 852, "y": 133, "id": 33, "timeOffset": -28 } - ] - }, - "timestamp": 1682952389668 - }, - { - "type": 3, - "data": { "source": 2, "type": 1, "id": 33, "x": 852.7421875, "y": 133.1640625 }, - "timestamp": 1682952389698 - }, - { "type": 3, "data": { "source": 2, "type": 5, "id": 33 }, "timestamp": 1682952389699 }, - { - "type": 3, - "data": { "source": 2, "type": 0, "id": 33, "x": 852.7421875, "y": 133.1640625 }, - "timestamp": 1682952389798 - }, - { - "type": 3, - "data": { "source": 2, "type": 2, "id": 33, "x": 852, "y": 133, "pointerType": 0 }, - "timestamp": 1682952389798 - }, - { - "type": 3, - "data": { "source": 2, "type": 1, "id": 33, "x": 852.7421875, "y": 133.1640625 }, - "timestamp": 1682952389943 - }, - { - "type": 3, - "data": { "source": 2, "type": 0, "id": 33, "x": 852.7421875, "y": 133.1640625 }, - "timestamp": 1682952390043 - }, - { - "type": 3, - "data": { "source": 2, "type": 2, "id": 33, "x": 852, "y": 133, "pointerType": 0 }, - "timestamp": 1682952390044 - }, - { "type": 3, "data": { "source": 2, "type": 4, "id": 33, "x": 852, "y": 133 }, "timestamp": 1682952390047 }, - { - "type": 3, - "data": { "source": 2, "type": 1, "id": 33, "x": 852.7421875, "y": 133.1640625 }, - "timestamp": 1682952390112 - }, - { - "type": 3, - "data": { "source": 2, "type": 0, "id": 33, "x": 852.7421875, "y": 133.1640625 }, - "timestamp": 1682952390243 - }, - { - "type": 3, - "data": { "source": 2, "type": 2, "id": 33, "x": 852, "y": 133, "pointerType": 0 }, - "timestamp": 1682952390244 - }, - { "type": 3, "data": { "source": 2, "type": 6, "id": 33 }, "timestamp": 1682952392745 } - ] - }, - "storage": "clickhouse" -} diff --git a/frontend/src/scenes/session-recordings/__mocks__/recording_snapshots.jsonl b/frontend/src/scenes/session-recordings/__mocks__/recording_snapshots.jsonl new file mode 100644 index 0000000000000..3fc93d05eb30a --- /dev/null +++ b/frontend/src/scenes/session-recordings/__mocks__/recording_snapshots.jsonl @@ -0,0 +1,2 @@ +{"window_id":"187d7c761a0525d-05f175487d4b65-1d525634-384000-187d7c761a149d0","data":[{"type":4,"data":{"href":"http://localhost:3000/","width":2560,"height":1304},"timestamp":1682952380877},{"type":2,"data":{"node":{"type":0,"childNodes":[{"type":1,"name":"html","publicId":"","systemId":"","id":2},{"type":2,"tagName":"html","attributes":{"lang":"en"},"childNodes":[{"type":2,"tagName":"head","attributes":{},"childNodes":[{"type":2,"tagName":"meta","attributes":{"charset":"utf-8"},"childNodes":[],"id":5},{"type":2,"tagName":"title","attributes":{},"childNodes":[{"type":3,"textContent":"PostHog","id":7}],"id":6},{"type":2,"tagName":"meta","attributes":{"name":"viewport","content":"width=device-width, initial-scale=1"},"childNodes":[],"id":8},{"type":2,"tagName":"meta","attributes":{"name":"next-head-count","content":"3"},"childNodes":[],"id":9},{"type":2,"tagName":"noscript","attributes":{"data-n-css":""},"childNodes":[],"id":10},{"type":2,"tagName":"script","attributes":{"defer":"","nomodule":"","src":"http://localhost:3000/_next/static/chunks/polyfills.js?ts=1682952380635"},"childNodes":[],"id":11},{"type":2,"tagName":"script","attributes":{"src":"http://localhost:3000/_next/static/chunks/webpack.js?ts=1682952380635","defer":""},"childNodes":[],"id":12},{"type":2,"tagName":"script","attributes":{"src":"http://localhost:3000/_next/static/chunks/main.js?ts=1682952380635","defer":""},"childNodes":[],"id":13},{"type":2,"tagName":"script","attributes":{"src":"http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1682952380635","defer":""},"childNodes":[],"id":14},{"type":2,"tagName":"script","attributes":{"src":"http://localhost:3000/_next/static/chunks/pages/index.js?ts=1682952380635","defer":""},"childNodes":[],"id":15},{"type":2,"tagName":"script","attributes":{"src":"http://localhost:3000/_next/static/development/_buildManifest.js?ts=1682952380635","defer":""},"childNodes":[],"id":16},{"type":2,"tagName":"script","attributes":{"src":"http://localhost:3000/_next/static/development/_ssgManifest.js?ts=1682952380635","defer":""},"childNodes":[],"id":17},{"type":2,"tagName":"style","attributes":{},"childNodes":[{"type":3,"textContent":"main { margin: 0px auto; max-width: 1200px; padding: 2rem; font-family: helvetica, arial, sans-serif; }.buttons { display: flex; gap: 0.5rem; }","isStyle":true,"id":19}],"id":18},{"type":2,"tagName":"noscript","attributes":{"id":"__next_css__DO_NOT_USE__"},"childNodes":[],"id":20}],"id":4},{"type":2,"tagName":"body","attributes":{},"childNodes":[{"type":2,"tagName":"div","attributes":{"id":"__next"},"childNodes":[{"type":2,"tagName":"main","attributes":{},"childNodes":[{"type":2,"tagName":"h1","attributes":{},"childNodes":[{"type":3,"textContent":"PostHog React","id":25}],"id":24},{"type":2,"tagName":"div","attributes":{"class":"buttons"},"childNodes":[{"type":2,"tagName":"button","attributes":{},"childNodes":[{"type":3,"textContent":"Capture event","id":28}],"id":27},{"type":2,"tagName":"button","attributes":{"data-attr":"autocapture-button"},"childNodes":[{"type":3,"textContent":"Autocapture buttons","id":30}],"id":29},{"type":2,"tagName":"button","attributes":{"class":"ph-no-capture","rr_width":"155.3046875px","rr_height":"21.5px"},"childNodes":[],"id":31}],"id":26},{"type":2,"tagName":"p","attributes":{},"childNodes":[{"type":3,"textContent":"Feature flag response: ","id":33},{"type":3,"textContent":"false","id":34}],"id":32}],"id":23}],"id":22},{"type":2,"tagName":"script","attributes":{"type":"text/javascript","src":"http://localhost:8000/static/recorder-v2.js?v=1.53.1"},"childNodes":[],"id":35},{"type":2,"tagName":"script","attributes":{"src":"http://localhost:3000/_next/static/chunks/react-refresh.js?ts=1682952380635"},"childNodes":[],"id":36},{"type":2,"tagName":"script","attributes":{"id":"__NEXT_DATA__","type":"application/json"},"childNodes":[{"type":3,"textContent":"SCRIPT_PLACEHOLDER","id":38}],"id":37},{"type":2,"tagName":"div","attributes":{"id":"__next-build-watcher","style":"position: fixed; bottom: 10px; right: 20px; width: 0px; height: 0px; z-index: 99999;"},"childNodes":[{"type":2,"tagName":"div","attributes":{"id":"container"},"childNodes":[{"type":3,"textContent":"\n ","id":41},{"type":2,"tagName":"div","attributes":{"id":"icon-wrapper"},"childNodes":[{"type":3,"textContent":"\n ","id":43},{"type":2,"tagName":"svg","attributes":{"viewBox":"0 0 226 200"},"childNodes":[{"type":3,"textContent":"\n ","id":45},{"type":2,"tagName":"defs","attributes":{},"childNodes":[{"type":3,"textContent":"\n ","id":47},{"type":2,"tagName":"lineargradient","attributes":{"x1":"114.720775%","y1":"181.283245%","x2":"39.5399306%","y2":"100%","id":"linear-gradient"},"childNodes":[{"type":3,"textContent":"\n ","id":49},{"type":2,"tagName":"stop","attributes":{"stop-color":"#000000","offset":"0%"},"childNodes":[],"isSVG":true,"id":50},{"type":3,"textContent":"\n ","id":51},{"type":2,"tagName":"stop","attributes":{"stop-color":"#FFFFFF","offset":"100%"},"childNodes":[],"isSVG":true,"id":52},{"type":3,"textContent":"\n ","id":53}],"isSVG":true,"id":48},{"type":3,"textContent":"\n ","id":54}],"isSVG":true,"id":46},{"type":3,"textContent":"\n ","id":55},{"type":2,"tagName":"g","attributes":{"id":"icon-group","fill":"none","stroke":"url(#linear-gradient)","stroke-width":"18"},"childNodes":[{"type":3,"textContent":"\n ","id":57},{"type":2,"tagName":"path","attributes":{"d":"M113,5.08219117 L4.28393801,197.5 L221.716062,197.5 L113,5.08219117 Z"},"childNodes":[],"isSVG":true,"id":58},{"type":3,"textContent":"\n ","id":59}],"isSVG":true,"id":56},{"type":3,"textContent":"\n ","id":60}],"isSVG":true,"id":44},{"type":3,"textContent":"\n ","id":61}],"id":42},{"type":3,"textContent":"\n ","id":62}],"id":40,"isShadow":true},{"type":2,"tagName":"style","attributes":{},"childNodes":[{"type":3,"textContent":"#container { position: absolute; bottom: 10px; right: 30px; border-radius: 3px; background: rgb(0, 0, 0); color: rgb(255, 255, 255); font: initial; cursor: initial; letter-spacing: initial; text-shadow: initial; text-transform: initial; visibility: initial; padding: 7px 10px 8px; align-items: center; box-shadow: rgba(0, 0, 0, 0.25) 0px 11px 40px 0px, rgba(0, 0, 0, 0.12) 0px 2px 10px 0px; display: none; opacity: 0; transition: opacity 0.1s ease 0s, bottom 0.1s ease 0s; animation: 0.1s ease-in-out 0s 1 normal none running fade-in; }#container.visible { display: flex; }#container.building { bottom: 20px; opacity: 1; }#icon-wrapper { width: 16px; height: 16px; }#icon-wrapper > svg { width: 100%; height: 100%; }#icon-group { animation: 1s ease-in-out 0s infinite normal both running strokedash; }@keyframes fade-in { \n 0% { bottom: 10px; opacity: 0; }\n 100% { bottom: 20px; opacity: 1; }\n}@keyframes strokedash { \n 0% { stroke-dasharray: 0, 226; }\n 80%, 100% { stroke-dasharray: 659, 226; }\n}","isStyle":true,"id":64}],"id":63,"isShadow":true}],"id":39,"isShadowHost":true},{"type":2,"tagName":"next-route-announcer","attributes":{},"childNodes":[{"type":2,"tagName":"p","attributes":{"aria-live":"assertive","id":"__next-route-announcer__","role":"alert","style":"border: 0px; clip: rect(0px, 0px, 0px, 0px); height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap; overflow-wrap: normal;"},"childNodes":[],"id":66}],"id":65}],"id":21}],"id":3}],"id":1},"initialOffset":{"left":0,"top":0}},"timestamp":1682952380882},{"type":3,"data":{"source":1,"positions":[{"x":2027,"y":120,"id":22,"timeOffset":0}]},"timestamp":1682952383040},{"type":3,"data":{"source":2,"type":1,"id":3,"x":1618.84765625,"y":299.01953125},"timestamp":1682952383262},{"type":3,"data":{"source":2,"type":0,"id":3,"x":1618.84765625,"y":299.01953125},"timestamp":1682952383263},{"type":3,"data":{"source":2,"type":2,"id":3,"x":1618,"y":299,"pointerType":0},"timestamp":1682952383264},{"type":3,"data":{"source":1,"positions":[{"x":1618,"y":299,"id":3,"timeOffset":-435},{"x":1609,"y":296,"id":3,"timeOffset":-4}]},"timestamp":1682952383543},{"type":3,"data":{"source":1,"positions":[{"x":1239,"y":216,"id":23,"timeOffset":-460},{"x":847,"y":210,"id":23,"timeOffset":-409},{"x":788,"y":215,"id":23,"timeOffset":-142},{"x":754,"y":163,"id":32,"timeOffset":-77},{"x":735,"y":135,"id":27,"timeOffset":-25}]},"timestamp":1682952384050},{"type":3,"data":{"source":2,"type":1,"id":27,"x":729.30859375,"y":124.6875},"timestamp":1682952384230},{"type":3,"data":{"source":2,"type":5,"id":27},"timestamp":1682952384231},{"type":3,"data":{"source":2,"type":0,"id":27,"x":729.30859375,"y":124.5546875},"timestamp":1682952384310},{"type":3,"data":{"source":2,"type":2,"id":27,"x":729,"y":124,"pointerType":0},"timestamp":1682952384313},{"type":3,"data":{"source":2,"type":1,"id":27,"x":729.30859375,"y":124.0546875},"timestamp":1682952384447},{"type":3,"data":{"source":2,"type":0,"id":27,"x":729.30859375,"y":124.0546875},"timestamp":1682952384460},{"type":3,"data":{"source":2,"type":2,"id":27,"x":729,"y":124,"pointerType":0},"timestamp":1682952384463},{"type":3,"data":{"source":2,"type":4,"id":27,"x":729,"y":124},"timestamp":1682952384464},{"type":3,"data":{"source":1,"positions":[{"x":729,"y":125,"id":27,"timeOffset":-466},{"x":729,"y":125,"id":27,"timeOffset":-399},{"x":729,"y":124,"id":27,"timeOffset":-346},{"x":729,"y":124,"id":27,"timeOffset":-231}]},"timestamp":1682952384555},{"type":3,"data":{"source":2,"type":1,"id":27,"x":729.30859375,"y":124.0546875},"timestamp":1682952384559},{"type":3,"data":{"source":2,"type":0,"id":27,"x":729.30859375,"y":124.0546875},"timestamp":1682952384675},{"type":3,"data":{"source":2,"type":2,"id":27,"x":729,"y":124,"pointerType":0},"timestamp":1682952384676},{"type":3,"data":{"source":2,"type":1,"id":27,"x":729.30859375,"y":124.0546875},"timestamp":1682952384709},{"type":3,"data":{"source":2,"type":0,"id":27,"x":729.30859375,"y":124.0546875},"timestamp":1682952384810},{"type":3,"data":{"source":2,"type":2,"id":27,"x":729,"y":124,"pointerType":0},"timestamp":1682952384811},{"type":3,"data":{"source":1,"positions":[{"x":713,"y":137,"id":27,"timeOffset":-49}]},"timestamp":1682952385058},{"type":3,"data":{"source":1,"positions":[{"x":605,"y":266,"id":3,"timeOffset":-487}]},"timestamp":1682952385562},{"type":3,"data":{"source":2,"type":6,"id":27},"timestamp":1682952385719},{"type":3,"data":{"source":4,"width":2560,"height":476},"timestamp":1682952385738},{"type":3,"data":{"source":1,"positions":[{"x":604,"y":266,"id":3,"timeOffset":-22}]},"timestamp":1682952386063},{"type":3,"data":{"source":1,"positions":[{"x":453,"y":173,"id":22,"timeOffset":-475},{"x":265,"y":32,"id":22,"timeOffset":-418}]},"timestamp":1682952386571}]} +{"window_id":"187d7c77dfe1d45-08bdcaf91135a2-1d525634-384000-187d7c77dff39a6","data":[{"type":4,"data":{"href":"http://localhost:3000/","width":2560,"height":1304},"timestamp":1682952388104},{"type":2,"data":{"node":{"type":0,"childNodes":[{"type":1,"name":"html","publicId":"","systemId":"","id":2},{"type":2,"tagName":"html","attributes":{"lang":"en"},"childNodes":[{"type":2,"tagName":"head","attributes":{},"childNodes":[{"type":2,"tagName":"style","attributes":{"data-next-hide-fouc":"true"},"childNodes":[{"type":3,"textContent":"body { display: none; }","isStyle":true,"id":6}],"id":5},{"type":2,"tagName":"noscript","attributes":{"data-next-hide-fouc":"true"},"childNodes":[{"type":3,"textContent":"","id":8}],"id":7},{"type":2,"tagName":"meta","attributes":{"charset":"utf-8"},"childNodes":[],"id":9},{"type":2,"tagName":"title","attributes":{},"childNodes":[{"type":3,"textContent":"PostHog","id":11}],"id":10},{"type":2,"tagName":"meta","attributes":{"name":"viewport","content":"width=device-width, initial-scale=1"},"childNodes":[],"id":12},{"type":2,"tagName":"meta","attributes":{"name":"next-head-count","content":"3"},"childNodes":[],"id":13},{"type":2,"tagName":"noscript","attributes":{"data-n-css":""},"childNodes":[],"id":14},{"type":2,"tagName":"script","attributes":{"defer":"","nomodule":"","src":"http://localhost:3000/_next/static/chunks/polyfills.js?ts=1682952387901"},"childNodes":[],"id":15},{"type":2,"tagName":"script","attributes":{"src":"http://localhost:3000/_next/static/chunks/webpack.js?ts=1682952387901","defer":""},"childNodes":[],"id":16},{"type":2,"tagName":"script","attributes":{"src":"http://localhost:3000/_next/static/chunks/main.js?ts=1682952387901","defer":""},"childNodes":[],"id":17},{"type":2,"tagName":"script","attributes":{"src":"http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1682952387901","defer":""},"childNodes":[],"id":18},{"type":2,"tagName":"script","attributes":{"src":"http://localhost:3000/_next/static/chunks/pages/index.js?ts=1682952387901","defer":""},"childNodes":[],"id":19},{"type":2,"tagName":"script","attributes":{"src":"http://localhost:3000/_next/static/development/_buildManifest.js?ts=1682952387901","defer":""},"childNodes":[],"id":20},{"type":2,"tagName":"script","attributes":{"src":"http://localhost:3000/_next/static/development/_ssgManifest.js?ts=1682952387901","defer":""},"childNodes":[],"id":21},{"type":2,"tagName":"style","attributes":{},"childNodes":[{"type":3,"textContent":"main { margin: 0px auto; max-width: 1200px; padding: 2rem; font-family: helvetica, arial, sans-serif; }.buttons { display: flex; gap: 0.5rem; }","isStyle":true,"id":23}],"id":22},{"type":2,"tagName":"noscript","attributes":{"id":"__next_css__DO_NOT_USE__"},"childNodes":[],"id":24}],"id":4},{"type":2,"tagName":"body","attributes":{},"childNodes":[{"type":2,"tagName":"div","attributes":{"id":"__next"},"childNodes":[{"type":2,"tagName":"main","attributes":{},"childNodes":[{"type":2,"tagName":"h1","attributes":{},"childNodes":[{"type":3,"textContent":"PostHog React","id":29}],"id":28},{"type":2,"tagName":"div","attributes":{"class":"buttons"},"childNodes":[{"type":2,"tagName":"button","attributes":{},"childNodes":[{"type":3,"textContent":"Capture event","id":32}],"id":31},{"type":2,"tagName":"button","attributes":{"data-attr":"autocapture-button"},"childNodes":[{"type":3,"textContent":"Autocapture buttons","id":34}],"id":33},{"type":2,"tagName":"button","attributes":{"class":"ph-no-capture","rr_width":"0px","rr_height":"0px"},"childNodes":[],"id":35}],"id":30},{"type":2,"tagName":"p","attributes":{},"childNodes":[{"type":3,"textContent":"Feature flag response: ","id":37}],"id":36}],"id":27}],"id":26},{"type":2,"tagName":"script","attributes":{"type":"text/javascript","src":"http://localhost:8000/static/recorder-v2.js?v=1.53.1"},"childNodes":[],"id":38},{"type":2,"tagName":"script","attributes":{"src":"http://localhost:3000/_next/static/chunks/react-refresh.js?ts=1682952387901"},"childNodes":[],"id":39},{"type":2,"tagName":"script","attributes":{"id":"__NEXT_DATA__","type":"application/json"},"childNodes":[{"type":3,"textContent":"SCRIPT_PLACEHOLDER","id":41}],"id":40}],"id":25}],"id":3}],"id":1},"initialOffset":{"left":0,"top":0}},"timestamp":1682952388106},{"type":3,"data":{"source":0,"texts":[],"attributes":[],"removes":[{"parentId":4,"id":7},{"parentId":4,"id":5}],"adds":[]},"timestamp":1682952388108},{"type":3,"data":{"source":0,"texts":[],"attributes":[],"removes":[],"adds":[{"parentId":25,"nextId":null,"node":{"type":2,"tagName":"div","attributes":{"id":"__next-build-watcher","style":"position: fixed; bottom: 10px; right: 20px; width: 0px; height: 0px; z-index: 99999;"},"childNodes":[],"id":42,"isShadowHost":true}},{"parentId":42,"nextId":null,"node":{"type":2,"tagName":"style","attributes":{},"childNodes":[],"id":43,"isShadow":true}},{"parentId":43,"nextId":null,"node":{"type":3,"textContent":"#container { position: absolute; bottom: 10px; right: 30px; border-radius: 3px; background: rgb(0, 0, 0); color: rgb(255, 255, 255); font: initial; cursor: initial; letter-spacing: initial; text-shadow: initial; text-transform: initial; visibility: initial; padding: 7px 10px 8px; align-items: center; box-shadow: rgba(0, 0, 0, 0.25) 0px 11px 40px 0px, rgba(0, 0, 0, 0.12) 0px 2px 10px 0px; display: none; opacity: 0; transition: opacity 0.1s ease 0s, bottom 0.1s ease 0s; animation: 0.1s ease-in-out 0s 1 normal none running fade-in; }#container.visible { display: flex; }#container.building { bottom: 20px; opacity: 1; }#icon-wrapper { width: 16px; height: 16px; }#icon-wrapper > svg { width: 100%; height: 100%; }#icon-group { animation: 1s ease-in-out 0s infinite normal both running strokedash; }@keyframes fade-in { \\n 0% { bottom: 10px; opacity: 0; }\\n 100% { bottom: 20px; opacity: 1; }\\n}@keyframes strokedash { \\n 0% { stroke-dasharray: 0, 226; }\\n 80%, 100% { stroke-dasharray: 659, 226; }\\n}","isStyle":true,"id":44}},{"parentId":42,"nextId":43,"node":{"type":2,"tagName":"div","attributes":{"id":"container"},"childNodes":[],"id":45,"isShadow":true}},{"parentId":45,"nextId":null,"node":{"type":3,"textContent":"\\n ","id":46}},{"parentId":45,"nextId":46,"node":{"type":2,"tagName":"div","attributes":{"id":"icon-wrapper"},"childNodes":[],"id":47}},{"parentId":45,"nextId":47,"node":{"type":3,"textContent":"\\n ","id":48}},{"parentId":47,"nextId":null,"node":{"type":3,"textContent":"\\n ","id":49}},{"parentId":47,"nextId":49,"node":{"type":2,"tagName":"svg","attributes":{"viewBox":"0 0 226 200"},"childNodes":[],"isSVG":true,"id":50}},{"parentId":47,"nextId":50,"node":{"type":3,"textContent":"\\n ","id":51}},{"parentId":50,"nextId":null,"node":{"type":3,"textContent":"\\n ","id":52}},{"parentId":50,"nextId":52,"node":{"type":2,"tagName":"g","attributes":{"id":"icon-group","fill":"none","stroke":"url(#linear-gradient)","stroke-width":"18"},"childNodes":[],"isSVG":true,"id":53}},{"parentId":50,"nextId":53,"node":{"type":3,"textContent":"\\n ","id":54}},{"parentId":50,"nextId":54,"node":{"type":2,"tagName":"defs","attributes":{},"childNodes":[],"isSVG":true,"id":55}},{"parentId":50,"nextId":55,"node":{"type":3,"textContent":"\\n ","id":56}},{"parentId":55,"nextId":null,"node":{"type":3,"textContent":"\\n ","id":57}},{"parentId":55,"nextId":57,"node":{"type":2,"tagName":"lineargradient","attributes":{"x1":"114.720775%","y1":"181.283245%","x2":"39.5399306%","y2":"100%","id":"linear-gradient"},"childNodes":[],"isSVG":true,"id":58}},{"parentId":55,"nextId":58,"node":{"type":3,"textContent":"\\n ","id":59}},{"parentId":58,"nextId":null,"node":{"type":3,"textContent":"\\n ","id":60}},{"parentId":58,"nextId":60,"node":{"type":2,"tagName":"stop","attributes":{"stop-color":"#FFFFFF","offset":"100%"},"childNodes":[],"isSVG":true,"id":61}},{"parentId":58,"nextId":61,"node":{"type":3,"textContent":"\\n ","id":62}},{"parentId":58,"nextId":62,"node":{"type":2,"tagName":"stop","attributes":{"stop-color":"#000000","offset":"0%"},"childNodes":[],"isSVG":true,"id":63}},{"parentId":58,"nextId":63,"node":{"type":3,"textContent":"\\n ","id":64}},{"parentId":53,"nextId":null,"node":{"type":3,"textContent":"\\n ","id":65}},{"parentId":53,"nextId":65,"node":{"type":2,"tagName":"path","attributes":{"d":"M113,5.08219117 L4.28393801,197.5 L221.716062,197.5 L113,5.08219117 Z"},"childNodes":[],"isSVG":true,"id":66}},{"parentId":53,"nextId":66,"node":{"type":3,"textContent":"\\n ","id":67}}]},"timestamp":1682952388117},{"type":3,"data":{"source":0,"texts":[],"attributes":[],"removes":[{"parentId":10,"id":11},{"parentId":4,"id":12}],"adds":[{"parentId":10,"nextId":null,"node":{"type":3,"textContent":"PostHog","id":68}},{"parentId":4,"nextId":13,"node":{"type":2,"tagName":"meta","attributes":{"name":"viewport","content":"width=device-width, initial-scale=1"},"childNodes":[],"id":69}},{"parentId":25,"nextId":null,"node":{"type":2,"tagName":"next-route-announcer","attributes":{},"childNodes":[],"id":70}},{"parentId":70,"nextId":null,"node":{"type":2,"tagName":"p","attributes":{"aria-live":"assertive","id":"__next-route-announcer__","role":"alert","style":"border: 0px; clip: rect(0px, 0px, 0px, 0px); height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap; overflow-wrap: normal;"},"childNodes":[],"id":71}},{"parentId":36,"nextId":null,"node":{"type":3,"textContent":"false","id":72}}]},"timestamp":1682952388132},{"type":3,"data":{"source":1,"positions":[{"x":294,"y":7,"id":26,"timeOffset":0}]},"timestamp":1682952388659},{"type":3,"data":{"source":1,"positions":[{"x":577,"y":269,"id":3,"timeOffset":-438},{"x":684,"y":304,"id":3,"timeOffset":-239},{"x":762,"y":244,"id":3,"timeOffset":-174},{"x":815,"y":203,"id":27,"timeOffset":-123}]},"timestamp":1682952389163},{"type":3,"data":{"source":1,"positions":[{"x":819,"y":197,"id":27,"timeOffset":-427},{"x":831,"y":176,"id":27,"timeOffset":-362},{"x":842,"y":157,"id":36,"timeOffset":-312},{"x":850,"y":142,"id":27,"timeOffset":-261},{"x":852,"y":137,"id":33,"timeOffset":-176},{"x":852,"y":133,"id":33,"timeOffset":-111},{"x":852,"y":133,"id":33,"timeOffset":-28}]},"timestamp":1682952389668},{"type":3,"data":{"source":2,"type":1,"id":33,"x":852.7421875,"y":133.1640625},"timestamp":1682952389698},{"type":3,"data":{"source":2,"type":5,"id":33},"timestamp":1682952389699},{"type":3,"data":{"source":2,"type":0,"id":33,"x":852.7421875,"y":133.1640625},"timestamp":1682952389798},{"type":3,"data":{"source":2,"type":2,"id":33,"x":852,"y":133,"pointerType":0},"timestamp":1682952389798},{"type":3,"data":{"source":2,"type":1,"id":33,"x":852.7421875,"y":133.1640625},"timestamp":1682952389943},{"type":3,"data":{"source":2,"type":0,"id":33,"x":852.7421875,"y":133.1640625},"timestamp":1682952390043},{"type":3,"data":{"source":2,"type":2,"id":33,"x":852,"y":133,"pointerType":0},"timestamp":1682952390044},{"type":3,"data":{"source":2,"type":4,"id":33,"x":852,"y":133},"timestamp":1682952390047},{"type":3,"data":{"source":2,"type":1,"id":33,"x":852.7421875,"y":133.1640625},"timestamp":1682952390112},{"type":3,"data":{"source":2,"type":0,"id":33,"x":852.7421875,"y":133.1640625},"timestamp":1682952390243},{"type":3,"data":{"source":2,"type":2,"id":33,"x":852,"y":133,"pointerType":0},"timestamp":1682952390244},{"type":3,"data":{"source":2,"type":6,"id":33},"timestamp":1682952392745}]}' + +export const snapshotsAsJSONLines = (): string => `${lineOne}\n${lineTwo}\n` + +export const sortedRecordingSnapshots = (): { snapshot_data_by_window_id: Record } => { + const sortedRecordingSnapshotsJson = { snapshot_data_by_window_id: {} } + + snapshotsAsJSONLines() + .trim() + .split('\n') + .forEach((line) => { + const j = JSON.parse(line) + sortedRecordingSnapshotsJson.snapshot_data_by_window_id[j.window_id] = j.data + .map((jd: Record) => { + return { + windowId: j.window_id, + ...jd, + } + }) + .sort((a: any, b: any) => a.timestamp - b.timestamp) + }) + + return sortedRecordingSnapshotsJson +} diff --git a/frontend/src/scenes/session-recordings/player/playerMetaLogic.test.ts b/frontend/src/scenes/session-recordings/player/playerMetaLogic.test.ts index ccad721c9e713..f6c4b38c3f2b7 100644 --- a/frontend/src/scenes/session-recordings/player/playerMetaLogic.test.ts +++ b/frontend/src/scenes/session-recordings/player/playerMetaLogic.test.ts @@ -5,7 +5,7 @@ import { sessionRecordingPlayerLogic } from 'scenes/session-recordings/player/se import { playerMetaLogic } from 'scenes/session-recordings/player/playerMetaLogic' import recordingMetaJson from '../__mocks__/recording_meta.json' import recordingEventsJson from '../__mocks__/recording_events_query' -import recordingSnapshotsJson from '../__mocks__/recording_snapshots.json' +import { snapshotsAsJSONLines } from '../__mocks__/recording_snapshots' import { useMocks } from '~/mocks/jest' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' @@ -18,7 +18,8 @@ describe('playerMetaLogic', () => { useMocks({ get: { '/api/projects/:team/session_recordings/:id': recordingMetaJson, - '/api/projects/:team/session_recordings/:id/snapshots/': recordingSnapshotsJson, + '/api/projects/:team/session_recordings/:id/snapshots/': (_, res, ctx) => + res(ctx.text(snapshotsAsJSONLines())), }, post: { '/api/projects/:team/query': recordingEventsJson, diff --git a/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.test.ts b/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.test.ts index 287f4ea2bd2a7..e16cd03c9d67d 100644 --- a/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.test.ts +++ b/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.test.ts @@ -15,36 +15,10 @@ import { teamLogic } from 'scenes/teamLogic' import { userLogic } from 'scenes/userLogic' import { AvailableFeature } from '~/types' import { useAvailableFeatures } from '~/mocks/features' -import fs from 'fs' -import path from 'path' -// const createSnapshotEndpoint = (id: number): string => `api/projects/${MOCK_TEAM_ID}/session_recordings/${id}/snapshots` -// const EVENTS_SESSION_RECORDING_SNAPSHOTS_ENDPOINT_REGEX = new RegExp( -// `api/projects/${MOCK_TEAM_ID}/session_recordings/\\d/snapshots` -// ) -// read the jsonl file as a string -const jsonlPath = '../__mocks__/recording_snapshots.jsonl' -// read the file using a relative path -const recordingSnapshotsJson = fs.readFileSync(path.join(__dirname, jsonlPath), 'utf8') +import { snapshotsAsJSONLines, sortedRecordingSnapshots } from '../__mocks__/recording_snapshots' -const sortedRecordingSnapshotsJson = { - snapshot_data_by_window_id: {}, -} - -recordingSnapshotsJson - .trim() - .split('\n') - .forEach((line) => { - const j = JSON.parse(line) - sortedRecordingSnapshotsJson.snapshot_data_by_window_id[j.window_id] = j.data - .map((jd: Record) => { - return { - windowId: j.window_id, - ...jd, - } - }) - .sort((a: any, b: any) => a.timestamp - b.timestamp) - }) +const sortedRecordingSnapshotsJson = sortedRecordingSnapshots() describe('sessionRecordingDataLogic', () => { let logic: ReturnType @@ -56,7 +30,7 @@ describe('sessionRecordingDataLogic', () => { '/api/projects/:team/session_recordings/:id/snapshots': async (req, res, ctx) => { // with no sources, returns sources... if (req.url.searchParams.get('source') === 'blob') { - return res(ctx.text(recordingSnapshotsJson)) + return res(ctx.text(snapshotsAsJSONLines())) } // with no source requested should return sources return [ diff --git a/frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.test.ts b/frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.test.ts index 740d04a34d101..2598b4d82a149 100644 --- a/frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.test.ts +++ b/frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.test.ts @@ -5,7 +5,7 @@ import { eventUsageLogic } from 'lib/utils/eventUsageLogic' import { sessionRecordingDataLogic } from 'scenes/session-recordings/player/sessionRecordingDataLogic' import { playerSettingsLogic } from 'scenes/session-recordings/player/playerSettingsLogic' import { useMocks } from '~/mocks/jest' -import recordingSnapshotsJson from 'scenes/session-recordings/__mocks__/recording_snapshots.json' +import { snapshotsAsJSONLines } from 'scenes/session-recordings/__mocks__/recording_snapshots' import recordingMetaJson from 'scenes/session-recordings/__mocks__/recording_meta.json' import recordingEventsJson from 'scenes/session-recordings/__mocks__/recording_events_query' import { resumeKeaLoadersErrors, silenceKeaLoadersErrors } from '~/initKea' @@ -22,7 +22,26 @@ describe('sessionRecordingPlayerLogic', () => { beforeEach(() => { useMocks({ get: { - '/api/projects/:team/session_recordings/:id/snapshots': recordingSnapshotsJson, + '/api/projects/:team/session_recordings/:id/snapshots/': (req, res, ctx) => { + // with no sources, returns sources... + if (req.url.searchParams.get('source') === 'blob') { + return res(ctx.text(snapshotsAsJSONLines())) + } + // with no source requested should return sources + return [ + 200, + { + sources: [ + { + source: 'blob', + start_timestamp: '2023-08-11T12:03:36.097000Z', + end_timestamp: '2023-08-11T12:04:52.268000Z', + blob_key: '1691755416097-1691755492268', + }, + ], + }, + ] + }, '/api/projects/:team/session_recordings/:id': recordingMetaJson, }, delete: { @@ -81,6 +100,10 @@ describe('sessionRecordingPlayerLogic', () => { await expectLogic(logic).toDispatchActions([ sessionRecordingDataLogic({ sessionRecordingId: '2' }).actionTypes.loadRecordingSnapshots, + // once to gather sources + sessionRecordingDataLogic({ sessionRecordingId: '2' }).actionTypes.loadRecordingSnapshotsV2, + // once to load source from that + sessionRecordingDataLogic({ sessionRecordingId: '2' }).actionTypes.loadRecordingSnapshotsV2, sessionRecordingDataLogic({ sessionRecordingId: '2' }).actionTypes.loadRecordingSnapshotsSuccess, ]) diff --git a/frontend/src/scenes/session-recordings/player/utils/segmenter.test.ts b/frontend/src/scenes/session-recordings/player/utils/segmenter.test.ts index 60842a44bb268..33d05b4eae663 100644 --- a/frontend/src/scenes/session-recordings/player/utils/segmenter.test.ts +++ b/frontend/src/scenes/session-recordings/player/utils/segmenter.test.ts @@ -1,4 +1,4 @@ -import recordingSnapshotsJson from 'scenes/session-recordings/__mocks__/recording_snapshots.json' +import { sortedRecordingSnapshots } from 'scenes/session-recordings/__mocks__/recording_snapshots' import recordingMetaJson from 'scenes/session-recordings/__mocks__/recording_meta.json' import { createSegments } from './segmenter' import { convertSnapshotsResponse } from '../sessionRecordingDataLogic' @@ -7,7 +7,7 @@ import { RecordingSnapshot } from '~/types' describe('segmenter', () => { it('matches snapshots', async () => { - const snapshots = convertSnapshotsResponse(recordingSnapshotsJson.snapshot_data_by_window_id) + const snapshots = convertSnapshotsResponse(sortedRecordingSnapshots().snapshot_data_by_window_id) const segments = createSegments( snapshots, dayjs(recordingMetaJson.start_time), From 1ceb815ab4c142cc29681c7e3ebe9bcea813ec85 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Tue, 26 Sep 2023 14:43:09 +0100 Subject: [PATCH 27/41] fi --- ...sionsRecordings-player-success.stories.tsx | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/frontend/src/scenes/session-recordings/SessionsRecordings-player-success.stories.tsx b/frontend/src/scenes/session-recordings/SessionsRecordings-player-success.stories.tsx index b0e1fb71acd0f..6cb305b378de8 100644 --- a/frontend/src/scenes/session-recordings/SessionsRecordings-player-success.stories.tsx +++ b/frontend/src/scenes/session-recordings/SessionsRecordings-player-success.stories.tsx @@ -87,8 +87,26 @@ const meta: Meta = { return [200, { has_next: false, results: response, version: 1 }] }, // without the session-recording-blob-replay feature flag, we only load via ClickHouse - '/api/projects/:team/session_recordings/:id/snapshots': (_, res, ctx) => - res(ctx.text(snapshotsAsJSONLines())), + '/api/projects/:team/session_recordings/:id/snapshots': (req, res, ctx) => { + // with no sources, returns sources... + if (req.url.searchParams.get('source') === 'blob') { + return res(ctx.text(snapshotsAsJSONLines())) + } + // with no source requested should return sources + return [ + 200, + { + sources: [ + { + source: 'blob', + start_timestamp: '2023-08-11T12:03:36.097000Z', + end_timestamp: '2023-08-11T12:04:52.268000Z', + blob_key: '1691755416097-1691755492268', + }, + ], + }, + ] + }, '/api/projects/:team/session_recordings/:id': recordingMetaJson, 'api/projects/:team/notebooks': { count: 0, From a58ad16c2e183dff8bff763e3b5bb0b71234d486 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 13:52:32 +0000 Subject: [PATCH 28/41] Update UI snapshots for `chromium` (1) --- ...ordings-play-list-no-pinned-recordings.png | Bin 112682 -> 112096 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/frontend/__snapshots__/scenes-app-recordings--recordings-play-list-no-pinned-recordings.png b/frontend/__snapshots__/scenes-app-recordings--recordings-play-list-no-pinned-recordings.png index b79c4b316f02234f1a8fc4a14278d9a0436b145e..c6fbd48b974c5ed563bc8c00a0a32d35c691edbf 100644 GIT binary patch literal 112096 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

qmwIc!QM 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 CLWYR| literal 112682 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 {iPQ^^T5^T?Z!upf`ME7W8NZW7ScnQl(h-hv& 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 Date: Tue, 26 Sep 2023 14:05:20 +0000 Subject: [PATCH 29/41] Update UI snapshots for `chromium` (1) --- ...ordings-play-list-no-pinned-recordings.png | Bin 112096 -> 112676 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/frontend/__snapshots__/scenes-app-recordings--recordings-play-list-no-pinned-recordings.png b/frontend/__snapshots__/scenes-app-recordings--recordings-play-list-no-pinned-recordings.png index c6fbd48b974c5ed563bc8c00a0a32d35c691edbf..1ec338834227c63ce460ffa6a6fef86d2873f2ec 100644 GIT binary patch literal 112676 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%0A*rt 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 $jM<-Ok*U!1a7_+hB7 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 GfBrA$R{uf( literal 112096 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

qmwIc!QM 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 CLWYR| From ffd20cc9f8bcb19b1ba1a8016973efc9ab45e1b9 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Wed, 27 Sep 2023 13:49:07 +0100 Subject: [PATCH 30/41] first pass remove v1 snapshots --- ...sion_recording_list_from_replay_summary.py | 24 +--- .../queries/session_replay_events.py | 30 +++++ ...sion_recording_list_from_session_replay.py | 2 +- .../session_recording_api.py | 116 +++--------------- .../test/test_lts_session_recordings.py | 19 ++- .../test/test_session_recordings.py | 69 ++++++----- 6 files changed, 102 insertions(+), 158 deletions(-) diff --git a/posthog/session_recordings/queries/session_recording_list_from_replay_summary.py b/posthog/session_recordings/queries/session_recording_list_from_replay_summary.py index fea81ced5d0eb..23897496fac0c 100644 --- a/posthog/session_recordings/queries/session_recording_list_from_replay_summary.py +++ b/posthog/session_recordings/queries/session_recording_list_from_replay_summary.py @@ -3,22 +3,18 @@ from datetime import datetime, timedelta from typing import Any, Dict, List, Literal, NamedTuple, Tuple, Union -from django.conf import settings - from posthog.client import sync_execute -from posthog.cloud_utils import is_cloud -from posthog.constants import TREND_FILTER_TYPE_ACTIONS, AvailableFeature, PropertyOperatorType +from posthog.constants import TREND_FILTER_TYPE_ACTIONS, PropertyOperatorType from posthog.models import Entity from posthog.models.action.util import format_entity_filter from posthog.models.filters.mixins.utils import cached_property from posthog.models.filters.session_recordings_filter import SessionRecordingsFilter -from posthog.models.instance_setting import get_instance_setting from posthog.models.property import PropertyGroup from posthog.models.property.util import parse_prop_grouped_clauses from posthog.models.team import PersonOnEventsMode -from posthog.models.team.team import Team from posthog.queries.event_query import EventQuery from posthog.queries.util import PersonPropertiesMode +from posthog.session_recordings.queries.session_replay_events import ttl_days @dataclasses.dataclass(frozen=True) @@ -55,22 +51,6 @@ def _get_filter_by_provided_session_ids_clause( return f'AND "{column_name}" in %(session_ids)s', {"session_ids": recording_filters.session_ids} -def ttl_days(team: Team) -> int: - ttl_days = (get_instance_setting("RECORDINGS_TTL_WEEKS") or 3) * 7 - if is_cloud(): - # NOTE: We use Playlists as a proxy to see if they are subbed to Recordings - is_paid = team.organization.is_feature_available(AvailableFeature.RECORDINGS_PLAYLISTS) - ttl_days = settings.REPLAY_RETENTION_DAYS_MAX if is_paid else settings.REPLAY_RETENTION_DAYS_MIN - - # NOTE: The date we started reliably ingested data to blob storage - days_since_blob_ingestion = (datetime.now() - datetime(2023, 8, 1)).days - - if days_since_blob_ingestion < ttl_days: - ttl_days = days_since_blob_ingestion - - return ttl_days - - class PersonsQuery(EventQuery): _filter: SessionRecordingsFilter diff --git a/posthog/session_recordings/queries/session_replay_events.py b/posthog/session_recordings/queries/session_replay_events.py index 6521e9f39fdb2..83f3659473691 100644 --- a/posthog/session_recordings/queries/session_replay_events.py +++ b/posthog/session_recordings/queries/session_replay_events.py @@ -1,7 +1,12 @@ from datetime import datetime from typing import Optional, Tuple, List +from django.conf import settings + from posthog.clickhouse.client import sync_execute +from posthog.cloud_utils import is_cloud +from posthog.constants import AvailableFeature +from posthog.models.instance_setting import get_instance_setting from posthog.models.team import Team from posthog.session_recordings.models.metadata import ( RecordingMetadata, @@ -9,6 +14,15 @@ class SessionReplayEvents: + def exists(self, session_id: str, team: Team) -> bool: + # TODO we could cache this result when its result is True. + # Once we know that session exists we don't need to check again (until the end of the day since TTL might apply) + result = sync_execute( + "SELECT count(1) FROM session_replay_events WHERE team_id = %(team_id)s AND session_id = %(session_id)s AND min_first_timestamp >= now() - INTERVAL %(recording_ttl_days)s DAY", + {"team_id": team.pk, "session_id": session_id, "recording_ttl_days": ttl_days(team)}, + ) + return result[0][0] > 0 + def get_metadata( self, session_id: str, team: Team, recording_start_time: Optional[datetime] = None ) -> Optional[RecordingMetadata]: @@ -66,3 +80,19 @@ def get_metadata( console_warn_count=replay[10], console_error_count=replay[11], ) + + +def ttl_days(team: Team) -> int: + ttl_days = (get_instance_setting("RECORDINGS_TTL_WEEKS") or 3) * 7 + if is_cloud(): + # NOTE: We use Playlists as a proxy to see if they are subbed to Recordings + is_paid = team.organization.is_feature_available(AvailableFeature.RECORDINGS_PLAYLISTS) + ttl_days = settings.REPLAY_RETENTION_DAYS_MAX if is_paid else settings.REPLAY_RETENTION_DAYS_MIN + + # NOTE: The date we started reliably ingested data to blob storage + days_since_blob_ingestion = (datetime.now() - datetime(2023, 8, 1)).days + + if days_since_blob_ingestion < ttl_days: + ttl_days = days_since_blob_ingestion + + return ttl_days diff --git a/posthog/session_recordings/queries/test/test_session_recording_list_from_session_replay.py b/posthog/session_recordings/queries/test/test_session_recording_list_from_session_replay.py index 6a529313a3851..c35a26359ff18 100644 --- a/posthog/session_recordings/queries/test/test_session_recording_list_from_session_replay.py +++ b/posthog/session_recordings/queries/test/test_session_recording_list_from_session_replay.py @@ -16,8 +16,8 @@ from posthog.models.team import Team from posthog.session_recordings.queries.session_recording_list_from_replay_summary import ( SessionRecordingListFromReplaySummary, - ttl_days, ) +from posthog.session_recordings.queries.session_replay_events import ttl_days from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary from posthog.test.base import ( APIBaseTest, diff --git a/posthog/session_recordings/session_recording_api.py b/posthog/session_recordings/session_recording_api.py index cf3505c556752..eacc774366fe2 100644 --- a/posthog/session_recordings/session_recording_api.py +++ b/posthog/session_recordings/session_recording_api.py @@ -11,18 +11,16 @@ from django.http import JsonResponse, HttpResponse from drf_spectacular.utils import extend_schema from loginas.utils import is_impersonated_session -from rest_framework import exceptions, request, serializers, viewsets, status +from rest_framework import exceptions, request, serializers, viewsets from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated -from rest_framework.renderers import JSONRenderer from rest_framework.response import Response -from sentry_sdk import capture_exception from posthog.api.person import PersonSerializer from posthog.api.routing import StructuredViewSetMixin from posthog.auth import SharingAccessTokenAuthentication from posthog.constants import SESSION_RECORDINGS_FILTER_IDS -from posthog.models import Filter, User +from posthog.models import User from posthog.models.filters.session_recordings_filter import SessionRecordingsFilter from posthog.models.person.person import PersonDistinctId from posthog.session_recordings.models.session_recording import SessionRecording @@ -39,14 +37,12 @@ ) from posthog.session_recordings.queries.session_recording_properties import SessionRecordingProperties from posthog.rate_limit import ClickHouseBurstRateThrottle, ClickHouseSustainedRateThrottle +from posthog.session_recordings.queries.session_replay_events import SessionReplayEvents from posthog.session_recordings.realtime_snapshots import get_realtime_snapshots from posthog.session_recordings.snapshots.convert_legacy_snapshots import convert_original_version_lts_recording from posthog.storage import object_storage -from posthog.utils import format_query_params_absolute_url from prometheus_client import Counter -DEFAULT_RECORDING_CHUNK_LIMIT = 20 # Should be tuned to find the best value - SNAPSHOT_SOURCE_REQUESTED = Counter( "session_snapshots_requested_counter", "When calling the API and providing a concrete snapshot type to load.", @@ -54,20 +50,6 @@ ) -def snapshots_response(data: Any) -> Any: - # NOTE: We have seen some issues with encoding of emojis, specifically when there is a lone "surrogate pair". See #13272 for more details - # The Django JsonResponse handles this case, but the DRF Response does not. So we fall back to the Django JsonResponse if we encounter an error - try: - JSONRenderer().render(data=data) - except Exception: - capture_exception( - Exception("DRF Json encoding failed, falling back to Django JsonResponse"), {"response_data": data} - ) - return JsonResponse(data) - - return Response(data) - - class SessionRecordingSerializer(serializers.ModelSerializer): id = serializers.CharField(source="session_id", read_only=True) recording_duration = serializers.IntegerField(source="duration", read_only=True) @@ -246,13 +228,25 @@ def destroy(self, request: request.Request, *args: Any, **kwargs: Any) -> Respon return Response({"success": True}, status=204) - def _snapshots_v2(self, request: request.Request): + @action(methods=["GET"], detail=True) + def snapshots(self, request: request.Request, **kwargs): """ - This will eventually replace the snapshots endpoint below. - This path only supports loading from S3 or Redis based on query params + Snapshots can be loaded from multiple places: + 1. From S3 if the session is older than our ingestion limit. This will be multiple files that can be streamed to the client + 2. or from Redis if the session is newer than our ingestion limit. + + Clients need to call this API twice. + First without a source parameter to get a list of sources supported by the given session. + And then once for each source in the returned list to get the actual snapshots. + + NB version 1 of this API has been deprecated and ClickHouse stored snapshots are no longer supported. """ recording = self.get_object() + + if not SessionReplayEvents().exists(session_id=str(recording.session_id), team=self.team): + raise exceptions.NotFound("Recording not found") + response_data = {} source = request.GET.get("source") might_have_realtime = True @@ -381,80 +375,6 @@ def _snapshots_v2(self, request: request.Request): return Response(serializer.data) - @action(methods=["GET"], detail=True) - def snapshots(self, request: request.Request, **kwargs): - """ - Snapshots can be loaded from multiple places: - 1. From S3 if the session is older than our ingestion limit. This will be multiple files that can be streamed to the client - 2. From Redis if the session is newer than our ingestion limit. - 3. From Clickhouse whilst we are migrating to the new ingestion method - - NB calling this API without `version=2` in the query params or with no version is deprecated and will be removed in the future - """ - - if request.GET.get("version") == "2": - return self._snapshots_v2(request) - - recording = self.get_object() - - # TODO: Determine if we should try Redis or not based on the recording start time and the S3 responses - - if recording.deleted: - raise exceptions.NotFound("Recording not found") - - if recording.storage_version: - # we're only expected recordings with no snapshot version here - # but a bad assumption about when we could create recordings with a snapshot version - # of 2023-08-01 means we need to "force upgrade" these requests to version 2 of the API - # so, we issue a temporary redirect to the same URL request but with version 2 in the query params - params = request.GET.copy() - params["version"] = "2" - return Response(status=status.HTTP_302_FOUND, headers={"Location": f"{request.path}?{params.urlencode()}"}) - - # TODO: Why do we use a Filter? Just swap to norma, offset, limit pagination - filter = Filter(request=request) - limit = filter.limit if filter.limit else DEFAULT_RECORDING_CHUNK_LIMIT - offset = filter.offset if filter.offset else 0 - - event_properties = {"team_id": self.team.pk, "session_being_loaded": recording.session_id, "offset": offset} - - if request.headers.get("X-POSTHOG-SESSION-ID"): - event_properties["$session_id"] = request.headers["X-POSTHOG-SESSION-ID"] - - posthoganalytics.capture( - self._distinct_id_from_request(request), "v1 session recording snapshots viewed", event_properties - ) - - # Optimisation step if passed to speed up retrieval of CH data - if not recording.start_time: - recording_start_time = ( - parser.parse(request.GET["recording_start_time"]) if request.GET.get("recording_start_time") else None - ) - recording.start_time = recording_start_time - - try: - recording.load_snapshots(limit, offset) - except NotImplementedError as e: - capture_exception(e) - raise exceptions.NotFound("Storage version 2023-08-01 can only be accessed via V2 of this endpoint") - - if offset == 0: - if not recording.snapshot_data_by_window_id: - raise exceptions.NotFound("Snapshots not found") - - if recording.can_load_more_snapshots: - next_url = format_query_params_absolute_url(request, offset + limit, limit) if True else None - else: - next_url = None - - res = { - "storage": recording.storage, - "next": next_url, - "snapshot_data_by_window_id": recording.snapshot_data_by_window_id, - } - - return snapshots_response(res) - @staticmethod def _distinct_id_from_request(request): if isinstance(request.user, AnonymousUser): diff --git a/posthog/session_recordings/test/test_lts_session_recordings.py b/posthog/session_recordings/test/test_lts_session_recordings.py index 57cd3e8cba18d..b16d873b93d7b 100644 --- a/posthog/session_recordings/test/test_lts_session_recordings.py +++ b/posthog/session_recordings/test/test_lts_session_recordings.py @@ -19,8 +19,11 @@ def setUp(self): # Create a new team each time to ensure no clashing between tests self.team = Team.objects.create(organization=self.organization, name="New Team") + @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) @patch("posthog.session_recordings.session_recording_api.object_storage.list_objects") - def test_2023_08_01_version_stored_snapshots_can_be_gathered(self, mock_list_objects: MagicMock) -> None: + def test_2023_08_01_version_stored_snapshots_can_be_gathered( + self, mock_list_objects: MagicMock, _mock_exists: MagicMock + ) -> None: session_id = str(uuid.uuid4()) lts_storage_path = "purposefully/not/what/we/would/calculate/to/prove/this/is/used" @@ -69,8 +72,11 @@ def list_objects_func(path: str) -> List[str]: ], } + @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) @patch("posthog.session_recordings.session_recording_api.object_storage.list_objects") - def test_original_version_stored_snapshots_can_be_gathered(self, mock_list_objects: MagicMock) -> None: + def test_original_version_stored_snapshots_can_be_gathered( + self, mock_list_objects: MagicMock, _mock_exists: MagicMock + ) -> None: session_id = str(uuid.uuid4()) lts_storage_path = "purposefully/not/what/we/would/calculate/to/prove/this/is/used" @@ -106,11 +112,16 @@ def list_objects_func(path: str) -> List[str]: ], } + @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) @patch("posthog.session_recordings.session_recording_api.requests.get") @patch("posthog.session_recordings.session_recording_api.object_storage.get_presigned_url") @patch("posthog.session_recordings.session_recording_api.object_storage.list_objects") def test_2023_08_01_version_stored_snapshots_can_be_loaded( - self, mock_list_objects: MagicMock, mock_get_presigned_url: MagicMock, mock_requests: MagicMock + self, + mock_list_objects: MagicMock, + mock_get_presigned_url: MagicMock, + mock_requests: MagicMock, + _mock_exists: MagicMock, ) -> None: session_id = str(uuid.uuid4()) lts_storage_path = "purposefully/not/what/we/would/calculate/to/prove/this/is/used" @@ -162,6 +173,7 @@ def list_objects_func(path: str) -> List[str]: assert response_data == "the file contents" + @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) @patch("posthog.session_recordings.session_recording_api.requests.get") @patch("posthog.session_recordings.session_recording_api.object_storage.tag") @patch("posthog.session_recordings.session_recording_api.object_storage.write") @@ -176,6 +188,7 @@ def test_original_version_stored_snapshots_can_be_loaded_without_upversion( mock_write: MagicMock, mock_tag: MagicMock, mock_requests: MagicMock, + _mock_exists: MagicMock, ) -> None: session_id = str(uuid.uuid4()) lts_storage_path = "purposefully/not/what/we/would/calculate/to/prove/this/is/used" diff --git a/posthog/session_recordings/test/test_session_recordings.py b/posthog/session_recordings/test/test_session_recordings.py index 14820ba9df997..20603ba1eb8e3 100644 --- a/posthog/session_recordings/test/test_session_recordings.py +++ b/posthog/session_recordings/test/test_session_recordings.py @@ -36,6 +36,7 @@ def setUp(self): super().setUp() # Create a new team each time to ensure no clashing between tests + # TODO this is pretty slow, we should change assertions so that we don't need it self.team = Team.objects.create(organization=self.organization, name="New Team") def create_snapshot( @@ -261,14 +262,20 @@ def test_viewed_state_of_session_recording_version_3(self): team=self.team, distinct_ids=["u1"], properties={"$some_prop": "something", "email": "bob@bob.com"} ) base_time = (now() - timedelta(days=1)).replace(microsecond=0) - SessionRecordingViewed.objects.create(team=self.team, user=self.user, session_id="1") - self.create_snapshot("u1", "1", base_time) - self.create_snapshot("u1", "2", base_time + relativedelta(seconds=30)) + session_id_one = "1" + session_id_two = "2" + + SessionRecordingViewed.objects.create(team=self.team, user=self.user, session_id=session_id_one) + self.create_snapshot("u1", session_id_one, base_time) + self.create_snapshot("u1", session_id_two, base_time + relativedelta(seconds=30)) response = self.client.get(f"/api/projects/{self.team.id}/session_recordings") response_data = response.json() - assert [(r["id"], r["viewed"]) for r in response_data["results"]] == [("2", False), ("1", True)] + assert [(r["id"], r["viewed"]) for r in response_data["results"]] == [ + (session_id_two, False), + (session_id_one, True), + ] def test_setting_viewed_state_of_session_recording(self): Person.objects.create( @@ -376,7 +383,7 @@ def test_single_session_recording_doesnt_leak_teams(self): self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) response = self.client.get(f"/api/projects/{self.team.id}/session_recordings/id_no_team_leaking/snapshots") - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND, response.json()) def test_session_recording_with_no_person(self): produce_replay_summary( @@ -458,8 +465,9 @@ def test_delete_session_recording(self): # New snapshot loading method @freeze_time("2023-01-01T00:00:00Z") + @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) @patch("posthog.session_recordings.session_recording_api.object_storage.list_objects") - def test_get_snapshots_v2_default_response(self, mock_list_objects) -> None: + def test_get_snapshots_v2_default_response(self, mock_list_objects: MagicMock, _mock_exists: MagicMock) -> None: session_id = str(uuid.uuid4()) timestamp = round(now().timestamp() * 1000) mock_list_objects.return_value = [ @@ -494,33 +502,9 @@ def test_get_snapshots_v2_default_response(self, mock_list_objects) -> None: mock_list_objects.assert_called_with(f"session_recordings/team_id/{self.team.pk}/session_id/{session_id}/data") @freeze_time("2023-01-01T00:00:00Z") + @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) @patch("posthog.session_recordings.session_recording_api.object_storage.list_objects") - def test_get_snapshots_upgrade_to_v2_if_stored_recording_requires_it(self, mock_list_objects: MagicMock) -> None: - session_id = str(uuid.uuid4()) - timestamp = round(now().timestamp() * 1000) - mock_list_objects.return_value = [ - f"session_recordings/team_id/{self.team.pk}/session_id/{session_id}/data/{timestamp - 10000}-{timestamp - 5000}", - f"session_recordings/team_id/{self.team.pk}/session_id/{session_id}/data/{timestamp - 5000}-{timestamp}", - ] - - # if the recording has been written with a newer version, we have to upgrade to v2 - SessionRecording.objects.create(team=self.team, session_id=session_id, storage_version="2023-08-01") - - # add an unnecessary param to make sure we maintain params when redirecting - response = self.client.get( - f"/api/projects/{self.team.id}/session_recordings/{session_id}/snapshots?some-param=1" - ) - assert response.status_code == status.HTTP_302_FOUND - assert ( - response.headers["Location"] - == f"/api/projects/{self.team.id}/session_recordings/{session_id}/snapshots?some-param=1&version=2" - ) - - mock_list_objects.assert_not_called() - - @freeze_time("2023-01-01T00:00:00Z") - @patch("posthog.session_recordings.session_recording_api.object_storage.list_objects") - def test_get_snapshots_v2_from_lts(self, mock_list_objects: MagicMock) -> None: + def test_get_snapshots_v2_from_lts(self, mock_list_objects: MagicMock, _mock_exists: MagicMock) -> None: session_id = str(uuid.uuid4()) timestamp = round(now().timestamp() * 1000) @@ -546,6 +530,7 @@ def list_objects_func(path: str) -> List[str]: mock_list_objects.side_effect = list_objects_func response = self.client.get(f"/api/projects/{self.team.id}/session_recordings/{session_id}/snapshots?version=2") + assert response.status_code == 200 response_data = response.json() assert response_data == { @@ -575,8 +560,9 @@ def list_objects_func(path: str) -> List[str]: ] @freeze_time("2023-01-01T00:00:00Z") + @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) @patch("posthog.session_recordings.session_recording_api.object_storage.list_objects") - def test_get_snapshots_v2_default_response_no_realtime_if_old(self, mock_list_objects) -> None: + def test_get_snapshots_v2_default_response_no_realtime_if_old(self, mock_list_objects, _mock_exists) -> None: session_id = str(uuid.uuid4()) old_timestamp = round((now() - timedelta(hours=26)).timestamp() * 1000) @@ -597,11 +583,12 @@ def test_get_snapshots_v2_default_response_no_realtime_if_old(self, mock_list_ob ] } + @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) @patch("posthog.session_recordings.session_recording_api.SessionRecording.get_or_build") @patch("posthog.session_recordings.session_recording_api.object_storage.get_presigned_url") @patch("posthog.session_recordings.session_recording_api.requests") def test_can_get_session_recording_blob( - self, _mock_requests, mock_presigned_url, mock_get_session_recording + self, _mock_requests, mock_presigned_url, mock_get_session_recording, _mock_exists ) -> None: session_id = str(uuid.uuid4()) """API will add session_recordings/team_id/{self.team.pk}/session_id/{session_id}""" @@ -696,6 +683,14 @@ def test_get_via_sharing_token(self, mock_copy_objects: MagicMock) -> None: "end_time": "2022-12-31T12:00:00Z", } + # now create a snapshot record that doesn't have a fixed date, as it needs to be within TTL for the request below to complete + self.create_snapshot( + "user", + session_id, + now(), + team_id=self.team.pk, + ) + response = self.client.get( f"/api/projects/{self.team.id}/session_recordings/{session_id}/snapshots?sharing_access_token={token}&version=2" ) @@ -789,3 +784,9 @@ def test_get_matching_events(self) -> None: assert response.status_code == status.HTTP_200_OK assert response.json() == {"results": [event_id]} + + def test_404_when_no_snapshots(self) -> None: + response = self.client.get( + f"/api/projects/{self.team.id}/session_recordings/1/snapshots?version=2", + ) + assert response.status_code == status.HTTP_404_NOT_FOUND From f25a80715c25503d189cfb91a76f9464c31ceb49 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Wed, 27 Sep 2023 14:26:55 +0100 Subject: [PATCH 31/41] delete stuff --- posthog/session_recordings/models/metadata.py | 11 +-- .../models/session_recording.py | 50 ----------- .../queries/session_recording_properties.py | 5 -- .../queries/session_replay_events.py | 8 +- .../test/test_session_recording_list.py | 0 .../session_recording_api.py | 2 - .../session_recording_helpers.py | 60 +------------ .../test}/test_session_recording_helpers.py | 87 ------------------- .../test/test_session_recordings.py | 3 +- 9 files changed, 13 insertions(+), 213 deletions(-) delete mode 100644 posthog/session_recordings/queries/test/test_session_recording_list.py rename posthog/{helpers/tests => session_recordings/test}/test_session_recording_helpers.py (78%) diff --git a/posthog/session_recordings/models/metadata.py b/posthog/session_recordings/models/metadata.py index 0f1e2e5a3731c..98359a09f30fe 100644 --- a/posthog/session_recordings/models/metadata.py +++ b/posthog/session_recordings/models/metadata.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Any, Dict, List, Optional, TypedDict, Union +from typing import Dict, List, Optional, TypedDict, Union SnapshotData = Dict WindowId = Optional[str] @@ -25,15 +25,6 @@ class SessionRecordingEventSummary(TypedDict): data: Dict[str, Union[int, str]] -class SessionRecordingEvent(TypedDict): - timestamp: datetime - distinct_id: str - session_id: str - window_id: str - snapshot_data: Dict[str, Any] - events_summary: List[SessionRecordingEventSummary] - - # NOTE: MatchingSessionRecordingEvent is a minimal version of full events that is used to display events matching a filter on the frontend class MatchingSessionRecordingEvent(TypedDict): uuid: str diff --git a/posthog/session_recordings/models/session_recording.py b/posthog/session_recordings/models/session_recording.py index ed7be73c2c208..c25c8ff611598 100644 --- a/posthog/session_recordings/models/session_recording.py +++ b/posthog/session_recordings/models/session_recording.py @@ -10,7 +10,6 @@ from posthog.models.team.team import Team from posthog.models.utils import UUIDModel from posthog.session_recordings.models.metadata import ( - DecompressedRecordingData, RecordingMatchingEvents, RecordingMetadata, ) @@ -63,7 +62,6 @@ class Meta: # Metadata can be loaded from Clickhouse or S3 _metadata: Optional[RecordingMetadata] = None - _snapshots: Optional[DecompressedRecordingData] = None def load_metadata(self) -> bool: if self._metadata: @@ -97,54 +95,6 @@ def load_metadata(self) -> bool: return True - def load_snapshots(self, limit=20, offset=0) -> None: - if self._snapshots: - return - - if self.object_storage_path: - self.load_object_data() - else: - # TODO this can be removed - raise NotImplementedError("Clickhouse backed snapshots are not supported") - - def load_object_data(self) -> None: - """ - This is only called in the to-be deprecated v1 of session recordings snapshot API - """ - try: - from ee.session_recordings.session_recording_extensions import load_persisted_recording - except ImportError: - load_persisted_recording = lambda *args: None - - data = load_persisted_recording(self) - - if not data: - return - - if data.get("version", None) == "2022-12-22": - self._snapshots = { - "has_next": False, - "snapshot_data_by_window_id": data["snapshot_data_by_window_id"], - } - elif data.get("version", None) == "2023-08-01": - raise NotImplementedError("Storage version 2023-08-01 will never be supported in this code path") - else: - # unknown version - return - - # S3 / Clickhouse backed fields - @property - def snapshot_data_by_window_id(self): - return self._snapshots["snapshot_data_by_window_id"] if self._snapshots else None - - @property - def can_load_more_snapshots(self): - return self._snapshots["has_next"] if self._snapshots else False - - @property - def storage(self): - return "object_storage_lts" if self.object_storage_path else "clickhouse" - def load_person(self) -> Optional[Person]: if self.person: return self.person diff --git a/posthog/session_recordings/queries/session_recording_properties.py b/posthog/session_recordings/queries/session_recording_properties.py index 3556af444ed78..49b42f8bfa98f 100644 --- a/posthog/session_recordings/queries/session_recording_properties.py +++ b/posthog/session_recordings/queries/session_recording_properties.py @@ -17,11 +17,6 @@ class EventFiltersSQL(NamedTuple): params: Dict[str, Any] -class SessionRecordingQueryResult(NamedTuple): - results: List - has_more_recording: bool - - class SessionRecordingProperties(EventQuery): _filter: SessionRecordingsFilter _session_ids: List[str] diff --git a/posthog/session_recordings/queries/session_replay_events.py b/posthog/session_recordings/queries/session_replay_events.py index 83f3659473691..02c2a26519c21 100644 --- a/posthog/session_recordings/queries/session_replay_events.py +++ b/posthog/session_recordings/queries/session_replay_events.py @@ -18,7 +18,13 @@ def exists(self, session_id: str, team: Team) -> bool: # TODO we could cache this result when its result is True. # Once we know that session exists we don't need to check again (until the end of the day since TTL might apply) result = sync_execute( - "SELECT count(1) FROM session_replay_events WHERE team_id = %(team_id)s AND session_id = %(session_id)s AND min_first_timestamp >= now() - INTERVAL %(recording_ttl_days)s DAY", + """ + SELECT count(1) + FROM session_replay_events + WHERE team_id = %(team_id)s + AND session_id = %(session_id)s + AND min_first_timestamp >= now() - INTERVAL %(recording_ttl_days)s DAY + """, {"team_id": team.pk, "session_id": session_id, "recording_ttl_days": ttl_days(team)}, ) return result[0][0] > 0 diff --git a/posthog/session_recordings/queries/test/test_session_recording_list.py b/posthog/session_recordings/queries/test/test_session_recording_list.py deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/posthog/session_recordings/session_recording_api.py b/posthog/session_recordings/session_recording_api.py index eacc774366fe2..c610f04a91950 100644 --- a/posthog/session_recordings/session_recording_api.py +++ b/posthog/session_recordings/session_recording_api.py @@ -74,7 +74,6 @@ class Meta: "console_error_count", "start_url", "person", - "storage", "pinned_count", ] @@ -94,7 +93,6 @@ class Meta: "console_warn_count", "console_error_count", "start_url", - "storage", "pinned_count", ] diff --git a/posthog/session_recordings/session_recording_helpers.py b/posthog/session_recordings/session_recording_helpers.py index e84cab58cfdb0..0cdff5642f4fe 100644 --- a/posthog/session_recordings/session_recording_helpers.py +++ b/posthog/session_recordings/session_recording_helpers.py @@ -5,12 +5,11 @@ from datetime import datetime, timezone from typing import Any, Callable, Dict, Generator, List, Tuple -from dateutil.parser import ParserError, parse +from dateutil.parser import parse from sentry_sdk.api import capture_exception from posthog.session_recordings.models.metadata import ( SessionRecordingEventSummary, - SnapshotData, ) from posthog.utils import flatten @@ -215,11 +214,6 @@ def _process_windowed_events( return result -def chunk_string(string: str, chunk_length: int) -> List[str]: - """Split a string into chunk_length-sized elements. Reversal operation: `''.join()`.""" - return [string[0 + offset : chunk_length + offset] for offset in range(0, len(string), chunk_length)] - - def is_unprocessed_snapshot_event(event: Dict) -> bool: try: is_snapshot = event["event"] == "$snapshot" @@ -234,6 +228,8 @@ def is_unprocessed_snapshot_event(event: Dict) -> bool: raise ValueError('$snapshot events must contain property "$snapshot_data"!') +# this is kept around as we upgrade older recordings in long term storage on demand. +# TODO: remove this once all recordings are upgraded def decompress(base64data: str) -> str: compressed_bytes = base64.b64decode(base64data) return gzip.decompress(compressed_bytes).decode("utf-16", "surrogatepass") @@ -264,55 +260,5 @@ def convert_to_timestamp(source: str) -> int: return int(parse(source).timestamp() * 1000) -def get_events_summary_from_snapshot_data( - snapshot_data: List[SnapshotData | None], -) -> List[SessionRecordingEventSummary]: - """ - Extract a minimal representation of the snapshot data events for easier querying. - 'data' and 'data.payload' values are included as long as they are strings or numbers - and in the inclusion list to keep the payload minimal - """ - events_summary = [] - - for event in snapshot_data: - if not event or "timestamp" not in event or "type" not in event: - continue - - # Get all top level data values - data = { - key: value - for key, value in event.get("data", {}).items() - if type(value) in [str, int] and key in EVENT_SUMMARY_DATA_INCLUSIONS - } - # Some events have a payload, some values of which we want - if event.get("data", {}).get("payload"): - # Make sure the payload is a dict before we access it - if isinstance(event["data"]["payload"], dict): - data["payload"] = { - key: value - for key, value in event["data"]["payload"].items() - if type(value) in [str, int] and f"payload.{key}" in EVENT_SUMMARY_DATA_INCLUSIONS - } - - # noinspection PyBroadException - try: - events_summary.append( - SessionRecordingEventSummary( - timestamp=int(event["timestamp"]) - if isinstance(event["timestamp"], (int, float)) - else convert_to_timestamp(event["timestamp"]), - type=event["type"], - data=data, - ) - ) - except ParserError: - capture_exception() - - # No guarantees are made about order so, we sort here to be sure - events_summary.sort(key=lambda x: x["timestamp"]) - - return events_summary - - def byte_size_dict(x: Dict | List) -> int: return len(json.dumps(x)) diff --git a/posthog/helpers/tests/test_session_recording_helpers.py b/posthog/session_recordings/test/test_session_recording_helpers.py similarity index 78% rename from posthog/helpers/tests/test_session_recording_helpers.py rename to posthog/session_recordings/test/test_session_recording_helpers.py index 806f749c28537..6c64d84efaf78 100644 --- a/posthog/helpers/tests/test_session_recording_helpers.py +++ b/posthog/session_recordings/test/test_session_recording_helpers.py @@ -11,8 +11,6 @@ from posthog.session_recordings.session_recording_helpers import ( RRWEB_MAP_EVENT_TYPE, SessionRecordingEventSummary, - SnapshotData, - get_events_summary_from_snapshot_data, is_active_event, preprocess_replay_events_for_blob_ingestion, split_replay_events, @@ -46,91 +44,6 @@ def test_preprocess_with_no_recordings(): assert mock_capture_flow(events)[0] == events -def test_get_events_summary_from_snapshot_data(): - timestamp = round(datetime.now().timestamp() * 1000) - - snapshot_events: List[SnapshotData | None] = [ - # ignore malformed events - {"type": 2, "foo": "bar"}, - # ignore other props - {"type": 2, "timestamp": timestamp, "foo": "bar"}, - # include standard properties - {"type": 1, "timestamp": timestamp, "data": {"source": 3}}, - # Payload as list when we expect a dict - {"type": 1, "timestamp": timestamp, "data": {"source": 3, "payload": [1, 2, 3]}}, - # include only allowed values - { - "type": 1, - "timestamp": timestamp, - "data": { - # Large values we dont want - "node": {}, - "text": "long-useless-text", - # Standard core values we want - "source": 3, - "type": 1, - # Values for initial render meta event - "href": "https://app.posthog.com/events?foo=bar", - "width": 2056, - "height": 1120, - # Special case for custom pageview events - "tag": "$pageview", - "plugin": "rrweb/console@1", - "payload": { - "href": "https://app.posthog.com/events?eventFilter=", # from pageview - "level": "log", # from console plugin - # random - "dont-want": "this", - "or-this": {"foo": "bar"}, - }, - }, - }, - # payload has iso string timestamp instead of number and is out of order by timestamp sort - # in https://posthog.sentry.io/issues/4089255349/?project=1899813&referrer=slack we saw a client - # send this event, which caused the backend sorting to fail because we treat the rrweb timestamp - # as if it is always a number - { - "type": 1, - "timestamp": "1987-04-28T17:17:17.590Z", - "data": {"source": 3}, - }, - # safely ignore string timestamps that aren't timestamps - { - "type": 1, - "timestamp": "it was about a hundred years ago, that I remember this happening", - "data": {"source": 3}, - }, - # we can see malformed packets - {"data": {}}, - {}, - None, - ] - - assert get_events_summary_from_snapshot_data(snapshot_events) == [ - {"data": {"source": 3}, "timestamp": 546628637590, "type": 1}, - {"timestamp": timestamp, "type": 2, "data": {}}, - {"timestamp": timestamp, "type": 1, "data": {"source": 3}}, - {"timestamp": timestamp, "type": 1, "data": {"source": 3}}, - { - "timestamp": timestamp, - "type": 1, - "data": { - "source": 3, - "type": 1, - "href": "https://app.posthog.com/events?foo=bar", - "width": 2056, - "height": 1120, - "tag": "$pageview", - "plugin": "rrweb/console@1", - "payload": { - "href": "https://app.posthog.com/events?eventFilter=", - "level": "log", - }, - }, - }, - ] - - @pytest.fixture def raw_snapshot_events(): return [ diff --git a/posthog/session_recordings/test/test_session_recordings.py b/posthog/session_recordings/test/test_session_recordings.py index 20603ba1eb8e3..a786618f3acb5 100644 --- a/posthog/session_recordings/test/test_session_recordings.py +++ b/posthog/session_recordings/test/test_session_recordings.py @@ -373,7 +373,6 @@ def test_get_single_session_recording_metadata(self): "created_at": "2023-01-01T12:00:00Z", "uuid": ANY, }, - "storage": "clickhouse", } def test_single_session_recording_doesnt_leak_teams(self): @@ -785,6 +784,8 @@ def test_get_matching_events(self) -> None: assert response.status_code == status.HTTP_200_OK assert response.json() == {"results": [event_id]} + # checks that we 404 without patching the "exists" check + # that is patched in other tests or freezing time doesn't work def test_404_when_no_snapshots(self) -> None: response = self.client.get( f"/api/projects/{self.team.id}/session_recordings/1/snapshots?version=2", From bd316ed7ba43d60872d64ee48655620557a70d97 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Wed, 27 Sep 2023 14:50:14 +0100 Subject: [PATCH 32/41] remove recording debug info from UI --- frontend/src/lib/constants.tsx | 1 - .../debug/RecordingDebugInfo.tsx | 39 ------------------- .../playlist/SessionRecordingPreview.tsx | 3 -- .../SessionRecordingsPlaylistItem.tsx | 3 -- 4 files changed, 46 deletions(-) delete mode 100644 frontend/src/scenes/session-recordings/debug/RecordingDebugInfo.tsx diff --git a/frontend/src/lib/constants.tsx b/frontend/src/lib/constants.tsx index 12cfb71d3a623..217b14bbf7e8b 100644 --- a/frontend/src/lib/constants.tsx +++ b/frontend/src/lib/constants.tsx @@ -136,7 +136,6 @@ export const FEATURE_FLAGS = { ROLE_BASED_ACCESS: 'role-based-access', // owner: #team-experiments, @liyiy QUERY_RUNNING_TIME: 'query_running_time', // owner: @mariusandra QUERY_TIMINGS: 'query-timings', // owner: @mariusandra - RECORDING_DEBUGGING: 'recording-debugging', // owner #team-monitoring POSTHOG_3000: 'posthog-3000', // owner: @Twixes ENABLE_PROMPTS: 'enable-prompts', // owner: @lharries FEEDBACK_SCENE: 'feedback-scene', // owner: @lharries diff --git a/frontend/src/scenes/session-recordings/debug/RecordingDebugInfo.tsx b/frontend/src/scenes/session-recordings/debug/RecordingDebugInfo.tsx deleted file mode 100644 index cc099a5617eda..0000000000000 --- a/frontend/src/scenes/session-recordings/debug/RecordingDebugInfo.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import clsx from 'clsx' -import { useValues } from 'kea' -import { IconInfo } from 'lib/lemon-ui/icons' -import { Tooltip } from 'lib/lemon-ui/Tooltip' -import { FEATURE_FLAGS } from 'lib/constants' -import { featureFlagLogic } from 'lib/logic/featureFlagLogic' -import { SessionRecordingType } from '~/types' - -export function RecordingDebugInfo({ - recording, - className, -}: { - recording: SessionRecordingType - className?: string -}): JSX.Element | null { - const { featureFlags } = useValues(featureFlagLogic) - const debugMode = !!featureFlags[FEATURE_FLAGS.RECORDING_DEBUGGING] - - if (!debugMode) { - return null - } - - return ( - -

  • - ID: {recording.id} -
  • -
  • - Storage: {recording.storage} -
  • - - } - > - - - ) -} diff --git a/frontend/src/scenes/session-recordings/playlist/SessionRecordingPreview.tsx b/frontend/src/scenes/session-recordings/playlist/SessionRecordingPreview.tsx index 5132c0ddb5e9d..6184992cdb86b 100644 --- a/frontend/src/scenes/session-recordings/playlist/SessionRecordingPreview.tsx +++ b/frontend/src/scenes/session-recordings/playlist/SessionRecordingPreview.tsx @@ -6,7 +6,6 @@ import { IconAutocapture, IconKeyboard, IconPinFilled, IconSchedule } from 'lib/ import { Tooltip } from 'lib/lemon-ui/Tooltip' import { TZLabel } from 'lib/components/TZLabel' import { LemonSkeleton } from 'lib/lemon-ui/LemonSkeleton' -import { RecordingDebugInfo } from '../debug/RecordingDebugInfo' import { DraggableToNotebook } from 'scenes/notebooks/AddToNotebook/DraggableToNotebook' import { urls } from 'scenes/urls' import { playerSettingsLogic } from 'scenes/session-recordings/player/playerSettingsLogic' @@ -228,8 +227,6 @@ export function SessionRecordingPreview({ - - ) diff --git a/frontend/src/scenes/session-recordings/playlist/SessionRecordingsPlaylistItem.tsx b/frontend/src/scenes/session-recordings/playlist/SessionRecordingsPlaylistItem.tsx index 3a2a662c2419b..dac0b89bdebfb 100644 --- a/frontend/src/scenes/session-recordings/playlist/SessionRecordingsPlaylistItem.tsx +++ b/frontend/src/scenes/session-recordings/playlist/SessionRecordingsPlaylistItem.tsx @@ -6,7 +6,6 @@ import { IconAutocapture, IconKeyboard, IconPinFilled, IconSchedule } from 'lib/ import { Tooltip } from 'lib/lemon-ui/Tooltip' import { TZLabel } from 'lib/components/TZLabel' import { LemonSkeleton } from 'lib/lemon-ui/LemonSkeleton' -import { RecordingDebugInfo } from '../debug/RecordingDebugInfo' import { DraggableToNotebook } from 'scenes/notebooks/AddToNotebook/DraggableToNotebook' import { urls } from 'scenes/urls' import { playerSettingsLogic } from 'scenes/session-recordings/player/playerSettingsLogic' @@ -228,8 +227,6 @@ export function SessionRecordingPlaylistItem({ - - ) From 3ef80d4177b42a55582b2f657c3234e1bb89557a Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Wed, 27 Sep 2023 15:34:50 +0100 Subject: [PATCH 33/41] even more --- frontend/src/types.ts | 5 ----- posthog/settings/ingestion.py | 6 ++---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 0c2d5c8c11dec..9e3cb48ecbddc 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -665,12 +665,8 @@ export interface SessionRecordingSnapshotSource { } export interface SessionRecordingSnapshotResponse { - // Future interface sources?: SessionRecordingSnapshotSource[] snapshots?: EncodedRecordingSnapshot[] - - // legacy interface - next?: string } export type RecordingSnapshot = eventWithTime & { @@ -680,7 +676,6 @@ export type RecordingSnapshot = eventWithTime & { export interface SessionPlayerSnapshotData { snapshots?: RecordingSnapshot[] sources?: SessionRecordingSnapshotSource[] - next?: string blob_keys?: string[] } diff --git a/posthog/settings/ingestion.py b/posthog/settings/ingestion.py index fb9d07cf964a2..bd9edbc6fb03c 100644 --- a/posthog/settings/ingestion.py +++ b/posthog/settings/ingestion.py @@ -30,7 +30,5 @@ "PARTITION_KEY_BUCKET_REPLENTISH_RATE", type_cast=float, default=1.0 ) -REPLAY_EVENT_MAX_SIZE = get_from_env("REPLAY_EVENT_MAX_SIZE", type_cast=int, default=1024 * 512) # 512kb - -REPLAY_RETENTION_DAYS_MIN = 30 -REPLAY_RETENTION_DAYS_MAX = 90 +REPLAY_RETENTION_DAYS_MIN = get_from_env("REPLAY_RETENTION_DAYS_MIN", type_cast=int, default=30) +REPLAY_RETENTION_DAYS_MAX = get_from_env("REPLAY_RETENTION_DAYS_MAX", type_cast=int, default=90) From 07b76de7b8b25f94983d8770a77a0b7c75a3f737 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 28 Sep 2023 10:26:47 +0100 Subject: [PATCH 34/41] better error when persisting --- .../session_recording_extensions.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/ee/session_recordings/session_recording_extensions.py b/ee/session_recordings/session_recording_extensions.py index 5c44106ff2a1c..ebfb3896a1415 100644 --- a/ee/session_recordings/session_recording_extensions.py +++ b/ee/session_recordings/session_recording_extensions.py @@ -54,6 +54,10 @@ def save_recording_with_new_content(recording: SessionRecording, content: str) - return new_path +class InvalidRecordingForPersisting(Exception): + pass + + def persist_recording(recording_id: str, team_id: int) -> None: """Persist a recording to the S3""" @@ -88,10 +92,10 @@ def persist_recording(recording_id: str, team_id: int) -> None: recording.save() return + target_prefix = recording.build_object_storage_path("2023-08-01") + source_prefix = recording.build_blob_ingestion_storage_path() # if snapshots are already in blob storage, then we can just copy the files between buckets with SNAPSHOT_PERSIST_TIME_HISTOGRAM.labels(source="S3").time(): - target_prefix = recording.build_object_storage_path("2023-08-01") - source_prefix = recording.build_blob_ingestion_storage_path() copied_count = object_storage.copy_objects(source_prefix, target_prefix) if copied_count > 0: @@ -101,7 +105,14 @@ def persist_recording(recording_id: str, team_id: int) -> None: logger.info("Persisting recording: done!", recording_id=recording_id, team_id=team_id, source="s3") return else: - raise NotImplementedError("ClickHouse backed recordings are not supported") + logger.error( + "No snapshots found to copy in S3 when persisting a recording", + recording_id=recording_id, + team_id=team_id, + target_prefix=target_prefix, + source_prefix=source_prefix, + ) + raise InvalidRecordingForPersisting("Could not persist recording: " + recording_id) def load_persisted_recording(recording: SessionRecording) -> Optional[PersistedRecordingV1]: From b3cb010732b31926acb4a4033dbbc67671faebcd Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:58:28 +0000 Subject: [PATCH 35/41] Update query snapshots --- .../test_clickhouse_experiment_secondary_results.ambr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ee/clickhouse/views/test/__snapshots__/test_clickhouse_experiment_secondary_results.ambr b/ee/clickhouse/views/test/__snapshots__/test_clickhouse_experiment_secondary_results.ambr index d42c1cb3ff2e1..9f9e01f13028a 100644 --- a/ee/clickhouse/views/test/__snapshots__/test_clickhouse_experiment_secondary_results.ambr +++ b/ee/clickhouse/views/test/__snapshots__/test_clickhouse_experiment_secondary_results.ambr @@ -1,6 +1,6 @@ # name: ClickhouseTestExperimentSecondaryResults.test_basic_secondary_metric_results ' - /* user_id:125 celery:posthog.celery.sync_insight_caching_state */ + /* user_id:128 celery:posthog.celery.sync_insight_caching_state */ SELECT team_id, date_diff('second', max(timestamp), now()) AS age FROM events From b79dba4252313f6fe0867ffd04d2ea167c71a0eb Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Wed, 4 Oct 2023 19:21:33 +0100 Subject: [PATCH 36/41] there is a voided promise as part of flush when empty, let's wait to avoid a flake --- .../session-recording/session-recordings-consumer-v2.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugin-server/tests/main/ingestion-queues/session-recording/session-recordings-consumer-v2.test.ts b/plugin-server/tests/main/ingestion-queues/session-recording/session-recordings-consumer-v2.test.ts index 055fbfa1933ae..9e62602147dea 100644 --- a/plugin-server/tests/main/ingestion-queues/session-recording/session-recordings-consumer-v2.test.ts +++ b/plugin-server/tests/main/ingestion-queues/session-recording/session-recordings-consumer-v2.test.ts @@ -161,7 +161,9 @@ describe('ingester', () => { await ingester.flushAllReadySessions() - expect(ingester.sessions['1-session_id_1']).not.toBeDefined() + await waitForExpect(() => { + expect(ingester.sessions['1-session_id_1']).not.toBeDefined() + }, 1000) }) describe('parsing the message', () => { From dae426b6ce9089605364cc1b183d9553d8dbc09d Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Wed, 11 Oct 2023 11:48:25 +0100 Subject: [PATCH 37/41] fix --- plugin-server/src/main/pluginsServer.ts | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/plugin-server/src/main/pluginsServer.ts b/plugin-server/src/main/pluginsServer.ts index 9660282369cc5..01e4369477006 100644 --- a/plugin-server/src/main/pluginsServer.ts +++ b/plugin-server/src/main/pluginsServer.ts @@ -401,30 +401,6 @@ export async function startPluginsServer( hub.lastActivityType = 'serverStart' } - if (capabilities.sessionRecordingIngestion) { - const statsd = hub?.statsd ?? createStatsdClient(serverConfig, null) - const postgres = hub?.postgres ?? new PostgresRouter(serverConfig, statsd) - const teamManager = hub?.teamManager ?? new TeamManager(postgres, serverConfig) - const { - stop, - isHealthy: isSessionRecordingsHealthy, - join, - } = await startSessionRecordingEventsConsumerV1({ - teamManager: teamManager, - kafkaConfig: serverConfig, - kafkaProducerConfig: serverConfig, - consumerMaxBytes: serverConfig.KAFKA_CONSUMPTION_MAX_BYTES, - consumerMaxBytesPerPartition: serverConfig.KAFKA_CONSUMPTION_MAX_BYTES_PER_PARTITION, - consumerMaxWaitMs: serverConfig.KAFKA_CONSUMPTION_MAX_WAIT_MS, - consumerErrorBackoffMs: serverConfig.KAFKA_CONSUMPTION_ERROR_BACKOFF_MS, - batchingTimeoutMs: serverConfig.KAFKA_CONSUMPTION_BATCHING_TIMEOUT_MS, - topicCreationTimeoutMs: serverConfig.KAFKA_TOPIC_CREATION_TIMEOUT_MS, - }) - stopSessionRecordingEventsConsumer = stop - joinSessionRecordingEventsConsumer = join - healthChecks['session-recordings'] = isSessionRecordingsHealthy - } - if (capabilities.sessionRecordingBlobIngestion) { const recordingConsumerConfig = sessionRecordingConsumerConfig(serverConfig) const statsd = hub?.statsd ?? createStatsdClient(serverConfig, null) From 27a166e464114745c375329df1cce13497d719c5 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Wed, 11 Oct 2023 12:11:42 +0100 Subject: [PATCH 38/41] fix --- .../test_session_recordings.ambr | 1844 ++++++++++++----- .../test/test_session_recordings.py | 12 +- 2 files changed, 1345 insertions(+), 511 deletions(-) diff --git a/posthog/session_recordings/test/__snapshots__/test_session_recordings.ambr b/posthog/session_recordings/test/__snapshots__/test_session_recordings.ambr index 5b68085b545af..6132a8cfcb66d 100644 --- a/posthog/session_recordings/test/__snapshots__/test_session_recordings.ambr +++ b/posthog/session_recordings/test/__snapshots__/test_session_recordings.ambr @@ -84,6 +84,179 @@ ' --- # name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.100 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.101 + ' + SELECT "posthog_sessionrecording"."id", + "posthog_sessionrecording"."session_id", + "posthog_sessionrecording"."team_id", + "posthog_sessionrecording"."created_at", + "posthog_sessionrecording"."deleted", + "posthog_sessionrecording"."object_storage_path", + "posthog_sessionrecording"."distinct_id", + "posthog_sessionrecording"."duration", + "posthog_sessionrecording"."active_seconds", + "posthog_sessionrecording"."inactive_seconds", + "posthog_sessionrecording"."start_time", + "posthog_sessionrecording"."end_time", + "posthog_sessionrecording"."click_count", + "posthog_sessionrecording"."keypress_count", + "posthog_sessionrecording"."mouse_activity_count", + "posthog_sessionrecording"."console_log_count", + "posthog_sessionrecording"."console_warn_count", + "posthog_sessionrecording"."console_error_count", + "posthog_sessionrecording"."start_url", + "posthog_sessionrecording"."storage_version" + FROM "posthog_sessionrecording" + WHERE ("posthog_sessionrecording"."session_id" IN ('1', + '2', + '3', + '4', + '5') + AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.102 + ' + SELECT "posthog_sessionrecordingviewed"."session_id" + FROM "posthog_sessionrecordingviewed" + WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 + AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.103 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version", + "posthog_person"."id", + "posthog_person"."created_at", + "posthog_person"."properties_last_updated_at", + "posthog_person"."properties_last_operation", + "posthog_person"."team_id", + "posthog_person"."properties", + "posthog_person"."is_user_id", + "posthog_person"."is_identified", + "posthog_person"."uuid", + "posthog_person"."version" + FROM "posthog_persondistinctid" + INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") + WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', + 'user2', + 'user3', + 'user4', + 'user5') + AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.104 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version" + FROM "posthog_persondistinctid" + WHERE "posthog_persondistinctid"."person_id" IN (1, + 2, + 3, + 4, + 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.105 + ' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."surveys_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."plugins_opt_in", + "posthog_team"."opt_out_capture", + "posthog_team"."event_names", + "posthog_team"."event_names_with_usage", + "posthog_team"."event_properties", + "posthog_team"."event_properties_with_usage", + "posthog_team"."event_properties_numerical" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.106 + ' + SELECT "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."email_opt_in", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."events_column_config" + FROM "posthog_user" + WHERE "posthog_user"."id" = 2 + LIMIT 21 /**/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.107 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -128,7 +301,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.101 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.108 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -157,7 +330,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.102 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.109 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -168,7 +341,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.103 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.11 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.110 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -179,7 +363,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.104 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.111 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -190,7 +374,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.105 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.112 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -201,7 +385,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.106 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.113 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -212,7 +396,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.107 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.114 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -223,7 +407,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.108 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.115 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -234,7 +418,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.109 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.116 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -245,18 +429,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.11 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.117 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.110 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.118 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -267,7 +451,39 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.111 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.119 + ' + SELECT "posthog_sessionrecording"."id", + "posthog_sessionrecording"."session_id", + "posthog_sessionrecording"."team_id", + "posthog_sessionrecording"."created_at", + "posthog_sessionrecording"."deleted", + "posthog_sessionrecording"."object_storage_path", + "posthog_sessionrecording"."distinct_id", + "posthog_sessionrecording"."duration", + "posthog_sessionrecording"."active_seconds", + "posthog_sessionrecording"."inactive_seconds", + "posthog_sessionrecording"."start_time", + "posthog_sessionrecording"."end_time", + "posthog_sessionrecording"."click_count", + "posthog_sessionrecording"."keypress_count", + "posthog_sessionrecording"."mouse_activity_count", + "posthog_sessionrecording"."console_log_count", + "posthog_sessionrecording"."console_warn_count", + "posthog_sessionrecording"."console_error_count", + "posthog_sessionrecording"."start_url", + "posthog_sessionrecording"."storage_version" + FROM "posthog_sessionrecording" + WHERE ("posthog_sessionrecording"."session_id" IN ('1', + '2', + '3', + '4', + '5', + '6') + AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.12 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -278,7 +494,58 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.112 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.120 + ' + SELECT "posthog_sessionrecordingviewed"."session_id" + FROM "posthog_sessionrecordingviewed" + WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 + AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.121 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version", + "posthog_person"."id", + "posthog_person"."created_at", + "posthog_person"."properties_last_updated_at", + "posthog_person"."properties_last_operation", + "posthog_person"."team_id", + "posthog_person"."properties", + "posthog_person"."is_user_id", + "posthog_person"."is_identified", + "posthog_person"."uuid", + "posthog_person"."version" + FROM "posthog_persondistinctid" + INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") + WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', + 'user2', + 'user3', + 'user4', + 'user5', + 'user6') + AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.122 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version" + FROM "posthog_persondistinctid" + WHERE "posthog_persondistinctid"."person_id" IN (1, + 2, + 3, + 4, + 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.123 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -330,7 +597,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.113 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.124 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -359,7 +626,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.114 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.125 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -404,7 +671,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.115 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.126 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -433,7 +700,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.116 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.127 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -444,7 +711,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.117 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.128 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -455,7 +722,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.118 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.129 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -466,29 +733,29 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.119 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.13 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.12 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.130 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.120 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.131 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -499,7 +766,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.121 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.132 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -510,7 +777,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.122 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.133 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -521,7 +788,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.123 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.134 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -532,7 +799,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.124 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.135 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -543,7 +810,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.125 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.136 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -554,7 +821,100 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.126 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.137 + ' + SELECT "posthog_sessionrecording"."id", + "posthog_sessionrecording"."session_id", + "posthog_sessionrecording"."team_id", + "posthog_sessionrecording"."created_at", + "posthog_sessionrecording"."deleted", + "posthog_sessionrecording"."object_storage_path", + "posthog_sessionrecording"."distinct_id", + "posthog_sessionrecording"."duration", + "posthog_sessionrecording"."active_seconds", + "posthog_sessionrecording"."inactive_seconds", + "posthog_sessionrecording"."start_time", + "posthog_sessionrecording"."end_time", + "posthog_sessionrecording"."click_count", + "posthog_sessionrecording"."keypress_count", + "posthog_sessionrecording"."mouse_activity_count", + "posthog_sessionrecording"."console_log_count", + "posthog_sessionrecording"."console_warn_count", + "posthog_sessionrecording"."console_error_count", + "posthog_sessionrecording"."start_url", + "posthog_sessionrecording"."storage_version" + FROM "posthog_sessionrecording" + WHERE ("posthog_sessionrecording"."session_id" IN ('1', + '2', + '3', + '4', + '5', + '6', + '7') + AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.138 + ' + SELECT "posthog_sessionrecordingviewed"."session_id" + FROM "posthog_sessionrecordingviewed" + WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 + AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.139 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version", + "posthog_person"."id", + "posthog_person"."created_at", + "posthog_person"."properties_last_updated_at", + "posthog_person"."properties_last_operation", + "posthog_person"."team_id", + "posthog_person"."properties", + "posthog_person"."is_user_id", + "posthog_person"."is_identified", + "posthog_person"."uuid", + "posthog_person"."version" + FROM "posthog_persondistinctid" + INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") + WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', + 'user2', + 'user3', + 'user4', + 'user5', + 'user6', + 'user7') + AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.14 + ' + SELECT "posthog_sessionrecordingviewed"."session_id" + FROM "posthog_sessionrecordingviewed" + WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 + AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.140 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version" + FROM "posthog_persondistinctid" + WHERE "posthog_persondistinctid"."person_id" IN (1, + 2, + 3, + 4, + 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.141 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -606,7 +966,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.127 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.142 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -635,7 +995,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.128 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.143 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -680,7 +1040,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.129 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.144 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -709,18 +1069,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.13 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.130 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.145 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -731,7 +1080,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.131 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.146 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -742,7 +1091,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.132 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.147 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -753,7 +1102,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.133 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.148 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -764,7 +1113,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.134 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.149 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -775,62 +1124,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.135 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.136 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.137 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.138 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.139 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.14 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.15 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -882,7 +1176,149 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.140 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.150 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.151 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.152 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.153 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.154 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.155 + ' + SELECT "posthog_sessionrecording"."id", + "posthog_sessionrecording"."session_id", + "posthog_sessionrecording"."team_id", + "posthog_sessionrecording"."created_at", + "posthog_sessionrecording"."deleted", + "posthog_sessionrecording"."object_storage_path", + "posthog_sessionrecording"."distinct_id", + "posthog_sessionrecording"."duration", + "posthog_sessionrecording"."active_seconds", + "posthog_sessionrecording"."inactive_seconds", + "posthog_sessionrecording"."start_time", + "posthog_sessionrecording"."end_time", + "posthog_sessionrecording"."click_count", + "posthog_sessionrecording"."keypress_count", + "posthog_sessionrecording"."mouse_activity_count", + "posthog_sessionrecording"."console_log_count", + "posthog_sessionrecording"."console_warn_count", + "posthog_sessionrecording"."console_error_count", + "posthog_sessionrecording"."start_url", + "posthog_sessionrecording"."storage_version" + FROM "posthog_sessionrecording" + WHERE ("posthog_sessionrecording"."session_id" IN ('1', + '2', + '3', + '4', + '5', + '6', + '7', + '8') + AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.156 + ' + SELECT "posthog_sessionrecordingviewed"."session_id" + FROM "posthog_sessionrecordingviewed" + WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 + AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.157 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version", + "posthog_person"."id", + "posthog_person"."created_at", + "posthog_person"."properties_last_updated_at", + "posthog_person"."properties_last_operation", + "posthog_person"."team_id", + "posthog_person"."properties", + "posthog_person"."is_user_id", + "posthog_person"."is_identified", + "posthog_person"."uuid", + "posthog_person"."version" + FROM "posthog_persondistinctid" + INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") + WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', + 'user2', + 'user3', + 'user4', + 'user5', + 'user6', + 'user7', + 'user8') + AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.158 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version" + FROM "posthog_persondistinctid" + WHERE "posthog_persondistinctid"."person_id" IN (1, + 2, + 3, + 4, + 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.159 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -934,7 +1370,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.141 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.16 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -963,7 +1399,36 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.142 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.160 + ' + SELECT "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."email_opt_in", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."events_column_config" + FROM "posthog_user" + WHERE "posthog_user"."id" = 2 + LIMIT 21 /**/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.161 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1008,7 +1473,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.143 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.162 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -1037,7 +1502,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.144 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.163 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1048,7 +1513,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.145 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.164 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1059,7 +1524,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.146 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.165 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1070,7 +1535,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.147 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.166 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1081,7 +1546,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.148 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.167 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1092,7 +1557,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.149 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.168 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1103,36 +1568,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.15 - ' - SELECT "posthog_user"."id", - "posthog_user"."password", - "posthog_user"."last_login", - "posthog_user"."first_name", - "posthog_user"."last_name", - "posthog_user"."is_staff", - "posthog_user"."is_active", - "posthog_user"."date_joined", - "posthog_user"."uuid", - "posthog_user"."current_organization_id", - "posthog_user"."current_team_id", - "posthog_user"."email", - "posthog_user"."pending_email", - "posthog_user"."temporary_token", - "posthog_user"."distinct_id", - "posthog_user"."is_email_verified", - "posthog_user"."has_seen_product_intro_for", - "posthog_user"."email_opt_in", - "posthog_user"."partial_notification_settings", - "posthog_user"."anonymize_data", - "posthog_user"."toolbar_mode", - "posthog_user"."events_column_config" - FROM "posthog_user" - WHERE "posthog_user"."id" = 2 - LIMIT 21 /**/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.150 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.169 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1143,7 +1579,52 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.151 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.17 + ' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."surveys_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.170 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1154,7 +1635,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.152 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.171 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1165,7 +1646,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.153 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.172 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1176,7 +1657,177 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.16 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.173 + ' + SELECT "posthog_sessionrecording"."id", + "posthog_sessionrecording"."session_id", + "posthog_sessionrecording"."team_id", + "posthog_sessionrecording"."created_at", + "posthog_sessionrecording"."deleted", + "posthog_sessionrecording"."object_storage_path", + "posthog_sessionrecording"."distinct_id", + "posthog_sessionrecording"."duration", + "posthog_sessionrecording"."active_seconds", + "posthog_sessionrecording"."inactive_seconds", + "posthog_sessionrecording"."start_time", + "posthog_sessionrecording"."end_time", + "posthog_sessionrecording"."click_count", + "posthog_sessionrecording"."keypress_count", + "posthog_sessionrecording"."mouse_activity_count", + "posthog_sessionrecording"."console_log_count", + "posthog_sessionrecording"."console_warn_count", + "posthog_sessionrecording"."console_error_count", + "posthog_sessionrecording"."start_url", + "posthog_sessionrecording"."storage_version" + FROM "posthog_sessionrecording" + WHERE ("posthog_sessionrecording"."session_id" IN ('1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9') + AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.174 + ' + SELECT "posthog_sessionrecordingviewed"."session_id" + FROM "posthog_sessionrecordingviewed" + WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 + AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.175 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version", + "posthog_person"."id", + "posthog_person"."created_at", + "posthog_person"."properties_last_updated_at", + "posthog_person"."properties_last_operation", + "posthog_person"."team_id", + "posthog_person"."properties", + "posthog_person"."is_user_id", + "posthog_person"."is_identified", + "posthog_person"."uuid", + "posthog_person"."version" + FROM "posthog_persondistinctid" + INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") + WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', + 'user2', + 'user3', + 'user4', + 'user5', + 'user6', + 'user7', + 'user8', + 'user9') + AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.176 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version" + FROM "posthog_persondistinctid" + WHERE "posthog_persondistinctid"."person_id" IN (1, + 2, + 3, + 4, + 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.177 + ' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."surveys_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."plugins_opt_in", + "posthog_team"."opt_out_capture", + "posthog_team"."event_names", + "posthog_team"."event_names_with_usage", + "posthog_team"."event_properties", + "posthog_team"."event_properties_with_usage", + "posthog_team"."event_properties_numerical" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.178 + ' + SELECT "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."email_opt_in", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."events_column_config" + FROM "posthog_user" + WHERE "posthog_user"."id" = 2 + LIMIT 21 /**/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.179 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1221,7 +1872,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.17 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.18 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -1250,29 +1901,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.18 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.19 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.2 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.180 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -1301,7 +1930,29 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.20 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.181 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.182 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.183 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1312,7 +1963,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.21 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.184 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1323,7 +1974,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.22 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.185 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1334,7 +1985,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.23 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.186 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1345,7 +1996,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.24 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.187 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1356,7 +2007,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.25 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.188 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1367,7 +2018,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.26 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.189 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1378,155 +2029,120 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.27 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.19 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.28 - ' - SELECT "posthog_team"."id", - "posthog_team"."uuid", - "posthog_team"."organization_id", - "posthog_team"."api_token", - "posthog_team"."app_urls", - "posthog_team"."name", - "posthog_team"."slack_incoming_webhook", - "posthog_team"."created_at", - "posthog_team"."updated_at", - "posthog_team"."anonymize_ips", - "posthog_team"."completed_snippet_onboarding", - "posthog_team"."has_completed_onboarding_for", - "posthog_team"."ingested_event", - "posthog_team"."autocapture_opt_out", - "posthog_team"."autocapture_exceptions_opt_in", - "posthog_team"."autocapture_exceptions_errors_to_ignore", - "posthog_team"."session_recording_opt_in", - "posthog_team"."capture_console_log_opt_in", - "posthog_team"."capture_performance_opt_in", - "posthog_team"."surveys_opt_in", - "posthog_team"."session_recording_version", - "posthog_team"."signup_token", - "posthog_team"."is_demo", - "posthog_team"."access_control", - "posthog_team"."week_start_day", - "posthog_team"."inject_web_apps", - "posthog_team"."test_account_filters", - "posthog_team"."test_account_filters_default_checked", - "posthog_team"."path_cleaning_filters", - "posthog_team"."timezone", - "posthog_team"."data_attributes", - "posthog_team"."person_display_name_properties", - "posthog_team"."live_events_columns", - "posthog_team"."recording_domains", - "posthog_team"."primary_dashboard_id", - "posthog_team"."extra_settings", - "posthog_team"."correlation_config", - "posthog_team"."session_recording_retention_period_days", - "posthog_team"."plugins_opt_in", - "posthog_team"."opt_out_capture", - "posthog_team"."event_names", - "posthog_team"."event_names_with_usage", - "posthog_team"."event_properties", - "posthog_team"."event_properties_with_usage", - "posthog_team"."event_properties_numerical" - FROM "posthog_team" - WHERE "posthog_team"."id" = 2 - LIMIT 21 - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.29 - ' - SELECT "posthog_user"."id", - "posthog_user"."password", - "posthog_user"."last_login", - "posthog_user"."first_name", - "posthog_user"."last_name", - "posthog_user"."is_staff", - "posthog_user"."is_active", - "posthog_user"."date_joined", - "posthog_user"."uuid", - "posthog_user"."current_organization_id", - "posthog_user"."current_team_id", - "posthog_user"."email", - "posthog_user"."pending_email", - "posthog_user"."temporary_token", - "posthog_user"."distinct_id", - "posthog_user"."is_email_verified", - "posthog_user"."has_seen_product_intro_for", - "posthog_user"."email_opt_in", - "posthog_user"."partial_notification_settings", - "posthog_user"."anonymize_data", - "posthog_user"."toolbar_mode", - "posthog_user"."events_column_config" - FROM "posthog_user" - WHERE "posthog_user"."id" = 2 - LIMIT 21 /**/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.3 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.190 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:RATE_LIMIT_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.30 - ' - SELECT "posthog_team"."id", - "posthog_team"."uuid", - "posthog_team"."organization_id", - "posthog_team"."api_token", - "posthog_team"."app_urls", - "posthog_team"."name", - "posthog_team"."slack_incoming_webhook", - "posthog_team"."created_at", - "posthog_team"."updated_at", - "posthog_team"."anonymize_ips", - "posthog_team"."completed_snippet_onboarding", - "posthog_team"."has_completed_onboarding_for", - "posthog_team"."ingested_event", - "posthog_team"."autocapture_opt_out", - "posthog_team"."autocapture_exceptions_opt_in", - "posthog_team"."autocapture_exceptions_errors_to_ignore", - "posthog_team"."session_recording_opt_in", - "posthog_team"."capture_console_log_opt_in", - "posthog_team"."capture_performance_opt_in", - "posthog_team"."surveys_opt_in", - "posthog_team"."session_recording_version", - "posthog_team"."signup_token", - "posthog_team"."is_demo", - "posthog_team"."access_control", - "posthog_team"."week_start_day", - "posthog_team"."inject_web_apps", - "posthog_team"."test_account_filters", - "posthog_team"."test_account_filters_default_checked", - "posthog_team"."path_cleaning_filters", - "posthog_team"."timezone", - "posthog_team"."data_attributes", - "posthog_team"."person_display_name_properties", - "posthog_team"."live_events_columns", - "posthog_team"."recording_domains", - "posthog_team"."primary_dashboard_id", - "posthog_team"."extra_settings", - "posthog_team"."correlation_config", - "posthog_team"."session_recording_retention_period_days" - FROM "posthog_team" - WHERE "posthog_team"."id" = 2 - LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.191 + ' + SELECT "posthog_sessionrecording"."id", + "posthog_sessionrecording"."session_id", + "posthog_sessionrecording"."team_id", + "posthog_sessionrecording"."created_at", + "posthog_sessionrecording"."deleted", + "posthog_sessionrecording"."object_storage_path", + "posthog_sessionrecording"."distinct_id", + "posthog_sessionrecording"."duration", + "posthog_sessionrecording"."active_seconds", + "posthog_sessionrecording"."inactive_seconds", + "posthog_sessionrecording"."start_time", + "posthog_sessionrecording"."end_time", + "posthog_sessionrecording"."click_count", + "posthog_sessionrecording"."keypress_count", + "posthog_sessionrecording"."mouse_activity_count", + "posthog_sessionrecording"."console_log_count", + "posthog_sessionrecording"."console_warn_count", + "posthog_sessionrecording"."console_error_count", + "posthog_sessionrecording"."start_url", + "posthog_sessionrecording"."storage_version" + FROM "posthog_sessionrecording" + WHERE ("posthog_sessionrecording"."session_id" IN ('1', + '10', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9') + AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.192 + ' + SELECT "posthog_sessionrecordingviewed"."session_id" + FROM "posthog_sessionrecordingviewed" + WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 + AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.193 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version", + "posthog_person"."id", + "posthog_person"."created_at", + "posthog_person"."properties_last_updated_at", + "posthog_person"."properties_last_operation", + "posthog_person"."team_id", + "posthog_person"."properties", + "posthog_person"."is_user_id", + "posthog_person"."is_identified", + "posthog_person"."uuid", + "posthog_person"."version" + FROM "posthog_persondistinctid" + INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") + WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', + 'user10', + 'user2', + 'user3', + 'user4', + 'user5', + 'user6', + 'user7', + 'user8', + 'user9') + AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.194 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version" + FROM "posthog_persondistinctid" + WHERE "posthog_persondistinctid"."person_id" IN (1, + 2, + 3, + 4, + 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.31 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.2 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -1555,18 +2171,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.32 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.33 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.20 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1577,7 +2182,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.34 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.21 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1588,7 +2193,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.35 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.22 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1599,7 +2204,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.36 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.23 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1610,7 +2215,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.37 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.24 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1621,7 +2226,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.38 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.25 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1632,7 +2237,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.39 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.26 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1643,18 +2248,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.4 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.27 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.40 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.28 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1665,18 +2270,91 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.41 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.29 + ' + SELECT "posthog_sessionrecording"."id", + "posthog_sessionrecording"."session_id", + "posthog_sessionrecording"."team_id", + "posthog_sessionrecording"."created_at", + "posthog_sessionrecording"."deleted", + "posthog_sessionrecording"."object_storage_path", + "posthog_sessionrecording"."distinct_id", + "posthog_sessionrecording"."duration", + "posthog_sessionrecording"."active_seconds", + "posthog_sessionrecording"."inactive_seconds", + "posthog_sessionrecording"."start_time", + "posthog_sessionrecording"."end_time", + "posthog_sessionrecording"."click_count", + "posthog_sessionrecording"."keypress_count", + "posthog_sessionrecording"."mouse_activity_count", + "posthog_sessionrecording"."console_log_count", + "posthog_sessionrecording"."console_warn_count", + "posthog_sessionrecording"."console_error_count", + "posthog_sessionrecording"."start_url", + "posthog_sessionrecording"."storage_version" + FROM "posthog_sessionrecording" + WHERE ("posthog_sessionrecording"."session_id" IN ('1') + AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.3 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RATE_LIMIT_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.42 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.30 + ' + SELECT "posthog_sessionrecordingviewed"."session_id" + FROM "posthog_sessionrecordingviewed" + WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 + AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.31 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version", + "posthog_person"."id", + "posthog_person"."created_at", + "posthog_person"."properties_last_updated_at", + "posthog_person"."properties_last_operation", + "posthog_person"."team_id", + "posthog_person"."properties", + "posthog_person"."is_user_id", + "posthog_person"."is_identified", + "posthog_person"."uuid", + "posthog_person"."version" + FROM "posthog_persondistinctid" + INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") + WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1') + AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.32 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version" + FROM "posthog_persondistinctid" + WHERE "posthog_persondistinctid"."person_id" IN (1, + 2, + 3, + 4, + 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.33 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1728,7 +2406,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.43 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.34 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -1757,7 +2435,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.44 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.35 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1802,7 +2480,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.45 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.36 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -1831,7 +2509,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.46 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.37 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1842,7 +2520,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.47 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.38 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1853,7 +2531,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.48 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.39 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1864,18 +2542,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.49 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.4 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.5 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.40 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1886,7 +2564,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.50 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.41 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1897,7 +2575,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.51 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.42 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1908,7 +2586,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.52 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.43 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1919,7 +2597,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.53 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.44 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1930,7 +2608,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.54 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.45 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1941,7 +2619,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.55 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.46 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1952,7 +2630,93 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.56 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.47 + ' + SELECT "posthog_sessionrecording"."id", + "posthog_sessionrecording"."session_id", + "posthog_sessionrecording"."team_id", + "posthog_sessionrecording"."created_at", + "posthog_sessionrecording"."deleted", + "posthog_sessionrecording"."object_storage_path", + "posthog_sessionrecording"."distinct_id", + "posthog_sessionrecording"."duration", + "posthog_sessionrecording"."active_seconds", + "posthog_sessionrecording"."inactive_seconds", + "posthog_sessionrecording"."start_time", + "posthog_sessionrecording"."end_time", + "posthog_sessionrecording"."click_count", + "posthog_sessionrecording"."keypress_count", + "posthog_sessionrecording"."mouse_activity_count", + "posthog_sessionrecording"."console_log_count", + "posthog_sessionrecording"."console_warn_count", + "posthog_sessionrecording"."console_error_count", + "posthog_sessionrecording"."start_url", + "posthog_sessionrecording"."storage_version" + FROM "posthog_sessionrecording" + WHERE ("posthog_sessionrecording"."session_id" IN ('1', + '2') + AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.48 + ' + SELECT "posthog_sessionrecordingviewed"."session_id" + FROM "posthog_sessionrecordingviewed" + WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 + AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.49 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version", + "posthog_person"."id", + "posthog_person"."created_at", + "posthog_person"."properties_last_updated_at", + "posthog_person"."properties_last_operation", + "posthog_person"."team_id", + "posthog_person"."properties", + "posthog_person"."is_user_id", + "posthog_person"."is_identified", + "posthog_person"."uuid", + "posthog_person"."version" + FROM "posthog_persondistinctid" + INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") + WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', + 'user2') + AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.5 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.50 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version" + FROM "posthog_persondistinctid" + WHERE "posthog_persondistinctid"."person_id" IN (1, + 2, + 3, + 4, + 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.51 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2004,7 +2768,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.57 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.52 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -2033,7 +2797,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.58 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.53 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2078,7 +2842,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.59 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.54 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -2107,7 +2871,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.6 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.55 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2118,51 +2882,51 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.60 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.56 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.61 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.57 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.62 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.58 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.63 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.59 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.64 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.6 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2173,7 +2937,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.65 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.60 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2184,7 +2948,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.66 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.61 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2195,7 +2959,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.67 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.62 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2206,7 +2970,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.68 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.63 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2217,7 +2981,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.69 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.64 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2228,18 +2992,84 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.7 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.65 ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + SELECT "posthog_sessionrecording"."id", + "posthog_sessionrecording"."session_id", + "posthog_sessionrecording"."team_id", + "posthog_sessionrecording"."created_at", + "posthog_sessionrecording"."deleted", + "posthog_sessionrecording"."object_storage_path", + "posthog_sessionrecording"."distinct_id", + "posthog_sessionrecording"."duration", + "posthog_sessionrecording"."active_seconds", + "posthog_sessionrecording"."inactive_seconds", + "posthog_sessionrecording"."start_time", + "posthog_sessionrecording"."end_time", + "posthog_sessionrecording"."click_count", + "posthog_sessionrecording"."keypress_count", + "posthog_sessionrecording"."mouse_activity_count", + "posthog_sessionrecording"."console_log_count", + "posthog_sessionrecording"."console_warn_count", + "posthog_sessionrecording"."console_error_count", + "posthog_sessionrecording"."start_url", + "posthog_sessionrecording"."storage_version" + FROM "posthog_sessionrecording" + WHERE ("posthog_sessionrecording"."session_id" IN ('1', + '2', + '3') + AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.70 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.66 + ' + SELECT "posthog_sessionrecordingviewed"."session_id" + FROM "posthog_sessionrecordingviewed" + WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 + AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.67 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version", + "posthog_person"."id", + "posthog_person"."created_at", + "posthog_person"."properties_last_updated_at", + "posthog_person"."properties_last_operation", + "posthog_person"."team_id", + "posthog_person"."properties", + "posthog_person"."is_user_id", + "posthog_person"."is_identified", + "posthog_person"."uuid", + "posthog_person"."version" + FROM "posthog_persondistinctid" + INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") + WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', + 'user2', + 'user3') + AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.68 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version" + FROM "posthog_persondistinctid" + WHERE "posthog_persondistinctid"."person_id" IN (1, + 2, + 3, + 4, + 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.69 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2291,7 +3121,18 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.71 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.7 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.70 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -2320,7 +3161,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.72 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.71 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2365,7 +3206,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.73 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.72 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -2394,7 +3235,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.74 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.73 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2405,7 +3246,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.75 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.74 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2416,7 +3257,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.76 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.75 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2427,7 +3268,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.77 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.76 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2438,7 +3279,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.78 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.77 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2449,7 +3290,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.79 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.78 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2460,29 +3301,29 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.8 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.79 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.80 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.8 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.81 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.80 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2493,7 +3334,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.82 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.81 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2504,7 +3345,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.83 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.82 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2515,7 +3356,86 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.83 + ' + SELECT "posthog_sessionrecording"."id", + "posthog_sessionrecording"."session_id", + "posthog_sessionrecording"."team_id", + "posthog_sessionrecording"."created_at", + "posthog_sessionrecording"."deleted", + "posthog_sessionrecording"."object_storage_path", + "posthog_sessionrecording"."distinct_id", + "posthog_sessionrecording"."duration", + "posthog_sessionrecording"."active_seconds", + "posthog_sessionrecording"."inactive_seconds", + "posthog_sessionrecording"."start_time", + "posthog_sessionrecording"."end_time", + "posthog_sessionrecording"."click_count", + "posthog_sessionrecording"."keypress_count", + "posthog_sessionrecording"."mouse_activity_count", + "posthog_sessionrecording"."console_log_count", + "posthog_sessionrecording"."console_warn_count", + "posthog_sessionrecording"."console_error_count", + "posthog_sessionrecording"."start_url", + "posthog_sessionrecording"."storage_version" + FROM "posthog_sessionrecording" + WHERE ("posthog_sessionrecording"."session_id" IN ('1', + '2', + '3', + '4') + AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- # name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.84 + ' + SELECT "posthog_sessionrecordingviewed"."session_id" + FROM "posthog_sessionrecordingviewed" + WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 + AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.85 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version", + "posthog_person"."id", + "posthog_person"."created_at", + "posthog_person"."properties_last_updated_at", + "posthog_person"."properties_last_operation", + "posthog_person"."team_id", + "posthog_person"."properties", + "posthog_person"."is_user_id", + "posthog_person"."is_identified", + "posthog_person"."uuid", + "posthog_person"."version" + FROM "posthog_persondistinctid" + INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") + WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', + 'user2', + 'user3', + 'user4') + AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.86 + ' + SELECT "posthog_persondistinctid"."id", + "posthog_persondistinctid"."team_id", + "posthog_persondistinctid"."person_id", + "posthog_persondistinctid"."distinct_id", + "posthog_persondistinctid"."version" + FROM "posthog_persondistinctid" + WHERE "posthog_persondistinctid"."person_id" IN (1, + 2, + 3, + 4, + 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.87 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2567,7 +3487,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.85 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.88 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -2596,7 +3516,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.86 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.89 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2641,7 +3561,18 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.87 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.9 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.90 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -2670,7 +3601,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.88 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.91 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2681,18 +3612,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.89 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.9 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.92 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2703,7 +3623,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.90 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.93 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2714,7 +3634,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.91 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.94 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2725,7 +3645,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.92 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.95 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2736,7 +3656,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.93 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.96 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2747,7 +3667,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.94 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.97 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2758,7 +3678,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.95 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.98 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2769,18 +3689,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.96 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.97 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.99 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2791,84 +3700,3 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.98 - ' - SELECT "posthog_team"."id", - "posthog_team"."uuid", - "posthog_team"."organization_id", - "posthog_team"."api_token", - "posthog_team"."app_urls", - "posthog_team"."name", - "posthog_team"."slack_incoming_webhook", - "posthog_team"."created_at", - "posthog_team"."updated_at", - "posthog_team"."anonymize_ips", - "posthog_team"."completed_snippet_onboarding", - "posthog_team"."has_completed_onboarding_for", - "posthog_team"."ingested_event", - "posthog_team"."autocapture_opt_out", - "posthog_team"."autocapture_exceptions_opt_in", - "posthog_team"."autocapture_exceptions_errors_to_ignore", - "posthog_team"."session_recording_opt_in", - "posthog_team"."capture_console_log_opt_in", - "posthog_team"."capture_performance_opt_in", - "posthog_team"."surveys_opt_in", - "posthog_team"."session_recording_version", - "posthog_team"."signup_token", - "posthog_team"."is_demo", - "posthog_team"."access_control", - "posthog_team"."week_start_day", - "posthog_team"."inject_web_apps", - "posthog_team"."test_account_filters", - "posthog_team"."test_account_filters_default_checked", - "posthog_team"."path_cleaning_filters", - "posthog_team"."timezone", - "posthog_team"."data_attributes", - "posthog_team"."person_display_name_properties", - "posthog_team"."live_events_columns", - "posthog_team"."recording_domains", - "posthog_team"."primary_dashboard_id", - "posthog_team"."extra_settings", - "posthog_team"."correlation_config", - "posthog_team"."session_recording_retention_period_days", - "posthog_team"."plugins_opt_in", - "posthog_team"."opt_out_capture", - "posthog_team"."event_names", - "posthog_team"."event_names_with_usage", - "posthog_team"."event_properties", - "posthog_team"."event_properties_with_usage", - "posthog_team"."event_properties_numerical" - FROM "posthog_team" - WHERE "posthog_team"."id" = 2 - LIMIT 21 - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.99 - ' - SELECT "posthog_user"."id", - "posthog_user"."password", - "posthog_user"."last_login", - "posthog_user"."first_name", - "posthog_user"."last_name", - "posthog_user"."is_staff", - "posthog_user"."is_active", - "posthog_user"."date_joined", - "posthog_user"."uuid", - "posthog_user"."current_organization_id", - "posthog_user"."current_team_id", - "posthog_user"."email", - "posthog_user"."pending_email", - "posthog_user"."temporary_token", - "posthog_user"."distinct_id", - "posthog_user"."is_email_verified", - "posthog_user"."has_seen_product_intro_for", - "posthog_user"."email_opt_in", - "posthog_user"."partial_notification_settings", - "posthog_user"."anonymize_data", - "posthog_user"."toolbar_mode", - "posthog_user"."events_column_config" - FROM "posthog_user" - WHERE "posthog_user"."id" = 2 - LIMIT 21 /**/ - ' ---- diff --git a/posthog/session_recordings/test/test_session_recordings.py b/posthog/session_recordings/test/test_session_recordings.py index dd471a95c79bd..a67b611361f40 100644 --- a/posthog/session_recordings/test/test_session_recordings.py +++ b/posthog/session_recordings/test/test_session_recordings.py @@ -462,14 +462,20 @@ def test_delete_session_recording(self): response = self.client.delete(f"/api/projects/{self.team.id}/session_recordings/1") self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) - def test_persist_session_recording(self): + @patch("ee.session_recordings.session_recording_extensions.object_storage.copy_objects", return_value=2) + def test_persist_session_recording(self, _mock_copy_objects: MagicMock) -> None: self.create_snapshot("user", "1", now() - relativedelta(days=1), team_id=self.team.pk) + response = self.client.get(f"/api/projects/{self.team.id}/session_recordings/1") + assert response.status_code == status.HTTP_200_OK assert response.json()["storage"] == "object_storage" - # Trying to delete same recording again returns 404 + response = self.client.post(f"/api/projects/{self.team.id}/session_recordings/1/persist") - assert response.json()["success"] + assert response.status_code == status.HTTP_200_OK + assert response.json() == {"success": True} + response = self.client.get(f"/api/projects/{self.team.id}/session_recordings/1") + assert response.status_code == status.HTTP_200_OK assert response.json()["storage"] == "object_storage_lts" # New snapshot loading method From 392cbdc9267ec23effe12e1bac9db6cc77e8859a Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Wed, 11 Oct 2023 12:21:10 +0100 Subject: [PATCH 39/41] fix --- .../test/test_funnel_correlations_persons.py | 58 +++--- ee/clickhouse/queries/test/test_paths.py | 64 +++---- .../test/test_session_recording_extensions.py | 32 +--- .../test/test_session_recording_playlist.py | 26 +-- posthog/api/test/test_persons_trends.py | 16 +- posthog/demo/legacy/data_generator.py | 16 +- .../funnels/test/test_funnel_persons.py | 11 +- .../test/test_funnel_strict_persons.py | 14 +- .../test/test_funnel_trends_persons.py | 29 ++- .../test/test_funnel_unordered_persons.py | 11 +- posthog/queries/trends/test/test_person.py | 20 +- .../test/test_session_recording_properties.py | 18 +- .../session_recordings/test/test_factory.py | 180 ------------------ .../test/test_session_recordings.py | 23 +-- posthog/tasks/test/test_usage_report.py | 58 +++--- 15 files changed, 220 insertions(+), 356 deletions(-) delete mode 100644 posthog/session_recordings/test/test_factory.py diff --git a/ee/clickhouse/queries/funnels/test/test_funnel_correlations_persons.py b/ee/clickhouse/queries/funnels/test/test_funnel_correlations_persons.py index 03a79d7dd7894..81dd5cf6a3920 100644 --- a/ee/clickhouse/queries/funnels/test/test_funnel_correlations_persons.py +++ b/ee/clickhouse/queries/funnels/test/test_funnel_correlations_persons.py @@ -10,7 +10,7 @@ from posthog.constants import INSIGHT_FUNNELS from posthog.models import Cohort, Filter from posthog.models.person import Person -from posthog.session_recordings.test.test_factory import create_session_recording_events +from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary from posthog.tasks.calculate_cohort import insert_cohort_from_insight_filter from posthog.test.base import ( APIBaseTest, @@ -273,13 +273,13 @@ def test_funnel_correlation_on_event_with_recordings(self): event_uuid="21111111-1111-1111-1111-111111111111", ) - create_session_recording_events( - self.team.pk, - datetime(2021, 1, 2, 0, 0, 0), - "user_1", - "s2", - use_recording_table=False, - use_replay_table=True, + timestamp = datetime(2021, 1, 2, 0, 0, 0) + produce_replay_summary( + team_id=self.team.pk, + session_id="s2", + distinct_id="user_1", + first_timestamp=timestamp, + last_timestamp=timestamp, ) # Success filter @@ -371,13 +371,13 @@ def test_funnel_correlation_on_properties_with_recordings(self): event_uuid="21111111-1111-1111-1111-111111111111", ) - create_session_recording_events( - self.team.pk, - datetime(2021, 1, 2, 0, 0, 0), - "user_1", - "s2", - use_recording_table=False, - use_replay_table=True, + timestamp = datetime(2021, 1, 2, 0, 0, 0) + produce_replay_summary( + team_id=self.team.pk, + session_id="s2", + distinct_id="user_1", + first_timestamp=timestamp, + last_timestamp=timestamp, ) # Success filter @@ -444,13 +444,13 @@ def test_strict_funnel_correlation_with_recordings(self): properties={"$session_id": "s2", "$window_id": "w2"}, event_uuid="41111111-1111-1111-1111-111111111111", ) - create_session_recording_events( - self.team.pk, - datetime(2021, 1, 2, 0, 0, 0), - "user_1", - "s2", - use_recording_table=False, - use_replay_table=True, + timestamp = datetime(2021, 1, 2, 0, 0, 0) + produce_replay_summary( + team_id=self.team.pk, + session_id="s2", + distinct_id="user_1", + first_timestamp=timestamp, + last_timestamp=timestamp, ) # Second user with strict funnel drop off, but completed the step events for a normal funnel @@ -479,13 +479,13 @@ def test_strict_funnel_correlation_with_recordings(self): properties={"$session_id": "s3", "$window_id": "w2"}, event_uuid="71111111-1111-1111-1111-111111111111", ) - create_session_recording_events( - self.team.pk, - datetime(2021, 1, 2, 0, 0, 0), - "user_2", - "s3", - use_recording_table=False, - use_replay_table=True, + timestamp1 = datetime(2021, 1, 2, 0, 0, 0) + produce_replay_summary( + team_id=self.team.pk, + session_id="s3", + distinct_id="user_2", + first_timestamp=timestamp1, + last_timestamp=timestamp1, ) # Success filter diff --git a/ee/clickhouse/queries/test/test_paths.py b/ee/clickhouse/queries/test/test_paths.py index 4a64ebf03c777..03e4203092377 100644 --- a/ee/clickhouse/queries/test/test_paths.py +++ b/ee/clickhouse/queries/test/test_paths.py @@ -19,7 +19,7 @@ from posthog.models.instance_setting import override_instance_config from posthog.queries.paths import Paths, PathsActors from posthog.queries.paths.paths_event_query import PathEventQuery -from posthog.session_recordings.test.test_factory import create_session_recording_events +from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, @@ -3181,23 +3181,21 @@ def test_recording(self): event_uuid="41111111-1111-1111-1111-111111111111", ), ] - create_session_recording_events( - self.team.pk, - timezone.now(), - "p1", - "s1", - window_id="w1", - use_recording_table=False, - use_replay_table=True, - ) - create_session_recording_events( - self.team.pk, - timezone.now(), - "p1", - "s3", - window_id="w3", - use_recording_table=False, - use_replay_table=True, + timestamp = timezone.now() + produce_replay_summary( + team_id=self.team.pk, + session_id="s1", + distinct_id="p1", + first_timestamp=timestamp, + last_timestamp=timestamp, + ) + timestamp1 = timezone.now() + produce_replay_summary( + team_id=self.team.pk, + session_id="s3", + distinct_id="p1", + first_timestamp=timestamp1, + last_timestamp=timestamp1, ) # User with path matches, but no recordings @@ -3328,14 +3326,13 @@ def test_recording_with_start_and_end(self): event_uuid="31111111-1111-1111-1111-111111111111", ), - create_session_recording_events( - self.team.pk, - timezone.now(), - "p1", - "s1", - window_id="w1", - use_recording_table=False, - use_replay_table=True, + timestamp = timezone.now() + produce_replay_summary( + team_id=self.team.pk, + session_id="s1", + distinct_id="p1", + first_timestamp=timestamp, + last_timestamp=timestamp, ) filter = PathFilter( @@ -3400,14 +3397,13 @@ def test_recording_for_dropoff(self): event_uuid="31111111-1111-1111-1111-111111111111", ), - create_session_recording_events( - self.team.pk, - timezone.now(), - "p1", - "s1", - window_id="w1", - use_recording_table=False, - use_replay_table=True, + timestamp = timezone.now() + produce_replay_summary( + team_id=self.team.pk, + session_id="s1", + distinct_id="p1", + first_timestamp=timestamp, + last_timestamp=timestamp, ) # No matching events for dropoff diff --git a/ee/session_recordings/test/test_session_recording_extensions.py b/ee/session_recordings/test/test_session_recording_extensions.py index 4583f7dacdd9e..c71750ed2ab80 100644 --- a/ee/session_recordings/test/test_session_recording_extensions.py +++ b/ee/session_recordings/test/test_session_recording_extensions.py @@ -16,7 +16,6 @@ from posthog.models.signals import mute_selected_signals from posthog.session_recordings.models.session_recording import SessionRecording from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary -from posthog.session_recordings.test.test_factory import create_session_recording_events from posthog.settings import ( OBJECT_STORAGE_ENDPOINT, OBJECT_STORAGE_ACCESS_KEY_ID, @@ -45,33 +44,18 @@ def teardown_method(self, method) -> None: bucket = s3.Bucket(OBJECT_STORAGE_BUCKET) bucket.objects.filter(Prefix=TEST_BUCKET).delete() - def create_snapshot(self, session_id, timestamp): - team_id = self.team.pk - - snapshot = { - "timestamp": timestamp.timestamp() * 1000, - "has_full_snapshot": 1, - "type": 2, - "data": {"source": 0, "href": long_url}, - } - - # can't immediately switch playlists to replay table - create_session_recording_events( - team_id=team_id, - distinct_id="distinct_id_1", - timestamp=timestamp, - session_id=session_id, - window_id="window_1", - snapshots=[snapshot], - use_recording_table=False, - use_replay_table=True, - ) - def test_does_not_persist_too_recent_recording(self): recording = SessionRecording.objects.create( team=self.team, session_id=f"test_does_not_persist_too_recent_recording-s1-{uuid4()}" ) - self.create_snapshot(recording.session_id, recording.created_at) + + produce_replay_summary( + team_id=self.team.pk, + session_id=recording.session_id, + distinct_id="distinct_id_1", + first_timestamp=recording.created_at, + last_timestamp=recording.created_at, + ) persist_recording(recording.session_id, recording.team_id) recording.refresh_from_db() diff --git a/ee/session_recordings/test/test_session_recording_playlist.py b/ee/session_recordings/test/test_session_recording_playlist.py index aab8f992d766b..9323bcc3570bf 100644 --- a/ee/session_recordings/test/test_session_recording_playlist.py +++ b/ee/session_recordings/test/test_session_recording_playlist.py @@ -14,7 +14,7 @@ from posthog.models import SessionRecording, SessionRecordingPlaylistItem from posthog.session_recordings.models.session_recording_playlist import SessionRecordingPlaylist from posthog.models.user import User -from posthog.session_recordings.test.test_factory import create_session_recording_events +from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary from posthog.settings import ( OBJECT_STORAGE_ENDPOINT, OBJECT_STORAGE_ACCESS_KEY_ID, @@ -176,20 +176,20 @@ def test_get_pinned_recordings_for_playlist(self, mock_copy_objects: MagicMock) session_two = f"test_fetch_playlist_recordings-session2-{uuid4()}" three_days_ago = (datetime.now() - timedelta(days=3)).replace(tzinfo=timezone.utc) - create_session_recording_events( + produce_replay_summary( team_id=self.team.id, - distinct_id="123", - timestamp=three_days_ago, session_id=session_one, - window_id="1234", + distinct_id="123", + first_timestamp=three_days_ago, + last_timestamp=three_days_ago, ) - create_session_recording_events( + produce_replay_summary( team_id=self.team.id, - distinct_id="123", - timestamp=three_days_ago, session_id=session_two, - window_id="1234", + distinct_id="123", + first_timestamp=three_days_ago, + last_timestamp=three_days_ago, ) # Create playlist items @@ -233,12 +233,12 @@ def test_fetch_playlist_recordings(self, mock_copy_objects: MagicMock, mock_list for id in [session_one, session_two]: # can't immediately switch playlists to replay table - create_session_recording_events( + produce_replay_summary( team_id=self.team.id, - distinct_id="123", - timestamp=three_days_ago, session_id=id, - window_id="1234", + distinct_id="123", + first_timestamp=three_days_ago, + last_timestamp=three_days_ago, ) self.client.post( diff --git a/posthog/api/test/test_persons_trends.py b/posthog/api/test/test_persons_trends.py index e5594673296c2..46e72c5651bec 100644 --- a/posthog/api/test/test_persons_trends.py +++ b/posthog/api/test/test_persons_trends.py @@ -5,7 +5,7 @@ from posthog.constants import ENTITY_ID, ENTITY_MATH, ENTITY_TYPE, TRENDS_CUMULATIVE from posthog.models import Action, ActionStep, Cohort, Organization -from posthog.session_recordings.test.test_factory import create_session_recording_events +from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, @@ -813,13 +813,13 @@ def test_trends_people_endpoint_includes_recordings(self): timestamp="2020-01-09T12:00:00Z", properties={"$session_id": "s1", "$window_id": "w1"}, ) - create_session_recording_events( - self.team.pk, - datetime(2020, 1, 9, 12), - "u1", - "s1", - use_recording_table=False, - use_replay_table=True, + timestamp = datetime(2020, 1, 9, 12) + produce_replay_summary( + team_id=self.team.pk, + session_id="s1", + distinct_id="u1", + first_timestamp=timestamp, + last_timestamp=timestamp, ) people = self.client.get( diff --git a/posthog/demo/legacy/data_generator.py b/posthog/demo/legacy/data_generator.py index 375805764a51b..65bdd350acc88 100644 --- a/posthog/demo/legacy/data_generator.py +++ b/posthog/demo/legacy/data_generator.py @@ -3,7 +3,7 @@ from posthog.models import Person, PersonDistinctId, Team from posthog.models.utils import UUIDT -from posthog.session_recordings.test.test_factory import create_session_recording_events +from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary class DataGenerator: @@ -72,13 +72,15 @@ def bulk_import_events(self): for event_data in self.events: create_event(**event_data, team=self.team, event_uuid=uuid4()) for data in self.snapshots: - create_session_recording_events( + timestamp = data["timestamp"] + distinct_id = data["distinct_id"] + session_id = data["session_id"] + produce_replay_summary( team_id=self.team.pk, - timestamp=data["timestamp"], - distinct_id=data["distinct_id"], - session_id=data["session_id"], - window_id=data["window_id"], - snapshots=[data["snapshot_data"]], + session_id=session_id, + distinct_id=distinct_id, + first_timestamp=timestamp, + last_timestamp=timestamp, ) def add_if_not_contained(self, array, value): diff --git a/posthog/queries/funnels/test/test_funnel_persons.py b/posthog/queries/funnels/test/test_funnel_persons.py index fa8d5cbeeef7e..8f8ed2b638f67 100644 --- a/posthog/queries/funnels/test/test_funnel_persons.py +++ b/posthog/queries/funnels/test/test_funnel_persons.py @@ -9,7 +9,7 @@ from posthog.models.event.util import bulk_create_events from posthog.models.person.util import bulk_create_persons from posthog.queries.funnels.funnel_persons import ClickhouseFunnelActors -from posthog.session_recordings.test.test_factory import create_session_recording_events +from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, @@ -443,7 +443,14 @@ def test_funnel_person_recordings(self): properties={"$session_id": "s2", "$window_id": "w2"}, event_uuid="21111111-1111-1111-1111-111111111111", ) - create_session_recording_events(self.team.pk, datetime(2021, 1, 3, 0, 0, 0), "user_1", "s2") + timestamp = datetime(2021, 1, 3, 0, 0, 0) + produce_replay_summary( + team_id=self.team.pk, + session_id="s2", + distinct_id="user_1", + first_timestamp=timestamp, + last_timestamp=timestamp, + ) # First event, but no recording filter = Filter( diff --git a/posthog/queries/funnels/test/test_funnel_strict_persons.py b/posthog/queries/funnels/test/test_funnel_strict_persons.py index a1abbbb03139a..9c9a304a59e8f 100644 --- a/posthog/queries/funnels/test/test_funnel_strict_persons.py +++ b/posthog/queries/funnels/test/test_funnel_strict_persons.py @@ -7,7 +7,7 @@ from posthog.constants import INSIGHT_FUNNELS from posthog.models.filters import Filter from posthog.queries.funnels.funnel_strict_persons import ClickhouseFunnelStrictActors -from posthog.session_recordings.test.test_factory import create_session_recording_events +from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, @@ -154,11 +154,13 @@ def test_strict_funnel_person_recordings(self): properties={"$session_id": "s2", "$window_id": "w2"}, event_uuid="21111111-1111-1111-1111-111111111111", ) - create_session_recording_events( - self.team.pk, - datetime(2021, 1, 3, 0, 0, 0), - "user_1", - "s2", + timestamp = datetime(2021, 1, 3, 0, 0, 0) + produce_replay_summary( + team_id=self.team.pk, + session_id="s2", + distinct_id="user_1", + first_timestamp=timestamp, + last_timestamp=timestamp, ) # First event, but no recording diff --git a/posthog/queries/funnels/test/test_funnel_trends_persons.py b/posthog/queries/funnels/test/test_funnel_trends_persons.py index 5f0ec37832137..ee75bfb025719 100644 --- a/posthog/queries/funnels/test/test_funnel_trends_persons.py +++ b/posthog/queries/funnels/test/test_funnel_trends_persons.py @@ -3,7 +3,7 @@ from posthog.constants import INSIGHT_FUNNELS, FunnelVizType from posthog.models.filters import Filter from posthog.queries.funnels.funnel_trends_persons import ClickhouseFunnelTrendsActors -from posthog.session_recordings.test.test_factory import create_session_recording_events +from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary from posthog.test.base import APIBaseTest, ClickhouseTestMixin, snapshot_clickhouse_queries from posthog.test.test_journeys import journeys_for @@ -35,7 +35,14 @@ def test_funnel_trend_persons_returns_recordings(self): }, self.team, ) - create_session_recording_events(self.team.pk, datetime(2021, 5, 1), "user_one", "s1b") + timestamp = datetime(2021, 5, 1) + produce_replay_summary( + team_id=self.team.pk, + session_id="s1b", + distinct_id="user_one", + first_timestamp=timestamp, + last_timestamp=timestamp, + ) filter = Filter(data={"funnel_to_step": 1, **filter_data}) _, results, _ = ClickhouseFunnelTrendsActors(filter, self.team).get_actors() @@ -55,7 +62,14 @@ def test_funnel_trend_persons_with_no_to_step(self): self.team, ) # the session recording can start a little before the events in the funnel - create_session_recording_events(self.team.pk, datetime(2021, 5, 1) - timedelta(hours=12), "user_one", "s1c") + timestamp = datetime(2021, 5, 1) - timedelta(hours=12) + produce_replay_summary( + team_id=self.team.pk, + session_id="s1c", + distinct_id="user_one", + first_timestamp=timestamp, + last_timestamp=timestamp, + ) filter = Filter(data=filter_data) _, results, _ = ClickhouseFunnelTrendsActors(filter, self.team).get_actors() @@ -72,7 +86,14 @@ def test_funnel_trend_persons_with_drop_off(self): }, self.team, ) - create_session_recording_events(self.team.pk, datetime(2021, 5, 1), "user_one", "s1a") + timestamp = datetime(2021, 5, 1) + produce_replay_summary( + team_id=self.team.pk, + session_id="s1a", + distinct_id="user_one", + first_timestamp=timestamp, + last_timestamp=timestamp, + ) filter = Filter(data={**filter_data, "drop_off": True}) _, results, _ = ClickhouseFunnelTrendsActors(filter, self.team).get_actors() diff --git a/posthog/queries/funnels/test/test_funnel_unordered_persons.py b/posthog/queries/funnels/test/test_funnel_unordered_persons.py index d34c51e4a1706..673dee6d30826 100644 --- a/posthog/queries/funnels/test/test_funnel_unordered_persons.py +++ b/posthog/queries/funnels/test/test_funnel_unordered_persons.py @@ -7,7 +7,7 @@ from posthog.constants import INSIGHT_FUNNELS from posthog.models.filters import Filter from posthog.queries.funnels.funnel_unordered_persons import ClickhouseFunnelUnorderedActors -from posthog.session_recordings.test.test_factory import create_session_recording_events +from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, @@ -160,7 +160,14 @@ def test_unordered_funnel_does_not_return_recordings(self): event_uuid="11111111-1111-1111-1111-111111111111", ) - create_session_recording_events(self.team.pk, timezone.now() + timedelta(days=1), "user_1", "s1") + timestamp = timezone.now() + timedelta(days=1) + produce_replay_summary( + team_id=self.team.pk, + session_id="s1", + distinct_id="user_1", + first_timestamp=timestamp, + last_timestamp=timestamp, + ) filter = Filter( data={ diff --git a/posthog/queries/trends/test/test_person.py b/posthog/queries/trends/test/test_person.py index f68a4ed13b9bd..bfd18b6ed8de8 100644 --- a/posthog/queries/trends/test/test_person.py +++ b/posthog/queries/trends/test/test_person.py @@ -12,7 +12,7 @@ from posthog.models.group.util import create_group from posthog.models.group_type_mapping import GroupTypeMapping from posthog.queries.trends.trends_actors import TrendsActors -from posthog.session_recordings.test.test_factory import create_session_recording_events +from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, @@ -39,7 +39,14 @@ def test_person_query_includes_recording_events(self): timestamp=timezone.now(), properties={"$session_id": "s2", "$window_id": "w2"}, ) # No associated recording, so not included - create_session_recording_events(self.team.pk, timezone.now(), "u1", "s1") + timestamp = timezone.now() + produce_replay_summary( + team_id=self.team.pk, + session_id="s1", + distinct_id="u1", + first_timestamp=timestamp, + last_timestamp=timestamp, + ) _create_event( event="pageview", @@ -108,7 +115,14 @@ def test_person_query_does_not_include_recording_events_if_flag_not_set(self): def test_group_query_includes_recording_events(self): GroupTypeMapping.objects.create(team=self.team, group_type="organization", group_type_index=0) create_group(team_id=self.team.pk, group_type_index=0, group_key="bla", properties={}) - create_session_recording_events(self.team.pk, timezone.now(), "u1", "s1") + timestamp = timezone.now() + produce_replay_summary( + team_id=self.team.pk, + session_id="s1", + distinct_id="u1", + first_timestamp=timestamp, + last_timestamp=timestamp, + ) _create_event( event="pageview", distinct_id="u1", team=self.team, timestamp=timezone.now(), properties={"$group_0": "bla"} diff --git a/posthog/session_recordings/queries/test/test_session_recording_properties.py b/posthog/session_recordings/queries/test/test_session_recording_properties.py index 387d41bbe1ebc..9844d77006721 100644 --- a/posthog/session_recordings/queries/test/test_session_recording_properties.py +++ b/posthog/session_recordings/queries/test/test_session_recording_properties.py @@ -5,7 +5,7 @@ from posthog.models import Person from posthog.models.filters.session_recordings_filter import SessionRecordingsFilter from posthog.session_recordings.queries.session_recording_properties import SessionRecordingProperties -from posthog.session_recordings.test.test_factory import create_snapshot +from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary from posthog.test.base import BaseTest, ClickhouseTestMixin, _create_event, snapshot_clickhouse_queries @@ -30,8 +30,20 @@ def base_time(self): @snapshot_clickhouse_queries def test_properties_list(self): Person.objects.create(team=self.team, distinct_ids=["user"], properties={"email": "bla"}) - create_snapshot(distinct_id="user", session_id="1", timestamp=self.base_time, team_id=self.team.id) - create_snapshot(distinct_id="user", session_id="2", timestamp=self.base_time, team_id=self.team.id) + produce_replay_summary( + team_id=self.team.id, + session_id="1", + distinct_id="user", + first_timestamp=self.base_time, + last_timestamp=self.base_time, + ) + produce_replay_summary( + team_id=self.team.id, + session_id="2", + distinct_id="user", + first_timestamp=self.base_time, + last_timestamp=self.base_time, + ) event_props = { "$session_id": "1", diff --git a/posthog/session_recordings/test/test_factory.py b/posthog/session_recordings/test/test_factory.py deleted file mode 100644 index 195286683d0de..0000000000000 --- a/posthog/session_recordings/test/test_factory.py +++ /dev/null @@ -1,180 +0,0 @@ -import json -from datetime import datetime, timedelta -from typing import Dict, List, Optional -from uuid import uuid4 - -import structlog - -from posthog.client import sync_execute -from posthog.kafka_client.client import ClickhouseProducer -from posthog.kafka_client.topics import KAFKA_CLICKHOUSE_SESSION_RECORDING_EVENTS -from posthog.session_recordings.sql.session_recording_event_sql import INSERT_SESSION_RECORDING_EVENT_SQL -from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary -from posthog.session_recordings.session_recording_helpers import ( - RRWEB_MAP_EVENT_TYPE, -) -from posthog.utils import cast_timestamp_or_now - -logger = structlog.get_logger(__name__) - -MAX_KAFKA_MESSAGE_LENGTH = 800_000 -MAX_INSERT_LENGTH = 15_000_000 - - -def _insert_session_recording_event( - team_id: int, - distinct_id: str, - session_id: str, - window_id: str, - timestamp: datetime, - snapshot_data: dict, -) -> str: - uuid = uuid4() - snapshot_data_json = json.dumps(snapshot_data) - timestamp_str = cast_timestamp_or_now(timestamp) - data = { - "uuid": str(uuid), - "team_id": team_id, - "distinct_id": distinct_id, - "session_id": session_id, - "window_id": window_id, - "snapshot_data": snapshot_data_json, - "timestamp": timestamp_str, - "created_at": timestamp_str, - } - if len(snapshot_data_json) <= MAX_KAFKA_MESSAGE_LENGTH: - p = ClickhouseProducer() - p.produce(sql=INSERT_SESSION_RECORDING_EVENT_SQL(), topic=KAFKA_CLICKHOUSE_SESSION_RECORDING_EVENTS, data=data) - elif len(snapshot_data_json) <= MAX_INSERT_LENGTH: - sync_execute(INSERT_SESSION_RECORDING_EVENT_SQL(), data, settings={"max_query_size": MAX_INSERT_LENGTH}) - - return str(uuid) - - -def create_session_recording_events( - team_id: int, - timestamp: datetime, - distinct_id: str, - session_id: str, - window_id: Optional[str] = None, - # If not given we will create a mock full snapshot - snapshots: Optional[List[dict]] = None, - chunk_size: Optional[int] = 512 * 1024, - use_replay_table: bool = True, - use_recording_table: bool = False, -) -> None: - if use_replay_table: - produce_replay_summary( - team_id=team_id, - session_id=session_id, - distinct_id=distinct_id, - first_timestamp=timestamp, - last_timestamp=timestamp, - ) - - -# Pre-compression and events_summary additions which potentially existed for some self-hosted instances -def create_uncompressed_session_recording_event( - team_id: int, - distinct_id: str, - session_id: str, - window_id: str, - timestamp: datetime, - snapshot_data: dict, -) -> str: - return _insert_session_recording_event( - team_id=team_id, - distinct_id=distinct_id, - session_id=session_id, - window_id=window_id, - timestamp=timestamp, - snapshot_data=snapshot_data, - ) - - -def create_snapshot( - session_id: str, - timestamp: datetime, - team_id: int, - distinct_id: Optional[str] = None, - window_id: str = "", - has_full_snapshot: bool = True, - type: Optional[int] = None, - data: Optional[Dict] = None, - use_replay_table=True, - use_recording_table=False, -) -> None: - if not data: - data = {"source": 0} - - snapshot_data = { - "data": {**data}, - "timestamp": round(timestamp.timestamp() * 1000), # NOTE: rrweb timestamps are milliseconds - "type": type - or (RRWEB_MAP_EVENT_TYPE.FullSnapshot if has_full_snapshot else RRWEB_MAP_EVENT_TYPE.IncrementalSnapshot), - } - - create_session_recording_events( - team_id=team_id, - timestamp=timestamp, - distinct_id=distinct_id if distinct_id else str(uuid4()), - session_id=session_id, - window_id=window_id, - snapshots=[snapshot_data], - use_recording_table=use_recording_table, - use_replay_table=use_replay_table, - ) - - -def create_snapshots( - snapshot_count: int, - distinct_id: str, - session_id: str, - timestamp: datetime, - team_id: int, - window_id: str = "", - has_full_snapshot: bool = True, - source: int = 0, - chunk_size: Optional[int] = 512 * 1024, - use_replay_table=True, - use_recording_table=False, -): - snapshots = [] - for index in range(snapshot_count): - snapshots.append( - { - "type": 2 if has_full_snapshot else 3, - "data": { - "source": source, - "texts": [], - "attributes": [], - "removes": [], - "adds": [ - { - "parentId": 4, - "nextId": 386, - "node": { - "type": 2, - "tagName": "style", - "attributes": {"data-emotion": "css"}, - "childNodes": [], - "id": 729, - }, - } - ], - }, - "timestamp": (timestamp + timedelta(seconds=index)).timestamp() * 1000, - }, - ) - - return create_session_recording_events( - team_id=team_id, - timestamp=timestamp, - distinct_id=distinct_id, - session_id=session_id, - window_id=window_id, - snapshots=snapshots, - chunk_size=chunk_size, - use_recording_table=use_recording_table, - use_replay_table=use_replay_table, - ) diff --git a/posthog/session_recordings/test/test_session_recordings.py b/posthog/session_recordings/test/test_session_recordings.py index a67b611361f40..61c05d993ee4a 100644 --- a/posthog/session_recordings/test/test_session_recordings.py +++ b/posthog/session_recordings/test/test_session_recordings.py @@ -19,7 +19,6 @@ from posthog.models.filters.session_recordings_filter import SessionRecordingsFilter from posthog.models.team import Team from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary -from posthog.session_recordings.test.test_factory import create_session_recording_events from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, @@ -66,15 +65,12 @@ def create_snapshot( if snapshot_data: snapshot.update(snapshot_data) - create_session_recording_events( + produce_replay_summary( team_id=team_id, - distinct_id=distinct_id, - timestamp=timestamp, session_id=session_id, - window_id=window_id, - snapshots=[snapshot], - use_replay_table=use_replay_table, - use_recording_table=use_recording_table, + distinct_id=distinct_id, + first_timestamp=timestamp, + last_timestamp=timestamp, ) def create_snapshots( @@ -116,15 +112,12 @@ def create_snapshots( } ) - create_session_recording_events( + produce_replay_summary( team_id=self.team.pk, - distinct_id=distinct_id, - timestamp=timestamp, session_id=session_id, - window_id=window_id, - snapshots=snapshots, - use_replay_table=use_replay_table, - use_recording_table=use_recording_table, + distinct_id=distinct_id, + first_timestamp=timestamp, + last_timestamp=timestamp, ) def test_get_session_recordings(self): diff --git a/posthog/tasks/test/test_usage_report.py b/posthog/tasks/test/test_usage_report.py index 491d50c0bb57a..fa49c1f47e457 100644 --- a/posthog/tasks/test/test_usage_report.py +++ b/posthog/tasks/test/test_usage_report.py @@ -27,7 +27,7 @@ from posthog.models.plugin import PluginConfig from posthog.models.sharing_configuration import SharingConfiguration from posthog.schema import EventsQuery -from posthog.session_recordings.test.test_factory import create_snapshot +from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary from posthog.tasks.usage_report import ( _get_all_org_reports, _get_all_usage_data_as_team_rows, @@ -225,49 +225,55 @@ def _create_sample_usage_data(self) -> None: # recordings in period - 5 sessions with 5 snapshots each for i in range(1, 6): for _ in range(0, 5): - create_snapshot( - has_full_snapshot=True, - distinct_id=distinct_id, - session_id=str(i), - timestamp=now() - relativedelta(hours=12), + session_id = str(i) + timestamp = now() - relativedelta(hours=12) + produce_replay_summary( team_id=self.org_1_team_2.id, + session_id=session_id, + distinct_id=distinct_id, + first_timestamp=timestamp, + last_timestamp=timestamp, ) # recordings out of period - 5 sessions with 5 snapshots each for i in range(1, 11): for _ in range(0, 5): - create_snapshot( - has_full_snapshot=True, - distinct_id=distinct_id, - session_id=str(i + 10), - timestamp=now() - relativedelta(hours=48), + id1 = str(i + 10) + timestamp1 = now() - relativedelta(hours=48) + produce_replay_summary( team_id=self.org_1_team_2.id, + session_id=id1, + distinct_id=distinct_id, + first_timestamp=timestamp1, + last_timestamp=timestamp1, ) # ensure there is a recording that starts before the period and ends during the period # report is going to be for "yesterday" relative to the test so... start_of_day = datetime.combine(now().date(), datetime.min.time()) - relativedelta(days=1) session_that_will_not_match = "session-that-will-not-match-because-it-starts-before-the-period" - create_snapshot( - has_full_snapshot=True, - distinct_id=distinct_id, - session_id=session_that_will_not_match, - timestamp=start_of_day - relativedelta(hours=1), + timestamp2 = start_of_day - relativedelta(hours=1) + produce_replay_summary( team_id=self.org_1_team_2.id, - ) - create_snapshot( - has_full_snapshot=False, - distinct_id=distinct_id, session_id=session_that_will_not_match, - timestamp=start_of_day, - team_id=self.org_1_team_2.id, - ) - create_snapshot( - has_full_snapshot=False, distinct_id=distinct_id, + first_timestamp=timestamp2, + last_timestamp=timestamp2, + ) + produce_replay_summary( + team_id=self.org_1_team_2.id, session_id=session_that_will_not_match, - timestamp=start_of_day + relativedelta(hours=1), + distinct_id=distinct_id, + first_timestamp=start_of_day, + last_timestamp=start_of_day, + ) + timestamp3 = start_of_day + relativedelta(hours=1) + produce_replay_summary( team_id=self.org_1_team_2.id, + session_id=session_that_will_not_match, + distinct_id=distinct_id, + first_timestamp=timestamp3, + last_timestamp=timestamp3, ) _create_event( distinct_id=distinct_id, From 26a76400650934a50e746b61b3fadc1e6584c20b Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Wed, 11 Oct 2023 12:24:39 +0100 Subject: [PATCH 40/41] fix --- .../test/test_session_recording_playlist.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ee/session_recordings/test/test_session_recording_playlist.py b/ee/session_recordings/test/test_session_recording_playlist.py index 9323bcc3570bf..0881f47697e99 100644 --- a/ee/session_recordings/test/test_session_recording_playlist.py +++ b/ee/session_recordings/test/test_session_recording_playlist.py @@ -231,11 +231,10 @@ def test_fetch_playlist_recordings(self, mock_copy_objects: MagicMock, mock_list session_two = f"test_fetch_playlist_recordings-session2-{uuid4()}" three_days_ago = (datetime.now() - timedelta(days=3)).replace(tzinfo=timezone.utc) - for id in [session_one, session_two]: - # can't immediately switch playlists to replay table + for session_id in [session_one, session_two]: produce_replay_summary( team_id=self.team.id, - session_id=id, + session_id=session_id, distinct_id="123", first_timestamp=three_days_ago, last_timestamp=three_days_ago, From b1e1fe76149a567cd10a59d850351e4233760921 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Wed, 11 Oct 2023 13:06:43 +0100 Subject: [PATCH 41/41] snapshot --- .../test_session_recordings.ambr | 1848 +++++------------ 1 file changed, 510 insertions(+), 1338 deletions(-) diff --git a/posthog/session_recordings/test/__snapshots__/test_session_recordings.ambr b/posthog/session_recordings/test/__snapshots__/test_session_recordings.ambr index 6132a8cfcb66d..5b68085b545af 100644 --- a/posthog/session_recordings/test/__snapshots__/test_session_recordings.ambr +++ b/posthog/session_recordings/test/__snapshots__/test_session_recordings.ambr @@ -84,179 +84,6 @@ ' --- # name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.100 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.101 - ' - SELECT "posthog_sessionrecording"."id", - "posthog_sessionrecording"."session_id", - "posthog_sessionrecording"."team_id", - "posthog_sessionrecording"."created_at", - "posthog_sessionrecording"."deleted", - "posthog_sessionrecording"."object_storage_path", - "posthog_sessionrecording"."distinct_id", - "posthog_sessionrecording"."duration", - "posthog_sessionrecording"."active_seconds", - "posthog_sessionrecording"."inactive_seconds", - "posthog_sessionrecording"."start_time", - "posthog_sessionrecording"."end_time", - "posthog_sessionrecording"."click_count", - "posthog_sessionrecording"."keypress_count", - "posthog_sessionrecording"."mouse_activity_count", - "posthog_sessionrecording"."console_log_count", - "posthog_sessionrecording"."console_warn_count", - "posthog_sessionrecording"."console_error_count", - "posthog_sessionrecording"."start_url", - "posthog_sessionrecording"."storage_version" - FROM "posthog_sessionrecording" - WHERE ("posthog_sessionrecording"."session_id" IN ('1', - '2', - '3', - '4', - '5') - AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.102 - ' - SELECT "posthog_sessionrecordingviewed"."session_id" - FROM "posthog_sessionrecordingviewed" - WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 - AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.103 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version", - "posthog_person"."id", - "posthog_person"."created_at", - "posthog_person"."properties_last_updated_at", - "posthog_person"."properties_last_operation", - "posthog_person"."team_id", - "posthog_person"."properties", - "posthog_person"."is_user_id", - "posthog_person"."is_identified", - "posthog_person"."uuid", - "posthog_person"."version" - FROM "posthog_persondistinctid" - INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") - WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', - 'user2', - 'user3', - 'user4', - 'user5') - AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.104 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version" - FROM "posthog_persondistinctid" - WHERE "posthog_persondistinctid"."person_id" IN (1, - 2, - 3, - 4, - 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.105 - ' - SELECT "posthog_team"."id", - "posthog_team"."uuid", - "posthog_team"."organization_id", - "posthog_team"."api_token", - "posthog_team"."app_urls", - "posthog_team"."name", - "posthog_team"."slack_incoming_webhook", - "posthog_team"."created_at", - "posthog_team"."updated_at", - "posthog_team"."anonymize_ips", - "posthog_team"."completed_snippet_onboarding", - "posthog_team"."has_completed_onboarding_for", - "posthog_team"."ingested_event", - "posthog_team"."autocapture_opt_out", - "posthog_team"."autocapture_exceptions_opt_in", - "posthog_team"."autocapture_exceptions_errors_to_ignore", - "posthog_team"."session_recording_opt_in", - "posthog_team"."capture_console_log_opt_in", - "posthog_team"."capture_performance_opt_in", - "posthog_team"."surveys_opt_in", - "posthog_team"."session_recording_version", - "posthog_team"."signup_token", - "posthog_team"."is_demo", - "posthog_team"."access_control", - "posthog_team"."week_start_day", - "posthog_team"."inject_web_apps", - "posthog_team"."test_account_filters", - "posthog_team"."test_account_filters_default_checked", - "posthog_team"."path_cleaning_filters", - "posthog_team"."timezone", - "posthog_team"."data_attributes", - "posthog_team"."person_display_name_properties", - "posthog_team"."live_events_columns", - "posthog_team"."recording_domains", - "posthog_team"."primary_dashboard_id", - "posthog_team"."extra_settings", - "posthog_team"."correlation_config", - "posthog_team"."session_recording_retention_period_days", - "posthog_team"."plugins_opt_in", - "posthog_team"."opt_out_capture", - "posthog_team"."event_names", - "posthog_team"."event_names_with_usage", - "posthog_team"."event_properties", - "posthog_team"."event_properties_with_usage", - "posthog_team"."event_properties_numerical" - FROM "posthog_team" - WHERE "posthog_team"."id" = 2 - LIMIT 21 - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.106 - ' - SELECT "posthog_user"."id", - "posthog_user"."password", - "posthog_user"."last_login", - "posthog_user"."first_name", - "posthog_user"."last_name", - "posthog_user"."is_staff", - "posthog_user"."is_active", - "posthog_user"."date_joined", - "posthog_user"."uuid", - "posthog_user"."current_organization_id", - "posthog_user"."current_team_id", - "posthog_user"."email", - "posthog_user"."pending_email", - "posthog_user"."temporary_token", - "posthog_user"."distinct_id", - "posthog_user"."is_email_verified", - "posthog_user"."has_seen_product_intro_for", - "posthog_user"."email_opt_in", - "posthog_user"."partial_notification_settings", - "posthog_user"."anonymize_data", - "posthog_user"."toolbar_mode", - "posthog_user"."events_column_config" - FROM "posthog_user" - WHERE "posthog_user"."id" = 2 - LIMIT 21 /**/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.107 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -301,7 +128,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.108 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.101 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -330,7 +157,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.109 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.102 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -341,18 +168,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.11 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.110 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.103 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -363,7 +179,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.111 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.104 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -374,7 +190,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.112 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.105 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -385,7 +201,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.113 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.106 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -396,7 +212,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.114 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.107 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -407,7 +223,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.115 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.108 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -418,7 +234,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.116 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.109 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -429,18 +245,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.117 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.11 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RECORDINGS_TTL_WEEKS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.118 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.110 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -451,39 +267,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.119 - ' - SELECT "posthog_sessionrecording"."id", - "posthog_sessionrecording"."session_id", - "posthog_sessionrecording"."team_id", - "posthog_sessionrecording"."created_at", - "posthog_sessionrecording"."deleted", - "posthog_sessionrecording"."object_storage_path", - "posthog_sessionrecording"."distinct_id", - "posthog_sessionrecording"."duration", - "posthog_sessionrecording"."active_seconds", - "posthog_sessionrecording"."inactive_seconds", - "posthog_sessionrecording"."start_time", - "posthog_sessionrecording"."end_time", - "posthog_sessionrecording"."click_count", - "posthog_sessionrecording"."keypress_count", - "posthog_sessionrecording"."mouse_activity_count", - "posthog_sessionrecording"."console_log_count", - "posthog_sessionrecording"."console_warn_count", - "posthog_sessionrecording"."console_error_count", - "posthog_sessionrecording"."start_url", - "posthog_sessionrecording"."storage_version" - FROM "posthog_sessionrecording" - WHERE ("posthog_sessionrecording"."session_id" IN ('1', - '2', - '3', - '4', - '5', - '6') - AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.12 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.111 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -494,58 +278,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.120 - ' - SELECT "posthog_sessionrecordingviewed"."session_id" - FROM "posthog_sessionrecordingviewed" - WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 - AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.121 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version", - "posthog_person"."id", - "posthog_person"."created_at", - "posthog_person"."properties_last_updated_at", - "posthog_person"."properties_last_operation", - "posthog_person"."team_id", - "posthog_person"."properties", - "posthog_person"."is_user_id", - "posthog_person"."is_identified", - "posthog_person"."uuid", - "posthog_person"."version" - FROM "posthog_persondistinctid" - INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") - WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', - 'user2', - 'user3', - 'user4', - 'user5', - 'user6') - AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.122 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version" - FROM "posthog_persondistinctid" - WHERE "posthog_persondistinctid"."person_id" IN (1, - 2, - 3, - 4, - 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.123 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.112 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -597,7 +330,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.124 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.113 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -626,7 +359,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.125 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.114 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -671,7 +404,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.126 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.115 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -700,7 +433,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.127 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.116 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -711,7 +444,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.128 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.117 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -722,7 +455,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.129 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.118 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -733,29 +466,29 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.13 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.119 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.130 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.12 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.131 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.120 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -766,7 +499,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.132 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.121 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -777,7 +510,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.133 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.122 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -788,7 +521,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.134 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.123 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -799,7 +532,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.135 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.124 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -810,7 +543,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.136 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.125 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -821,100 +554,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.137 - ' - SELECT "posthog_sessionrecording"."id", - "posthog_sessionrecording"."session_id", - "posthog_sessionrecording"."team_id", - "posthog_sessionrecording"."created_at", - "posthog_sessionrecording"."deleted", - "posthog_sessionrecording"."object_storage_path", - "posthog_sessionrecording"."distinct_id", - "posthog_sessionrecording"."duration", - "posthog_sessionrecording"."active_seconds", - "posthog_sessionrecording"."inactive_seconds", - "posthog_sessionrecording"."start_time", - "posthog_sessionrecording"."end_time", - "posthog_sessionrecording"."click_count", - "posthog_sessionrecording"."keypress_count", - "posthog_sessionrecording"."mouse_activity_count", - "posthog_sessionrecording"."console_log_count", - "posthog_sessionrecording"."console_warn_count", - "posthog_sessionrecording"."console_error_count", - "posthog_sessionrecording"."start_url", - "posthog_sessionrecording"."storage_version" - FROM "posthog_sessionrecording" - WHERE ("posthog_sessionrecording"."session_id" IN ('1', - '2', - '3', - '4', - '5', - '6', - '7') - AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.138 - ' - SELECT "posthog_sessionrecordingviewed"."session_id" - FROM "posthog_sessionrecordingviewed" - WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 - AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.139 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version", - "posthog_person"."id", - "posthog_person"."created_at", - "posthog_person"."properties_last_updated_at", - "posthog_person"."properties_last_operation", - "posthog_person"."team_id", - "posthog_person"."properties", - "posthog_person"."is_user_id", - "posthog_person"."is_identified", - "posthog_person"."uuid", - "posthog_person"."version" - FROM "posthog_persondistinctid" - INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") - WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', - 'user2', - 'user3', - 'user4', - 'user5', - 'user6', - 'user7') - AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.14 - ' - SELECT "posthog_sessionrecordingviewed"."session_id" - FROM "posthog_sessionrecordingviewed" - WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 - AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.140 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version" - FROM "posthog_persondistinctid" - WHERE "posthog_persondistinctid"."person_id" IN (1, - 2, - 3, - 4, - 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.141 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.126 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -966,7 +606,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.142 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.127 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -995,7 +635,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.143 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.128 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1040,7 +680,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.144 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.129 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -1069,7 +709,18 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.145 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.13 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.130 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1080,7 +731,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.146 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.131 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1091,7 +742,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.147 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.132 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1102,7 +753,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.148 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.133 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1113,7 +764,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.149 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.134 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1124,59 +775,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.15 - ' - SELECT "posthog_team"."id", - "posthog_team"."uuid", - "posthog_team"."organization_id", - "posthog_team"."api_token", - "posthog_team"."app_urls", - "posthog_team"."name", - "posthog_team"."slack_incoming_webhook", - "posthog_team"."created_at", - "posthog_team"."updated_at", - "posthog_team"."anonymize_ips", - "posthog_team"."completed_snippet_onboarding", - "posthog_team"."has_completed_onboarding_for", - "posthog_team"."ingested_event", - "posthog_team"."autocapture_opt_out", - "posthog_team"."autocapture_exceptions_opt_in", - "posthog_team"."autocapture_exceptions_errors_to_ignore", - "posthog_team"."session_recording_opt_in", - "posthog_team"."capture_console_log_opt_in", - "posthog_team"."capture_performance_opt_in", - "posthog_team"."surveys_opt_in", - "posthog_team"."session_recording_version", - "posthog_team"."signup_token", - "posthog_team"."is_demo", - "posthog_team"."access_control", - "posthog_team"."week_start_day", - "posthog_team"."inject_web_apps", - "posthog_team"."test_account_filters", - "posthog_team"."test_account_filters_default_checked", - "posthog_team"."path_cleaning_filters", - "posthog_team"."timezone", - "posthog_team"."data_attributes", - "posthog_team"."person_display_name_properties", - "posthog_team"."live_events_columns", - "posthog_team"."recording_domains", - "posthog_team"."primary_dashboard_id", - "posthog_team"."extra_settings", - "posthog_team"."correlation_config", - "posthog_team"."session_recording_retention_period_days", - "posthog_team"."plugins_opt_in", - "posthog_team"."opt_out_capture", - "posthog_team"."event_names", - "posthog_team"."event_names_with_usage", - "posthog_team"."event_properties", - "posthog_team"."event_properties_with_usage", - "posthog_team"."event_properties_numerical" - FROM "posthog_team" - WHERE "posthog_team"."id" = 2 - LIMIT 21 - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.150 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.135 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1187,7 +786,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.151 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.136 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1198,7 +797,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.152 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.137 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1209,7 +808,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.153 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.138 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1220,7 +819,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.154 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.139 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1231,94 +830,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.155 - ' - SELECT "posthog_sessionrecording"."id", - "posthog_sessionrecording"."session_id", - "posthog_sessionrecording"."team_id", - "posthog_sessionrecording"."created_at", - "posthog_sessionrecording"."deleted", - "posthog_sessionrecording"."object_storage_path", - "posthog_sessionrecording"."distinct_id", - "posthog_sessionrecording"."duration", - "posthog_sessionrecording"."active_seconds", - "posthog_sessionrecording"."inactive_seconds", - "posthog_sessionrecording"."start_time", - "posthog_sessionrecording"."end_time", - "posthog_sessionrecording"."click_count", - "posthog_sessionrecording"."keypress_count", - "posthog_sessionrecording"."mouse_activity_count", - "posthog_sessionrecording"."console_log_count", - "posthog_sessionrecording"."console_warn_count", - "posthog_sessionrecording"."console_error_count", - "posthog_sessionrecording"."start_url", - "posthog_sessionrecording"."storage_version" - FROM "posthog_sessionrecording" - WHERE ("posthog_sessionrecording"."session_id" IN ('1', - '2', - '3', - '4', - '5', - '6', - '7', - '8') - AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.156 - ' - SELECT "posthog_sessionrecordingviewed"."session_id" - FROM "posthog_sessionrecordingviewed" - WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 - AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.157 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version", - "posthog_person"."id", - "posthog_person"."created_at", - "posthog_person"."properties_last_updated_at", - "posthog_person"."properties_last_operation", - "posthog_person"."team_id", - "posthog_person"."properties", - "posthog_person"."is_user_id", - "posthog_person"."is_identified", - "posthog_person"."uuid", - "posthog_person"."version" - FROM "posthog_persondistinctid" - INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") - WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', - 'user2', - 'user3', - 'user4', - 'user5', - 'user6', - 'user7', - 'user8') - AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.158 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version" - FROM "posthog_persondistinctid" - WHERE "posthog_persondistinctid"."person_id" IN (1, - 2, - 3, - 4, - 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.159 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.14 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1370,36 +882,59 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.16 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.140 ' - SELECT "posthog_user"."id", - "posthog_user"."password", - "posthog_user"."last_login", - "posthog_user"."first_name", - "posthog_user"."last_name", - "posthog_user"."is_staff", - "posthog_user"."is_active", - "posthog_user"."date_joined", - "posthog_user"."uuid", - "posthog_user"."current_organization_id", - "posthog_user"."current_team_id", - "posthog_user"."email", - "posthog_user"."pending_email", - "posthog_user"."temporary_token", - "posthog_user"."distinct_id", - "posthog_user"."is_email_verified", - "posthog_user"."has_seen_product_intro_for", - "posthog_user"."email_opt_in", - "posthog_user"."partial_notification_settings", - "posthog_user"."anonymize_data", - "posthog_user"."toolbar_mode", - "posthog_user"."events_column_config" - FROM "posthog_user" - WHERE "posthog_user"."id" = 2 - LIMIT 21 /**/ + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."surveys_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."plugins_opt_in", + "posthog_team"."opt_out_capture", + "posthog_team"."event_names", + "posthog_team"."event_names_with_usage", + "posthog_team"."event_properties", + "posthog_team"."event_properties_with_usage", + "posthog_team"."event_properties_numerical" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.160 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.141 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -1428,7 +963,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.161 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.142 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1473,7 +1008,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.162 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.143 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -1502,7 +1037,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.163 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.144 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1513,7 +1048,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.164 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.145 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1524,7 +1059,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.165 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.146 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1535,7 +1070,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.166 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.147 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1546,7 +1081,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.167 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.148 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1557,7 +1092,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.168 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.149 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1568,7 +1103,36 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.169 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.15 + ' + SELECT "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."email_opt_in", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."events_column_config" + FROM "posthog_user" + WHERE "posthog_user"."id" = 2 + LIMIT 21 /**/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.150 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1579,52 +1143,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.17 - ' - SELECT "posthog_team"."id", - "posthog_team"."uuid", - "posthog_team"."organization_id", - "posthog_team"."api_token", - "posthog_team"."app_urls", - "posthog_team"."name", - "posthog_team"."slack_incoming_webhook", - "posthog_team"."created_at", - "posthog_team"."updated_at", - "posthog_team"."anonymize_ips", - "posthog_team"."completed_snippet_onboarding", - "posthog_team"."has_completed_onboarding_for", - "posthog_team"."ingested_event", - "posthog_team"."autocapture_opt_out", - "posthog_team"."autocapture_exceptions_opt_in", - "posthog_team"."autocapture_exceptions_errors_to_ignore", - "posthog_team"."session_recording_opt_in", - "posthog_team"."capture_console_log_opt_in", - "posthog_team"."capture_performance_opt_in", - "posthog_team"."surveys_opt_in", - "posthog_team"."session_recording_version", - "posthog_team"."signup_token", - "posthog_team"."is_demo", - "posthog_team"."access_control", - "posthog_team"."week_start_day", - "posthog_team"."inject_web_apps", - "posthog_team"."test_account_filters", - "posthog_team"."test_account_filters_default_checked", - "posthog_team"."path_cleaning_filters", - "posthog_team"."timezone", - "posthog_team"."data_attributes", - "posthog_team"."person_display_name_properties", - "posthog_team"."live_events_columns", - "posthog_team"."recording_domains", - "posthog_team"."primary_dashboard_id", - "posthog_team"."extra_settings", - "posthog_team"."correlation_config", - "posthog_team"."session_recording_retention_period_days" - FROM "posthog_team" - WHERE "posthog_team"."id" = 2 - LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.170 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.151 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1635,7 +1154,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.171 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.152 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1646,7 +1165,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.172 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.153 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1657,177 +1176,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.173 - ' - SELECT "posthog_sessionrecording"."id", - "posthog_sessionrecording"."session_id", - "posthog_sessionrecording"."team_id", - "posthog_sessionrecording"."created_at", - "posthog_sessionrecording"."deleted", - "posthog_sessionrecording"."object_storage_path", - "posthog_sessionrecording"."distinct_id", - "posthog_sessionrecording"."duration", - "posthog_sessionrecording"."active_seconds", - "posthog_sessionrecording"."inactive_seconds", - "posthog_sessionrecording"."start_time", - "posthog_sessionrecording"."end_time", - "posthog_sessionrecording"."click_count", - "posthog_sessionrecording"."keypress_count", - "posthog_sessionrecording"."mouse_activity_count", - "posthog_sessionrecording"."console_log_count", - "posthog_sessionrecording"."console_warn_count", - "posthog_sessionrecording"."console_error_count", - "posthog_sessionrecording"."start_url", - "posthog_sessionrecording"."storage_version" - FROM "posthog_sessionrecording" - WHERE ("posthog_sessionrecording"."session_id" IN ('1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9') - AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.174 - ' - SELECT "posthog_sessionrecordingviewed"."session_id" - FROM "posthog_sessionrecordingviewed" - WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 - AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.175 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version", - "posthog_person"."id", - "posthog_person"."created_at", - "posthog_person"."properties_last_updated_at", - "posthog_person"."properties_last_operation", - "posthog_person"."team_id", - "posthog_person"."properties", - "posthog_person"."is_user_id", - "posthog_person"."is_identified", - "posthog_person"."uuid", - "posthog_person"."version" - FROM "posthog_persondistinctid" - INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") - WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', - 'user2', - 'user3', - 'user4', - 'user5', - 'user6', - 'user7', - 'user8', - 'user9') - AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.176 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version" - FROM "posthog_persondistinctid" - WHERE "posthog_persondistinctid"."person_id" IN (1, - 2, - 3, - 4, - 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.177 - ' - SELECT "posthog_team"."id", - "posthog_team"."uuid", - "posthog_team"."organization_id", - "posthog_team"."api_token", - "posthog_team"."app_urls", - "posthog_team"."name", - "posthog_team"."slack_incoming_webhook", - "posthog_team"."created_at", - "posthog_team"."updated_at", - "posthog_team"."anonymize_ips", - "posthog_team"."completed_snippet_onboarding", - "posthog_team"."has_completed_onboarding_for", - "posthog_team"."ingested_event", - "posthog_team"."autocapture_opt_out", - "posthog_team"."autocapture_exceptions_opt_in", - "posthog_team"."autocapture_exceptions_errors_to_ignore", - "posthog_team"."session_recording_opt_in", - "posthog_team"."capture_console_log_opt_in", - "posthog_team"."capture_performance_opt_in", - "posthog_team"."surveys_opt_in", - "posthog_team"."session_recording_version", - "posthog_team"."signup_token", - "posthog_team"."is_demo", - "posthog_team"."access_control", - "posthog_team"."week_start_day", - "posthog_team"."inject_web_apps", - "posthog_team"."test_account_filters", - "posthog_team"."test_account_filters_default_checked", - "posthog_team"."path_cleaning_filters", - "posthog_team"."timezone", - "posthog_team"."data_attributes", - "posthog_team"."person_display_name_properties", - "posthog_team"."live_events_columns", - "posthog_team"."recording_domains", - "posthog_team"."primary_dashboard_id", - "posthog_team"."extra_settings", - "posthog_team"."correlation_config", - "posthog_team"."session_recording_retention_period_days", - "posthog_team"."plugins_opt_in", - "posthog_team"."opt_out_capture", - "posthog_team"."event_names", - "posthog_team"."event_names_with_usage", - "posthog_team"."event_properties", - "posthog_team"."event_properties_with_usage", - "posthog_team"."event_properties_numerical" - FROM "posthog_team" - WHERE "posthog_team"."id" = 2 - LIMIT 21 - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.178 - ' - SELECT "posthog_user"."id", - "posthog_user"."password", - "posthog_user"."last_login", - "posthog_user"."first_name", - "posthog_user"."last_name", - "posthog_user"."is_staff", - "posthog_user"."is_active", - "posthog_user"."date_joined", - "posthog_user"."uuid", - "posthog_user"."current_organization_id", - "posthog_user"."current_team_id", - "posthog_user"."email", - "posthog_user"."pending_email", - "posthog_user"."temporary_token", - "posthog_user"."distinct_id", - "posthog_user"."is_email_verified", - "posthog_user"."has_seen_product_intro_for", - "posthog_user"."email_opt_in", - "posthog_user"."partial_notification_settings", - "posthog_user"."anonymize_data", - "posthog_user"."toolbar_mode", - "posthog_user"."events_column_config" - FROM "posthog_user" - WHERE "posthog_user"."id" = 2 - LIMIT 21 /**/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.179 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.16 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1872,7 +1221,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.18 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.17 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -1901,7 +1250,29 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.180 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.18 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.19 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.2 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -1924,35 +1295,13 @@ "posthog_organization"."usage", "posthog_organization"."setup_section_2_completed", "posthog_organization"."personalization", - "posthog_organization"."domain_whitelist" - FROM "posthog_organizationmembership" - INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") - WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.181 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.182 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + "posthog_organization"."domain_whitelist" + FROM "posthog_organizationmembership" + INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") + WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.183 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.20 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1963,7 +1312,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.184 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.21 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1974,7 +1323,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.185 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.22 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1985,7 +1334,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.186 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.23 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -1996,7 +1345,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.187 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.24 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2007,7 +1356,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.188 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.25 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2018,7 +1367,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.189 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.26 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2029,120 +1378,155 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.19 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.27 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.190 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.28 + ' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."surveys_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."plugins_opt_in", + "posthog_team"."opt_out_capture", + "posthog_team"."event_names", + "posthog_team"."event_names_with_usage", + "posthog_team"."event_properties", + "posthog_team"."event_properties_with_usage", + "posthog_team"."event_properties_numerical" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.29 + ' + SELECT "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."email_opt_in", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."events_column_config" + FROM "posthog_user" + WHERE "posthog_user"."id" = 2 + LIMIT 21 /**/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.3 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RATE_LIMIT_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.191 - ' - SELECT "posthog_sessionrecording"."id", - "posthog_sessionrecording"."session_id", - "posthog_sessionrecording"."team_id", - "posthog_sessionrecording"."created_at", - "posthog_sessionrecording"."deleted", - "posthog_sessionrecording"."object_storage_path", - "posthog_sessionrecording"."distinct_id", - "posthog_sessionrecording"."duration", - "posthog_sessionrecording"."active_seconds", - "posthog_sessionrecording"."inactive_seconds", - "posthog_sessionrecording"."start_time", - "posthog_sessionrecording"."end_time", - "posthog_sessionrecording"."click_count", - "posthog_sessionrecording"."keypress_count", - "posthog_sessionrecording"."mouse_activity_count", - "posthog_sessionrecording"."console_log_count", - "posthog_sessionrecording"."console_warn_count", - "posthog_sessionrecording"."console_error_count", - "posthog_sessionrecording"."start_url", - "posthog_sessionrecording"."storage_version" - FROM "posthog_sessionrecording" - WHERE ("posthog_sessionrecording"."session_id" IN ('1', - '10', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9') - AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.192 - ' - SELECT "posthog_sessionrecordingviewed"."session_id" - FROM "posthog_sessionrecordingviewed" - WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 - AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.193 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version", - "posthog_person"."id", - "posthog_person"."created_at", - "posthog_person"."properties_last_updated_at", - "posthog_person"."properties_last_operation", - "posthog_person"."team_id", - "posthog_person"."properties", - "posthog_person"."is_user_id", - "posthog_person"."is_identified", - "posthog_person"."uuid", - "posthog_person"."version" - FROM "posthog_persondistinctid" - INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") - WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', - 'user10', - 'user2', - 'user3', - 'user4', - 'user5', - 'user6', - 'user7', - 'user8', - 'user9') - AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.194 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version" - FROM "posthog_persondistinctid" - WHERE "posthog_persondistinctid"."person_id" IN (1, - 2, - 3, - 4, - 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.30 + ' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."surveys_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.2 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.31 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -2171,7 +1555,18 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.20 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.32 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.33 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2182,7 +1577,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.21 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.34 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2193,7 +1588,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.22 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.35 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2204,7 +1599,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.23 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.36 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2215,7 +1610,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.24 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.37 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2226,7 +1621,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.25 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.38 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2237,7 +1632,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.26 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.39 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2248,18 +1643,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.27 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.4 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.28 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.40 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2270,91 +1665,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.29 - ' - SELECT "posthog_sessionrecording"."id", - "posthog_sessionrecording"."session_id", - "posthog_sessionrecording"."team_id", - "posthog_sessionrecording"."created_at", - "posthog_sessionrecording"."deleted", - "posthog_sessionrecording"."object_storage_path", - "posthog_sessionrecording"."distinct_id", - "posthog_sessionrecording"."duration", - "posthog_sessionrecording"."active_seconds", - "posthog_sessionrecording"."inactive_seconds", - "posthog_sessionrecording"."start_time", - "posthog_sessionrecording"."end_time", - "posthog_sessionrecording"."click_count", - "posthog_sessionrecording"."keypress_count", - "posthog_sessionrecording"."mouse_activity_count", - "posthog_sessionrecording"."console_log_count", - "posthog_sessionrecording"."console_warn_count", - "posthog_sessionrecording"."console_error_count", - "posthog_sessionrecording"."start_url", - "posthog_sessionrecording"."storage_version" - FROM "posthog_sessionrecording" - WHERE ("posthog_sessionrecording"."session_id" IN ('1') - AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.3 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.41 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:RATE_LIMIT_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.30 - ' - SELECT "posthog_sessionrecordingviewed"."session_id" - FROM "posthog_sessionrecordingviewed" - WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 - AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.31 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version", - "posthog_person"."id", - "posthog_person"."created_at", - "posthog_person"."properties_last_updated_at", - "posthog_person"."properties_last_operation", - "posthog_person"."team_id", - "posthog_person"."properties", - "posthog_person"."is_user_id", - "posthog_person"."is_identified", - "posthog_person"."uuid", - "posthog_person"."version" - FROM "posthog_persondistinctid" - INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") - WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1') - AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.32 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version" - FROM "posthog_persondistinctid" - WHERE "posthog_persondistinctid"."person_id" IN (1, - 2, - 3, - 4, - 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.33 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.42 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2406,7 +1728,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.34 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.43 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -2435,7 +1757,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.35 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.44 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2480,7 +1802,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.36 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.45 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -2509,7 +1831,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.37 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.46 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2520,7 +1842,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.38 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.47 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2531,7 +1853,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.39 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.48 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2542,18 +1864,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.4 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.49 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.40 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.5 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2564,7 +1886,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.41 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.50 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2575,7 +1897,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.42 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.51 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2586,7 +1908,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.43 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.52 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2597,7 +1919,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.44 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.53 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2608,7 +1930,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.45 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.54 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2619,7 +1941,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.46 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.55 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2630,93 +1952,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.47 - ' - SELECT "posthog_sessionrecording"."id", - "posthog_sessionrecording"."session_id", - "posthog_sessionrecording"."team_id", - "posthog_sessionrecording"."created_at", - "posthog_sessionrecording"."deleted", - "posthog_sessionrecording"."object_storage_path", - "posthog_sessionrecording"."distinct_id", - "posthog_sessionrecording"."duration", - "posthog_sessionrecording"."active_seconds", - "posthog_sessionrecording"."inactive_seconds", - "posthog_sessionrecording"."start_time", - "posthog_sessionrecording"."end_time", - "posthog_sessionrecording"."click_count", - "posthog_sessionrecording"."keypress_count", - "posthog_sessionrecording"."mouse_activity_count", - "posthog_sessionrecording"."console_log_count", - "posthog_sessionrecording"."console_warn_count", - "posthog_sessionrecording"."console_error_count", - "posthog_sessionrecording"."start_url", - "posthog_sessionrecording"."storage_version" - FROM "posthog_sessionrecording" - WHERE ("posthog_sessionrecording"."session_id" IN ('1', - '2') - AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.48 - ' - SELECT "posthog_sessionrecordingviewed"."session_id" - FROM "posthog_sessionrecordingviewed" - WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 - AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.49 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version", - "posthog_person"."id", - "posthog_person"."created_at", - "posthog_person"."properties_last_updated_at", - "posthog_person"."properties_last_operation", - "posthog_person"."team_id", - "posthog_person"."properties", - "posthog_person"."is_user_id", - "posthog_person"."is_identified", - "posthog_person"."uuid", - "posthog_person"."version" - FROM "posthog_persondistinctid" - INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") - WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', - 'user2') - AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.5 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.50 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version" - FROM "posthog_persondistinctid" - WHERE "posthog_persondistinctid"."person_id" IN (1, - 2, - 3, - 4, - 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.51 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.56 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2768,7 +2004,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.52 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.57 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -2797,7 +2033,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.53 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.58 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2842,7 +2078,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.54 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.59 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -2871,7 +2107,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.55 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.6 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2882,51 +2118,51 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.56 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.60 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.57 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.61 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.58 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.62 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.59 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.63 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.6 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.64 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2937,7 +2173,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.60 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.65 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2948,7 +2184,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.61 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.66 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2959,7 +2195,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.62 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.67 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2970,7 +2206,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.63 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.68 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2981,7 +2217,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.64 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.69 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -2992,84 +2228,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.65 - ' - SELECT "posthog_sessionrecording"."id", - "posthog_sessionrecording"."session_id", - "posthog_sessionrecording"."team_id", - "posthog_sessionrecording"."created_at", - "posthog_sessionrecording"."deleted", - "posthog_sessionrecording"."object_storage_path", - "posthog_sessionrecording"."distinct_id", - "posthog_sessionrecording"."duration", - "posthog_sessionrecording"."active_seconds", - "posthog_sessionrecording"."inactive_seconds", - "posthog_sessionrecording"."start_time", - "posthog_sessionrecording"."end_time", - "posthog_sessionrecording"."click_count", - "posthog_sessionrecording"."keypress_count", - "posthog_sessionrecording"."mouse_activity_count", - "posthog_sessionrecording"."console_log_count", - "posthog_sessionrecording"."console_warn_count", - "posthog_sessionrecording"."console_error_count", - "posthog_sessionrecording"."start_url", - "posthog_sessionrecording"."storage_version" - FROM "posthog_sessionrecording" - WHERE ("posthog_sessionrecording"."session_id" IN ('1', - '2', - '3') - AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.66 - ' - SELECT "posthog_sessionrecordingviewed"."session_id" - FROM "posthog_sessionrecordingviewed" - WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 - AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.67 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version", - "posthog_person"."id", - "posthog_person"."created_at", - "posthog_person"."properties_last_updated_at", - "posthog_person"."properties_last_operation", - "posthog_person"."team_id", - "posthog_person"."properties", - "posthog_person"."is_user_id", - "posthog_person"."is_identified", - "posthog_person"."uuid", - "posthog_person"."version" - FROM "posthog_persondistinctid" - INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") - WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', - 'user2', - 'user3') - AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.68 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.7 ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version" - FROM "posthog_persondistinctid" - WHERE "posthog_persondistinctid"."person_id" IN (1, - 2, - 3, - 4, - 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.69 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.70 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -3121,18 +2291,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.7 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.70 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.71 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -3161,7 +2320,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.71 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.72 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -3206,7 +2365,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.72 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.73 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -3235,7 +2394,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.73 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.74 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3246,7 +2405,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.74 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.75 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3257,7 +2416,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.75 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.76 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3268,7 +2427,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.76 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.77 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3279,7 +2438,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.77 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.78 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3290,7 +2449,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.78 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.79 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3301,29 +2460,29 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.79 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.8 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.8 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.80 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", "posthog_instancesetting"."raw_value" FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_V2_ENABLED' + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' ORDER BY "posthog_instancesetting"."id" ASC LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.80 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.81 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3334,7 +2493,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.81 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.82 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3345,7 +2504,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.82 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.83 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3356,86 +2515,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.83 - ' - SELECT "posthog_sessionrecording"."id", - "posthog_sessionrecording"."session_id", - "posthog_sessionrecording"."team_id", - "posthog_sessionrecording"."created_at", - "posthog_sessionrecording"."deleted", - "posthog_sessionrecording"."object_storage_path", - "posthog_sessionrecording"."distinct_id", - "posthog_sessionrecording"."duration", - "posthog_sessionrecording"."active_seconds", - "posthog_sessionrecording"."inactive_seconds", - "posthog_sessionrecording"."start_time", - "posthog_sessionrecording"."end_time", - "posthog_sessionrecording"."click_count", - "posthog_sessionrecording"."keypress_count", - "posthog_sessionrecording"."mouse_activity_count", - "posthog_sessionrecording"."console_log_count", - "posthog_sessionrecording"."console_warn_count", - "posthog_sessionrecording"."console_error_count", - "posthog_sessionrecording"."start_url", - "posthog_sessionrecording"."storage_version" - FROM "posthog_sessionrecording" - WHERE ("posthog_sessionrecording"."session_id" IN ('1', - '2', - '3', - '4') - AND "posthog_sessionrecording"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- # name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.84 - ' - SELECT "posthog_sessionrecordingviewed"."session_id" - FROM "posthog_sessionrecordingviewed" - WHERE ("posthog_sessionrecordingviewed"."team_id" = 2 - AND "posthog_sessionrecordingviewed"."user_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.85 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version", - "posthog_person"."id", - "posthog_person"."created_at", - "posthog_person"."properties_last_updated_at", - "posthog_person"."properties_last_operation", - "posthog_person"."team_id", - "posthog_person"."properties", - "posthog_person"."is_user_id", - "posthog_person"."is_identified", - "posthog_person"."uuid", - "posthog_person"."version" - FROM "posthog_persondistinctid" - INNER JOIN "posthog_person" ON ("posthog_persondistinctid"."person_id" = "posthog_person"."id") - WHERE ("posthog_persondistinctid"."distinct_id" IN ('user1', - 'user2', - 'user3', - 'user4') - AND "posthog_persondistinctid"."team_id" = 2) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.86 - ' - SELECT "posthog_persondistinctid"."id", - "posthog_persondistinctid"."team_id", - "posthog_persondistinctid"."person_id", - "posthog_persondistinctid"."distinct_id", - "posthog_persondistinctid"."version" - FROM "posthog_persondistinctid" - WHERE "posthog_persondistinctid"."person_id" IN (1, - 2, - 3, - 4, - 5 /* ... */) /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.87 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -3487,7 +2567,7 @@ LIMIT 21 ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.88 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.85 ' SELECT "posthog_user"."id", "posthog_user"."password", @@ -3516,7 +2596,7 @@ LIMIT 21 /**/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.89 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.86 ' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -3561,18 +2641,7 @@ LIMIT 21 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.9 - ' - SELECT "posthog_instancesetting"."id", - "posthog_instancesetting"."key", - "posthog_instancesetting"."raw_value" - FROM "posthog_instancesetting" - WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' - ORDER BY "posthog_instancesetting"."id" ASC - LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ - ' ---- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.90 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.87 ' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -3601,7 +2670,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.91 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.88 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3612,7 +2681,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.92 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.89 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3623,7 +2692,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.93 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.9 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:PERSON_ON_EVENTS_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.90 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3634,7 +2714,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.94 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.91 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3645,7 +2725,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.95 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.92 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3656,7 +2736,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.96 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.93 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3667,7 +2747,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.97 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.94 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3678,7 +2758,7 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.98 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.95 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3689,7 +2769,18 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- -# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.99 +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.96 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:AGGREGATE_BY_DISTINCT_IDS_TEAMS' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.97 ' SELECT "posthog_instancesetting"."id", "posthog_instancesetting"."key", @@ -3700,3 +2791,84 @@ LIMIT 1 /*controller='project_session_recordings-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/session_recordings/%3F%24'*/ ' --- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.98 + ' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."surveys_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."plugins_opt_in", + "posthog_team"."opt_out_capture", + "posthog_team"."event_names", + "posthog_team"."event_names_with_usage", + "posthog_team"."event_properties", + "posthog_team"."event_properties_with_usage", + "posthog_team"."event_properties_numerical" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 + ' +--- +# name: TestSessionRecordings.test_listing_recordings_is_not_nplus1_for_persons.99 + ' + SELECT "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."email_opt_in", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."events_column_config" + FROM "posthog_user" + WHERE "posthog_user"."id" = 2 + LIMIT 21 /**/ + ' +---