IodidDOCUMENTATION

reference/filter.mdx

/doc/reference/filter

PUBLIC DOCUMENTATION

Reference — Filter

Filter 10 fields, canonical/summoner factory, Base64Url codec with * for null, Redis keys and ActivityFilter minGames.

Filter (src/main/java/com/safjnest/lol/model/Filter.java:13) is the core of every aggregation — it encapsulates 10 dimensions for statistics, activity, matchups, champion stats.

Fields

java
public class Filter {
    private int champion;          // 0 = all, >0 = champion ID
    private LaneType lane;         // null = all
    private GameQueueType queue;   // null = all (or ALL)
    private TierType rank;         // null = all
    private RankBehavior rankBehavior = GREATER_OR_EQUAL; // EXACT or GREATER_OR_EQUAL
    private String patch;          // null = latest, format major.minor
    private LeagueShard region;    // null = all
    private int opponent;          // 0 = all, >0 = opponent champion ID
    private int duo;               // 0 = all, >0 = duo champion ID
    private long timeStart;        // 0 = epoch 0, otherwise millis
    private long timeEnd;          // 0 = now, otherwise millis
    public enum RankBehavior { EXACT, GREATER_OR_EQUAL }
}
FieldTypeDefault (new Filter() :20)ValidationNotes
championint0>=0 (activityFilter :150)0=all
laneLaneTypenullLaneTypeUtils.playablesTOP..UTILITY
queueGameQueueTypenull (but constructor sets patch/rank/period)optionalQueuenull=all, TEAM_BUILDER_RANKED_SOLO→RANKED_SOLO_5X5
rankTierTypeEMERALDranknull=all
rankBehaviorRankBehaviorGREATER_OR_EQUALenumEXACT vs >=
patchStringPatchUtils.getPatch() (:21)\d+\.\d+null=latest
regionLeagueShardnullregionnull=all
opponentint0>=0
duoint0>=0
timeStartlongSeasonUtils.getCurrentSplitRange()[0] (:24)>=0
timeEndlongSeasonUtils.getCurrentSplitRange()[1]>=0

Constructor Filter() (:20) initializes patch = PatchUtils.getPatch() (:21), rank=EMERALD (:22), rankBehavior=GREATER_OR_EQUAL, timeStart/timeEnd = current split (SeasonUtils.getCurrentSplitRange :24).

Factory defaults

Filter.canonical()

canonical() (src/main/java/com/safjnest/lol/model/Filter.java:44):

java
public static Filter canonical() {
    SeasonUtils.SeasonRange season = SeasonUtils.getCurrentSeasonRange(); // :45
    return new Filter().setChampion(0).setLane(null).setQueue(null).setRank(null)
        .setPatch(null).setRegion(null).setOpponent(0).setDuo(0)
        .setPeriod(season == null ? 0 : season.start(), season == null ? 0 : season.end()); // :55
}

Current season filter — zeroes everything except period = aggregated SeasonRange (min start, max end of splits in rsc/testing/lol_testing/split.json SeasonUtils.java:41). Used for GET /records (RecordsController.java:29) and champion aggregations.

Filter.summoner(timeStart, timeEnd)

summoner(tStart, tEnd) (Filter.java:31):

java
public static Filter summoner(long timeStart, long timeEnd) {
    return new Filter().setChampion(0).setLane(null).setQueue(null).setRank(null)
        .setPatch(null).setRegion(null).setOpponent(0).setDuo(0).setPeriod(timeStart, timeEnd); // :41
}

Filter for profile/activity — explicit period, others zeroed. Used by LolApiParameters.activityFilter (:151):

java
Filter filter = start==0 && end==0 ? Filter.canonical() : Filter.summoner(start,end);
return filter.setQueue(queue).setChampion(champion); // :152

ActivityFilter

ActivityFilter (src/main/java/com/safjnest/lol/model/ActivityFilter.java:3) extends Filter, adds minGames:

java
public class ActivityFilter extends Filter {
    private int minGames = 5; // DEFAULT_MIN_GAMES:5
    public int minGames() { return minGames; }
    public ActivityFilter setMinGames(int minGames) { if (minGames<1) throw IAE; this.minGames=minGames; return this; }
}

Constructor zeroes everything and sets period = Filter.canonical().period() (:19). Used for GET /profile/{puuid}/matchups via LolApiParameters.matchupsFilter (:137):

java
ActivityFilter filter = new ActivityFilter();
filter.setQueue(queue).setLane(role).setMinGames(minGames);
if (start!=0 || end!=0) filter.setPeriod(start, effectiveEnd).setPatch(null);
else filter.setPatch(patch);

Codec — Base64Url * for null

FilterCodec (src/main/java/com/safjnest/lol/utils/FilterCodec.java:6):

java
public static String encode(String raw) { return Base64.getEncoder().encodeToString(raw.getBytes(UTF_8)); } // :10
public static String encodeUrl(String raw) { return Base64.getUrlEncoder().withoutPadding().encodeToString(raw.getBytes(UTF_8)); } // :15
public static String decode(String key) { return new String(Base64.getDecoder().decode(key), UTF_8); } // :20
public static String join(String... parts) { return String.join("|", parts); } // :30
public static String encodeValue(Object v) { return v!=null ? v.toString() : "*"; } // :40
public static String encodeInt(int v) { return v!=0 ? String.valueOf(v) : "*"; } // :44
public static String encodeEnum(Enum<?> v) { return v!=null ? v.name() : "*"; } // :52
public static String encodeOrdinal(Enum<?> v) { return v!=null ? String.valueOf(v.ordinal()) : "*"; } // :56
public static String decodeString(String part) { return "*".equals(trimmed) ? null : trimmed; } // :60
public static T decodeEnum(String part, Class<T> type) { if ("*".equals(trimmed)) return null; return valueOf(trimmed, type); } // :74
  • * represents null or 0 for int.
  • encode = standard Base64 with padding, encodeUrl = URL-safe Base64 without padding (:15).

