Exemple #1
0
def stickiness_process_entity_type(target_entity: Entity, team: Team,
                                   filter: StickinessFilter) -> QuerySet:

    events: Union[EventManager, QuerySet] = Event.objects.none()
    if target_entity.type == TREND_FILTER_TYPE_EVENTS:
        events = base.process_entity_for_events(target_entity,
                                                team_id=team.pk,
                                                order_by=None).filter(
                                                    base.filter_events(
                                                        team.pk, filter,
                                                        target_entity))
    elif target_entity.type == TREND_FILTER_TYPE_ACTIONS:
        actions = Action.objects.filter(deleted=False, team=team)
        actions = actions.prefetch_related(
            Prefetch("steps", queryset=ActionStep.objects.order_by("id")))
        try:
            actions.get(pk=target_entity.id)
        except Action.DoesNotExist:
            return Event.objects.none()

        events = base.process_entity_for_events(target_entity,
                                                team_id=team.pk,
                                                order_by=None).filter(
                                                    base.filter_events(
                                                        team.pk, filter,
                                                        target_entity))
    else:
        raise ValueError("target entity must be action or event")
    return events
Exemple #2
0
def filter_by_type(entity: Entity, team: Team, filter: Filter) -> QuerySet:
    events: Union[EventManager, QuerySet] = Event.objects.none()
    if filter.session:
        events = Event.objects.filter(team=team).filter(
            base.filter_events(team.pk, filter)).add_person_id(team.pk)
    else:
        if entity.type == TREND_FILTER_TYPE_EVENTS:
            events = base.process_entity_for_events(entity,
                                                    team_id=team.pk,
                                                    order_by=None).filter(
                                                        base.filter_events(
                                                            team.pk, filter,
                                                            entity))
        elif entity.type == TREND_FILTER_TYPE_ACTIONS:
            actions = Action.objects.filter(deleted=False)
            try:
                actions.get(pk=entity.id)
            except Action.DoesNotExist:
                return events
            events = base.process_entity_for_events(entity,
                                                    team_id=team.pk,
                                                    order_by=None).filter(
                                                        base.filter_events(
                                                            team.pk, filter,
                                                            entity))
    return events
Exemple #3
0
    def _retrieve_people(self, target_entity: Entity, filter: StickinessFilter, team: Team) -> ReturnDict:
        from posthog.api.person import PersonSerializer

        if target_entity.type == TREND_FILTER_TYPE_EVENTS:
            filtered_events = base.process_entity_for_events(target_entity, team_id=team.pk, order_by=None).filter(
                base.filter_events(team.pk, filter, target_entity)
            )
        elif target_entity.type == TREND_FILTER_TYPE_ACTIONS:
            actions = Action.objects.filter(deleted=False, team=team)
            actions = actions.prefetch_related(Prefetch("steps", queryset=ActionStep.objects.order_by("id")))
            try:
                actions.get(pk=target_entity.id)
            except Action.DoesNotExist:
                return PersonSerializer([], many=True).data

            filtered_events = base.process_entity_for_events(target_entity, team_id=team.pk, order_by=None).filter(
                base.filter_events(team.pk, filter, target_entity)
            )
        else:
            raise ValueError("target entity must be action or event")

        events = (
            filtered_events.values("person_id")
            .annotate(day_count=Count(filter.trunc_func("timestamp"), distinct=True))
            .filter(day_count=filter.selected_interval)
        )

        people = Person.objects.filter(
            team=team, id__in=[p["person_id"] for p in events[filter.offset : filter.offset + 100]],
        )

        people = people.prefetch_related(Prefetch("persondistinctid_set", to_attr="distinct_ids_cache"))

        return PersonSerializer(people, many=True).data
