• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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