Keys — toKey, pageKey, toStateKey, toSummonerKey, genericKey

Filter (Filter.java:237):

MethodFile:lineRaw format (join |)CodecPartsRedis use
toKey():237champion|lane|queue|rank|rankBehavior|patch|region (+ opponent|duo if non-zero)encode (standard)7+2legacy champion stats (7 parts)
pageKey():251lane|queue|rank|rankBehavior|patch|region|timeStart|timeEnd (+ opponent|duo)encode8+2pagination (no longer used)
toStateKey():266champion|lane(ordinal)|queue(ordinal)|rank(ordinal)|patch|region|opponent|duo|timeStart|timeEnd|rankBehaviorencodeUrl11profile_matchups (:283 via toStateKey)
toSummonerKey():283champion|lane|queue|rank|rankBehavior|patch|region|opponent|duo|timeStart|timeEndencodeUrl11profile_statistics, profile_activity, summoner_statistics (ProfileService.java:341)
genericKey():300queue|rank|rankBehavior|patch|region|lane|timeStart|timeEndencode8champion_builds/champion_stats per champion

Reverse decoding:

  • fromKey (:69): Base64.decode + split 7-9 parts, decodeEnum for lane/queue/rank.
  • fromSummonerKey (:105): decodeUrl + split 11 exact parts (if parts.length !=11 throw IAE), decodeInt for champion/opponent/duo, decodeLong for time.
  • fromStateKey (:85): decodeUrl + decodeOrdinal for lane/queue/rank.
  • fromGenericKey (:58): decode + 4-6 parts, decodeEnum for queue/rank/region/lane.

Example keys

java
Filter f = Filter.canonical(); // EMERALD rank cleared, season period
String summonerKey = f.toSummonerKey();
// raw: "0|*|*|*|GREATER_OR_EQUAL|*|*|*|*|1700000000000|1716000000000"
// encodedUrl: "MHwqKnwqKkdSRUFURVJfT1JfRVFVQUx8Kip8Kip8Kip8MTcwMDAwMDAwMDAwMHwxNzE2MDAwMDAwMDAw"

Filter g = Filter.summoner(0,0).setQueue(GameQueueType.RANKED_SOLO_5X5).setChampion(157);
String key = g.toSummonerKey();
// raw: "157|*|RANKED_SOLO_5X5|*|GREATER_OR_EQUAL|*|*|*|*|0|0"
// encodedUrl: "MTU3fCp8UkFOS0VEX1NPTE9fNVg1fCp8R1JFQVRFUl9PUl9FUVVBTHwqKnwqKnwqKnwwfDA"

Filter h = new ActivityFilter().setLane(LaneType.MID).setPatch("15.6").setMinGames(5);
String stateKey = h.toStateKey();
// raw: "0|2|ordinal-queue|ordinal-rank|15.6|*|*|*|timeStart|timeEnd|GREATER_OR_EQUAL"
// encodedUrl: URL-safe Base64 without padding

* for null/0 ensures split("\\|", -1) (FilterCodec.java:36) preserves empty fields.

FromSummonerKey — validation

java
// Filter.java:105
public static Filter fromSummonerKey(String key) {
    String raw = FilterCodec.decodeUrl(key);
    String[] parts = FilterCodec.split(raw);
    if (parts.length != 11) throw new IllegalArgumentException("Invalid summoner filter key");
    return new Filter()
        .setChampion(decodeInt(parts[0]))      // *→0
        .setLane(decodeEnum(parts[1], LaneType.class))
        .setQueue(decodeEnum(parts[2], GameQueueType.class))
        .setRank(decodeEnum(parts[3], TierType.class))
        .setRankBehavior(RankBehavior.valueOf(parts[4]))
        .setPatch(decodeString(parts[5]))     // *→null
        .setRegion(decodeEnum(parts[6], LeagueShard.class))
        .setOpponent(decodeInt(parts[7]))
        .setDuo(decodeInt(parts[8]))
        .setPeriod(decodeLong(parts[9]), decodeLong(parts[10]));
}

ActivityFilter — minGames

ActivityFilter.minGames (ActivityFilter.java:22) default 5 (DEFAULT_MIN_GAMES). Validation LolApiParameters.minGames (:119): >=1 otherwise 400.

Used only for matchups — filters opponents with fewer than minGames games. aggregationFilter() (:32): Filter.fromStateKey(toStateKey()) for normalization.

Use in Redis

java
// ProfileService.java:341
String cacheKey = RedisKey.SUMMONER_STATISTICS.of(cacheRegion, shard, puuid, filter.toSummonerKey());
ProfileStatistics cached = RedisClient.get(cacheKey, ProfileStatistics.class);
if (cached == null) {
    Document doc = database.getCollection("profile_statistics").find(Filters.eq("_id", puuid + ":" + filter.toSummonerKey())).first();
    // ...
    RedisClient.set(RedisKey.SUMMONER_STATISTICS, stats, cacheRegion, shard, puuid, filter.toSummonerKey());
}

Same for SUMMONER_ACTIVITY and SUMMONER_MATCHUPS (with toStateKey for matchups).