Exemple #4
0
    def _serialize_lifecycle(self, entity: Entity, filter: Filter,
                             team_id: int) -> List[Dict[str, Any]]:

        period = filter.interval or "day"
        num_intervals, prev_date_from, date_from, date_to, after_date_to = get_time_diff(
            period, filter.date_from, filter.date_to, team_id)
        interval_trunc, sub_interval = get_trunc_func(period=period)

        # include the before and after when filteirng all events

        filter = filter.with_data({
            "date_from": prev_date_from.isoformat(),
            "date_to": after_date_to.isoformat()
        })

        filtered_events = (Event.objects.filter(
            team_id=team_id).add_person_id(team_id).filter(
                filter_events(team_id, filter, entity)))
        event_query, event_params = queryset_to_named_query(
            filtered_events, "events")

        earliest_events_filtered = (Event.objects.filter(
            team_id=team_id).add_person_id(team_id).filter(
                filter_events(team_id, filter, entity, include_dates=False)))
        earliest_events_query, earliest_events_params = queryset_to_named_query(
            earliest_events_filtered, "earliest_events")

        with connection.cursor() as cursor:
            cursor.execute(
                LIFECYCLE_SQL.format(
                    action_join=ACTION_JOIN
                    if entity.type == TREND_FILTER_TYPE_ACTIONS else "",
                    event_condition="{} = %(event)s".format(
                        "action_id" if entity.type ==
                        TREND_FILTER_TYPE_ACTIONS else "event"),
                    events=event_query,
                    earliest_events=earliest_events_query,
                ),
                {
                    "team_id": team_id,
                    "event": entity.id,
                    "interval": interval_trunc,
                    "one_interval": "1 " + interval_trunc,
                    "sub_interval": "1 " + sub_interval,
                    "num_intervals": num_intervals,
                    "prev_date_from": prev_date_from,
                    "date_from": date_from,
                    "date_to": date_to,
                    "after_date_to": after_date_to,
                    **event_params,
                    **earliest_events_params,
                },
            )
            res = []
            for val in cursor.fetchall():
                label = "{} - {}".format(entity.name, val[2])
                additional_values = {"label": label, "status": val[2]}
                parsed_result = parse_response(val, filter, additional_values)
                res.append(parsed_result)
        return res
    def run(self, filter: Filter, team: Team, *args,
            **kwargs) -> List[Dict[str, Any]]:
        calculated = []

        events = Event.objects.none()
        for entity in filter.entities:
            events |= process_entity_for_events(
                entity, team_id=team.pk).filter(
                    filter_events(team_id=team.pk,
                                  filter=filter,
                                  entity=entity,
                                  include_dates=False))

        if not len(events):
            events = self.events_query(filter, team)

        # get compared period
        if filter.compare and filter._date_from != "all" and filter.session == SESSION_AVG:
            calculated = self.calculate_sessions(
                events.filter(filter.date_filter_Q), filter, team)
            calculated = convert_to_comparison(calculated, filter, "current")

            compare_filter = determine_compared_filter(filter)
            compared_calculated = self.calculate_sessions(
                events.filter(compare_filter.date_filter_Q), compare_filter,
                team)
            converted_compared_calculated = convert_to_comparison(
                compared_calculated, filter, "previous")
            calculated.extend(converted_compared_calculated)
        else:
            events = events.filter(filter.date_filter_Q)
            calculated = self.calculate_sessions(events, filter, team)

        return calculated
Exemple #6
0
    def get_people(self,
                   request: request.Request) -> Union[Dict[str, Any], List]:
        team = self.team
        filter = Filter(request=request)
        offset = int(request.GET.get("offset", 0))

        def _calculate_people(events: QuerySet, offset: int):
            events = events.values("person_id").distinct()

            if request.GET.get(
                    "breakdown_type"
            ) == "cohort" and request.GET.get("breakdown_value") != "all":
                events = events.filter(
                    Exists(
                        CohortPeople.objects.filter(
                            cohort_id=int(request.GET["breakdown_value"]),
                            person_id=OuterRef("person_id"),
                        ).only("id")))
            if request.GET.get("breakdown_type") == "person":
                events = events.filter(
                    Exists(
                        Person.objects.filter(
                            **{
                                "id":
                                OuterRef("person_id"),
                                "team_id":
                                self.team.pk,
                                "properties__{}".format(request.GET["breakdown"]):
                                request.GET["breakdown_value"],
                            }).only("id")))

            people = Person.objects.filter(
                team=team,
                id__in=[p["person_id"] for p in events[offset:offset + 100]])

            people = people.prefetch_related(
                Prefetch("persondistinctid_set", to_attr="distinct_ids_cache"))

            return PersonSerializer(people,
                                    context={
                                        "request": request
                                    },
                                    many=True).data

        filtered_events: QuerySet = QuerySet()
        if request.GET.get("session"):
            filtered_events = (Event.objects.filter(team=team).filter(
                base.filter_events(team.pk, filter)).add_person_id(team.pk))
        else:
            entity = get_target_entity(request)

            if entity.type == TREND_FILTER_TYPE_EVENTS:
                filtered_events = base.process_entity_for_events(
                    entity, team_id=team.pk, order_by=None).filter(
                        base.filter_events(team.pk, filter, entity))
            elif entity.type == TREND_FILTER_TYPE_ACTIONS:
                actions = super().get_queryset()
                actions = actions.filter(deleted=False)
                try:
                    action = actions.get(pk=entity.id)
                except Action.DoesNotExist:
                    return []
                filtered_events = base.process_entity_for_events(
                    entity, team_id=team.pk, order_by=None).filter(
                        base.filter_events(team.pk, filter, entity))

        people = _calculate_people(events=filtered_events, offset=offset)

        current_url = request.get_full_path()
        next_url = paginated_result(people, request, offset)

        return {
            "results": [{
                "people": people,
                "count": len(people)
            }],
            "next": next_url,
            "previous": current_url[1:]
        }
