---
title: "Working with Custom Fields Filters"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Working with Custom Fields Filters}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE, purl = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  eval = FALSE,
  purl = FALSE
)
```

```{r, purl = FALSE}
library(sensortowerR)
library(dplyr)
```

## Introduction

Custom Fields Filters are a powerful feature in Sensor Tower that let you create complex, reusable queries to segment apps across hundreds of attributes. In `sensortowerR` 1.0.0, every filter is built with a single verb — `st_filter()` — which returns an S3 object accepted anywhere a raw filter ID string was accepted before.

## Understanding Custom Fields

Sensor Tower tracks over 400 custom fields, including:

- **Game attributes**: Genre, sub-genre, art style, camera POV
- **Monetization**: Free/paid, IAP, ads, subscriptions
- **Technical**: SDKs used, platform support, device compatibility
- **Performance**: Retention rates, ratings, download counts
- **Metadata**: Release dates, publisher info, update frequency

## Basic workflow

### 1. Discover available fields

```{r, purl = FALSE}
# List every custom field you can filter on
fields <- st_discover_fields()

# See valid values for a specific field
st_custom_fields_values("Primary Genre")
```

### 2. Build a filter

```{r, purl = FALSE}
# Single-criterion filter
puzzle_filter <- st_filter(genre = "Puzzle")

# Multi-criterion filter (all AND-combined)
word_puzzle_free <- st_filter(
  genre        = c("Puzzle", "Word"),
  monetization = "Free"
)

# Date range
new_releases <- st_filter(
  date_from = Sys.Date() - 90,
  date_to   = Sys.Date()
)

# SDK filter
unity_games <- st_filter(sdk = "Unity")

# Publisher filter
ea_games <- st_filter(publisher = "Electronic Arts")
```

### 3. Inspect the filter

```{r, purl = FALSE}
print(puzzle_filter)
as.character(puzzle_filter)  # Server-side filter ID
```

### 4. Use the filter

Every function that accepts a filter takes either a raw 24-hex ID string or an `st_filter` object:

```{r, purl = FALSE}
# Discover apps matching the filter
puzzle_apps <- st_apps(filter = puzzle_filter, limit = 100)

# Top-chart rankings restricted to the filter
top_puzzle <- st_rankings(
  entity = "app",
  os     = "unified",
  filter = puzzle_filter,
  limit  = 25
)

# Raw list of filtered apps (power-user)
raw_hits <- st_get_filtered_apps(filter = puzzle_filter)
```

### 5. Combine filters

Two `st_filter` objects compose with `c()`:

```{r, purl = FALSE}
rpgs       <- st_filter(genre = "RPG")
free_apps  <- st_filter(monetization = "Free")
free_rpgs  <- c(rpgs, free_apps)

apps <- st_apps(filter = free_rpgs)
```

### 6. Reuse an existing filter ID

If you already have a filter ID from the web UI or a previous session:

```{r, purl = FALSE}
existing <- st_filter(filter_id = "5ba4585f539ce75b97db6bcb")
st_apps(filter = existing)
```

## Advanced: arbitrary custom fields

For fields not covered by the named arguments, use `custom_fields = list(...)`:

```{r, purl = FALSE}
complex_filter <- st_filter(
  custom_fields = list(
    "Art Style"       = "3D",
    "Player Count"    = "Multiplayer",
    "Primary Genre"   = "Shooter"
  )
)

top_shooters <- st_rankings(
  entity = "app",
  os     = "ios",
  filter = complex_filter,
  limit  = 50
)
```

## Inspecting and validating filters

```{r, purl = FALSE}
# Does a string look like a valid filter ID?
st_is_valid_filter_id("5ba4585f539ce75b97db6bcb")  # TRUE

# Fetch the canonical filter definition from the API
collection <- st_get_filter_collection("5ba4585f539ce75b97db6bcb")

# Run a smoke-test that the filter yields results
st_test_filter("5ba4585f539ce75b97db6bcb")

# Richer diagnostic output
st_analyze_filter("5ba4585f539ce75b97db6bcb", verbose = TRUE)
```

## Migration from 0.9.x

If you were using `st_filter_by_date()`, `st_filter_by_genre()`, `st_custom_fields_filter()`, `st_combine_filters()`, etc. — all of those are now `.Defunct()` stubs that point at the correct `st_filter()` call:

```{r, purl = FALSE}
# Old (0.9.x)
# puzzle <- st_filter_by_genre(genres = "Puzzle")
# decade <- st_filter_by_date(start_date = "2020-01-01", end_date = "2029-12-31")
# combined <- st_combine_filters(list(puzzle, decade))

# New (1.0.0)
puzzle   <- st_filter(genre = "Puzzle")
decade   <- st_filter(date_from = "2020-01-01", date_to = "2029-12-31")
combined <- c(puzzle, decade)
```

See `vignette("migrating-to-1.0", package = "sensortowerR")` for the complete translation table.
