1// Copyright (C) 2023 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// A single value. These are often retived from trace_processor so 16// need to map to the related sqlite type: 17// null = NULL, string = TEXT, number = INTEGER/REAL, boolean = INTEGER 18export type Primitive = null|string|boolean|number; 19 20export const NullType = null; 21export const NumType = 0 as const; 22export const StrType = 'str' as const; 23export const IdType = 'id' as const; 24export const BoolType = true as const; 25 26// Values may be of any of the above types: 27type KeyType = 28 typeof NumType|typeof StrType|typeof NullType|typeof IdType|typeof BoolType; 29 30// KeySet is a specification for the key/value pairs on an Event. 31// - Every event must have a string ID. 32// - In addition Events may have 1 or more key/value pairs. 33// The *specification* for the key/value pair has to be *precisely* one 34// of the KeySet constants above. So: 35// const thisTypeChecks: KeySet = { id: IdType, foo: StrType }; 36// const thisDoesNot: KeySet = { id: IdType, foo: "bar" }; 37// Since although are is a string it's not a KeySet. 38export type KeySet = { 39 readonly id: typeof IdType, 40 readonly [key: string]: KeyType, 41}; 42 43export interface EmptyKeySet extends KeySet { 44 readonly id: typeof IdType; 45} 46 47// A particular key/value pair on an Event matches the relevant entry 48// on the KeySet if the KeyType and the value type 'match': 49// IdType => string 50// StrType => string 51// BoolType => boolean 52// NullType => null 53// NumType => number 54type IsExactly<P, Q> = P extends Q ? (Q extends P ? any : never) : never; 55type IsId<T> = T extends IsExactly<T, typeof IdType>? string : never; 56type IsStr<T> = T extends IsExactly<T, typeof StrType>? string : never; 57type IsNum<T> = T extends IsExactly<T, typeof NumType>? number : never; 58type IsBool<T> = T extends IsExactly<T, typeof BoolType>? boolean : never; 59type IsNull<T> = T extends IsExactly<T, typeof NullType>? null : never; 60type MapType<T> = IsId<T>|IsStr<T>|IsNum<T>|IsBool<T>|IsNull<T>; 61type ConformingValue<T> = T extends MapType<T>? MapType<T>: void; 62 63// A single trace Event. 64// Events have: 65// - A globally unique identifier `id`. 66// - Zero or more key/value pairs. 67// Note: Events do *not* have to have all possible keys/value pairs for 68// the given id. It is expected that users will only materialise the 69// key/value pairs relevant to the specific use case at hand. 70export type UntypedEvent = { 71 readonly id: string, 72 readonly [key: string]: Primitive, 73}; 74 75export type Event<K extends KeySet> = { 76 [Property in keyof K]: ConformingValue<K[Property]>; 77}; 78 79type KeyUnion<P, Q> = P&Q; 80 81// An EventSet is a: 82// - ordered 83// - immutable 84// - subset 85// of events in the trace. 86export interface EventSet<P extends KeySet> { 87 // All possible keys for Events in this EventSet. 88 readonly keys: KeySet; 89 90 // Methods for refining the set. 91 // Note: these are all synchronous - we expect the cost (and hence 92 // any asynchronous queries) to be deferred to analysis time. 93 filter(...filters: Filter[]): EventSet<P>; 94 sort(...sorts: Sort[]): EventSet<P>; 95 union<Q extends KeySet>(other: EventSet<Q>): EventSet<KeyUnion<P, Q>>; 96 intersect<Q extends KeySet>(other: EventSet<Q>): EventSet<KeyUnion<P, Q>>; 97 98 // Methods for analysing the set. 99 // Note: these are all asynchronous - it's expected that these will 100 // often have to do queries. 101 count(): Promise<number>; 102 isEmpty(): Promise<boolean>; 103 materialise<T extends P>(keys: T, offset?: number, limit?: number): 104 Promise<ConcreteEventSet<T>>; 105} 106 107export type UntypedEventSet = EventSet<KeySet>; 108 109// An expression that operates on an Event and produces a Primitive as 110// output. Expressions have to work both in JavaScript and in SQL. 111// In SQL users can use buildQueryFragment to convert the expression 112// into a snippet of SQL. For JavaScript they call execute(). In both 113// cases you need to know which keys the expression uses, for this call 114// `freeVariables`. 115export interface Expr { 116 // Return a fragment of SQL that can be used to evaluate the 117 // expression. `binding` maps key names to column names in the 118 // resulting SQL. The caller must ensure that binding includes at 119 // least all the keys from `freeVariables`. 120 buildQueryFragment(binding: Map<string, string>): string; 121 122 // Run the expression on an Event. The caller must ensure that event 123 // has all the keys from `freeVariables` materialised. 124 execute(event: UntypedEvent): Primitive; 125 126 // Returns the set of keys used in this expression. 127 // For example in an expression representing `(foo + 4) * bar` 128 // freeVariables would return the set {'foo', 'bar'}. 129 freeVariables(): Set<string>; 130} 131 132// A filter is a (normally boolean) expression. 133export type Filter = Expr; 134 135// Sorting direction. 136export enum Direction { 137 ASC, 138 DESC, 139} 140 141// A sort is an expression combined with a direction: 142export interface Sort { 143 direction: Direction; 144 expression: Expr; 145} 146 147// An EventSet where the Event are accesible synchronously. 148interface ConcreteEventSet<T extends KeySet> extends EventSet<T> { 149 readonly events: Event<T>[]; 150} 151 152export type UntypedConcreteEventSet = ConcreteEventSet<KeySet>; 153