Exemple #7
0
    def get_people(self,
                   request: request.Request) -> Union[Dict[str, Any], List]:
        team = request.user.team
        filter = Filter(request=request)
        offset = int(request.GET.get("offset", 0))

        def _calculate_people(events: QuerySet, offset: int):
            shown_as = request.GET.get("shown_as")
            if shown_as is not None and shown_as == "Stickiness":
                stickiness_days = int(request.GET["stickiness_days"])
                events = (events.values("person_id").annotate(day_count=Count(
                    functions.TruncDay("timestamp"), distinct=True)).filter(
                        day_count=stickiness_days))
            else:
                events = events.values("person_id").distinct()

            if request.GET.get(
                    "breakdown_type"
            ) == "cohort" and request.GET.get("breakdown_value") != "all":
                events = events.filter(
                    Exists(
                        CohortPeople.objects.filter(
                            cohort_id=int(request.GET["breakdown_value"]),
                            person_id=OuterRef("person_id"),
                        ).only("id")))
            if request.GET.get("breakdown_type") == "person":
                events = events.filter(
                    Exists(
                        Person.objects.filter(
                            **{
                                "id":
                                OuterRef("person_id"),
                                "properties__{}".format(request.GET["breakdown"]):
                                request.GET["breakdown_value"],
                            }).only("id")))

            people = Person.objects.filter(
                team=team,
                id__in=[p["person_id"] for p in events[offset:offset + 100]],
            )

            people = people.prefetch_related(
                Prefetch("persondistinctid_set", to_attr="distinct_ids_cache"))

            return serialize_people(people=people, request=request)

        filtered_events: QuerySet = QuerySet()
        if request.GET.get("session"):
            filtered_events = (Event.objects.filter(team=team).filter(
                base.filter_events(team.pk, filter)).add_person_id(team.pk))
        else:
            if len(filter.entities) >= 1:
                entity = filter.entities[0]
            else:
                entity = Entity({
                    "id": request.GET["entityId"],
                    "type": request.GET["type"]
                })

            if entity.type == TREND_FILTER_TYPE_EVENTS:
                filtered_events = base.process_entity_for_events(
                    entity, team_id=team.pk, order_by=None).filter(
                        base.filter_events(team.pk, filter, entity))
            elif entity.type == TREND_FILTER_TYPE_ACTIONS:
                actions = super().get_queryset()
                actions = actions.filter(deleted=False)
                try:
                    action = actions.get(pk=entity.id)
                except Action.DoesNotExist:
                    return []
                filtered_events = base.process_entity_for_events(
                    entity, team_id=team.pk, order_by=None).filter(
                        base.filter_events(team.pk, filter, entity))

        people = _calculate_people(events=filtered_events, offset=offset)

        current_url = request.get_full_path()
        next_url: Optional[str] = request.get_full_path()
        if people["count"] > 99 and next_url:
            if "offset" in next_url:
                next_url = next_url[1:]
                next_url = next_url.replace("offset=" + str(offset),
                                            "offset=" + str(offset + 100))
            else:
                next_url = request.build_absolute_uri("{}{}offset={}".format(
                    next_url, "&" if "?" in next_url else "?", offset + 100))
        else:
            next_url = None

        return {
            "results": [people],
            "next": next_url,
            "previous": current_url[1:]
        }
Exemple #8
0
    def get_people(
        self,
        filter: Filter,
        team_id: int,
        target_date: datetime,
        lifecycle_type: str,
        limit: int = 100,
    ):
        entity = filter.entities[0]
        period = filter.interval or "day"
        num_intervals, prev_date_from, date_from, date_to, after_date_to = get_time_diff(
            period, filter.date_from, filter.date_to, team_id)
        interval_trunc, sub_interval = get_trunc_func(period=period)

        # include the before and after when filteirng all events
        filter = Filter(
            data={
                **filter._data, "date_from": prev_date_from.isoformat(),
                "date_to": after_date_to.isoformat()
            })

        filtered_events = Event.objects.filter(team_id=team_id).filter(
            filter_events(team_id, filter, entity))
        event_query, event_params = queryset_to_named_query(filtered_events)

        earliest_events_filtered = Event.objects.filter(
            team_id=team_id).filter(
                filter_events(team_id, filter, entity, include_dates=False))
        earliest_events_query, earliest_events_params = queryset_to_named_query(
            earliest_events_filtered, "earliest_events")

        with connection.cursor() as cursor:
            cursor.execute(
                LIFECYCLE_PEOPLE_SQL.format(
                    action_join=ACTION_JOIN
                    if entity.type == TREND_FILTER_TYPE_ACTIONS else "",
                    event_condition="{} = %(event)s".format(
                        "action_id" if entity.type ==
                        TREND_FILTER_TYPE_ACTIONS else "event"),
                    events=event_query,
                    earliest_events=earliest_events_query,
                ),
                {
                    "team_id": team_id,
                    "event": entity.id,
                    "interval": interval_trunc,
                    "one_interval": "1 " + interval_trunc,
                    "sub_interval": "1 " + sub_interval,
                    "num_intervals": num_intervals,
                    "prev_date_from": prev_date_from,
                    "date_from": date_from,
                    "date_to": date_to,
                    "after_date_to": after_date_to,
                    "target_date": target_date,
                    "status": lifecycle_type,
                    "offset": filter.offset,
                    "limit": limit,
                    **event_params,
                    **earliest_events_params,
                },
            )
            pids = cursor.fetchall()

            people = Person.objects.filter(
                team_id=team_id,
                id__in=[p[0] for p in pids],
            )
            people = people.prefetch_related(
                Prefetch("persondistinctid_set", to_attr="distinct_ids_cache"))

            from posthog.api.person import PersonSerializer

            return PersonSerializer(people, many=True).data