1// Copyright (C) 2024 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 15import {z} from 'zod'; 16import { 17 SqlModules, 18 SqlColumn, 19 SqlFunction, 20 SqlArgument, 21 SqlMacro, 22 SqlModule, 23 SqlPackage, 24 SqlTable, 25 SqlTableFunction, 26} from './sql_modules'; 27import {SqlTableDescription} from '../../components/widgets/sql/table/table_description'; 28import { 29 TableColumn, 30 TableColumnSet, 31} from '../../components/widgets/sql/table/column'; 32import { 33 ArgSetColumnSet, 34 DurationColumn, 35 ProcessColumn, 36 ProcessIdColumn, 37 SchedIdColumn, 38 SliceIdColumn, 39 StandardColumn, 40 ThreadColumn, 41 ThreadIdColumn, 42 ThreadStateIdColumn, 43 TimestampColumn, 44} from '../../components/widgets/sql/table/well_known_columns'; 45 46export class SqlModulesImpl implements SqlModules { 47 readonly packages: SqlPackage[]; 48 49 constructor(docs: SqlModulesDocsSchema) { 50 this.packages = docs.map((json) => new StdlibPackageImpl(json)); 51 } 52 53 listTables(): string[] { 54 return this.packages.flatMap((p) => p.listTables()); 55 } 56 57 getModuleForTable(tableName: string): SqlModule | undefined { 58 for (const stdlibPackage of this.packages) { 59 const maybeTable = stdlibPackage.getModuleForTable(tableName); 60 if (maybeTable) { 61 return maybeTable; 62 } 63 } 64 return undefined; 65 } 66} 67 68export class StdlibPackageImpl implements SqlPackage { 69 readonly name: string; 70 readonly modules: SqlModule[]; 71 72 constructor(docs: DocsPackageSchemaType) { 73 this.name = docs.name; 74 this.modules = []; 75 for (const moduleJson of docs.modules) { 76 this.modules.push(new StdlibModuleImpl(moduleJson)); 77 } 78 } 79 80 getModuleForTable(tableName: string): SqlModule | undefined { 81 for (const module of this.modules) { 82 for (const dataObj of module.dataObjects) { 83 if (dataObj.name == tableName) { 84 return module; 85 } 86 } 87 } 88 return undefined; 89 } 90 91 listTables(): string[] { 92 return this.modules.flatMap((module) => 93 module.dataObjects.map((dataObj) => dataObj.name), 94 ); 95 } 96 97 getSqlTableDescription(tableName: string): SqlTableDescription | undefined { 98 for (const module of this.modules) { 99 for (const dataObj of module.dataObjects) { 100 if (dataObj.name == tableName) { 101 return module.getSqlTableDescription(tableName); 102 } 103 } 104 } 105 return undefined; 106 } 107} 108 109export class StdlibModuleImpl implements SqlModule { 110 readonly includeKey: string; 111 readonly dataObjects: SqlTable[]; 112 readonly functions: SqlFunction[]; 113 readonly tableFunctions: SqlTableFunction[]; 114 readonly macros: SqlMacro[]; 115 116 constructor(docs: DocsModuleSchemaType) { 117 this.includeKey = docs.module_name; 118 this.dataObjects = docs.data_objects.map( 119 (json) => new StdlibDataObjectImpl(json), 120 ); 121 this.functions = docs.functions.map((json) => new StdlibFunctionImpl(json)); 122 this.tableFunctions = docs.table_functions.map( 123 (json) => new StdlibTableFunctionImpl(json), 124 ); 125 this.macros = docs.macros.map((json) => new StdlibMacroImpl(json)); 126 } 127 getTable(tableName: string): SqlTable | undefined { 128 for (const obj of this.dataObjects) { 129 if (obj.name == tableName) { 130 return obj; 131 } 132 } 133 return undefined; 134 } 135 136 getSqlTableDescription(tableName: string): SqlTableDescription | undefined { 137 const sqlTable = this.getTable(tableName); 138 if (sqlTable === undefined) { 139 return undefined; 140 } 141 return { 142 imports: [this.includeKey], 143 name: sqlTable.name, 144 columns: sqlTable.getTableColumns(), 145 }; 146 } 147} 148 149class StdlibMacroImpl implements SqlMacro { 150 readonly name: string; 151 readonly summaryDesc: string; 152 readonly description: string; 153 readonly args: SqlArgument[]; 154 readonly returnType: string; 155 156 constructor(docs: DocsMacroSchemaType) { 157 this.name = docs.name; 158 this.summaryDesc = docs.summary_desc; 159 this.description = docs.desc; 160 this.returnType = docs.return_type; 161 this.args = []; 162 this.args = docs.args.map((json) => new StdlibFunctionArgImpl(json)); 163 } 164} 165 166class StdlibTableFunctionImpl implements SqlTableFunction { 167 readonly name: string; 168 readonly summaryDesc: string; 169 readonly description: string; 170 readonly args: SqlArgument[]; 171 readonly returnCols: SqlColumn[]; 172 173 constructor(docs: DocsTableFunctionSchemaType) { 174 this.name = docs.name; 175 this.summaryDesc = docs.summary_desc; 176 this.description = docs.desc; 177 this.args = docs.args.map((json) => new StdlibFunctionArgImpl(json)); 178 this.returnCols = docs.cols.map((json) => new StdlibColumnImpl(json)); 179 } 180} 181 182class StdlibFunctionImpl implements SqlFunction { 183 readonly name: string; 184 readonly summaryDesc: string; 185 readonly description: string; 186 readonly args: SqlArgument[]; 187 readonly returnType: string; 188 readonly returnDesc: string; 189 190 constructor(docs: DocsFunctionSchemaType) { 191 this.name = docs.name; 192 this.summaryDesc = docs.summary_desc; 193 this.description = docs.desc; 194 this.returnType = docs.return_type; 195 this.returnDesc = docs.return_desc; 196 this.args = docs.args.map((json) => new StdlibFunctionArgImpl(json)); 197 } 198} 199 200class StdlibDataObjectImpl implements SqlTable { 201 name: string; 202 description: string; 203 type: string; 204 columns: SqlColumn[]; 205 206 constructor(docs: DocsDataObjectSchemaType) { 207 this.name = docs.name; 208 this.description = docs.desc; 209 this.type = docs.type; 210 this.columns = docs.cols.map((json) => new StdlibColumnImpl(json)); 211 } 212 213 getTableColumns(): (TableColumn | TableColumnSet)[] { 214 return this.columns.map((col) => col.asTableColumn(this.name)); 215 } 216} 217 218class StdlibColumnImpl implements SqlColumn { 219 name: string; 220 type: string; 221 description: string; 222 223 constructor(docs: DocsArgOrColSchemaType) { 224 this.type = docs.type; 225 this.description = docs.desc; 226 this.name = docs.name; 227 } 228 229 asTableColumn(tableName: string): TableColumn | TableColumnSet { 230 if (this.type === 'TIMESTAMP') { 231 return new TimestampColumn(this.name); 232 } 233 if (this.type === 'DURATION') { 234 return new DurationColumn(this.name); 235 } 236 if (this.type === 'ARGSETID') { 237 return new ArgSetColumnSet(this.name); 238 } 239 240 if (this.name === 'ID') { 241 if (tableName === 'slice') { 242 return new SliceIdColumn(this.name); 243 } 244 if (tableName === 'thread') { 245 return new ThreadIdColumn(this.name); 246 } 247 if (tableName === 'process') { 248 return new ProcessIdColumn(this.name); 249 } 250 if (tableName === 'thread_state') { 251 return new ThreadStateIdColumn(this.name); 252 } 253 if (tableName === 'sched') { 254 return new SchedIdColumn(this.name); 255 } 256 return new StandardColumn(this.name); 257 } 258 259 if (this.type === 'JOINID(slice.id)') { 260 return new SliceIdColumn(this.name); 261 } 262 if (this.type === 'JOINID(thread.id)') { 263 return new ThreadColumn(this.name); 264 } 265 if (this.type === 'JOINID(process.id)') { 266 return new ProcessColumn(this.name); 267 } 268 if (this.type === 'JOINID(thread_state.id)') { 269 return new ThreadStateIdColumn(this.name); 270 } 271 if (this.type === 'JOINID(sched.id)') { 272 return new SchedIdColumn(this.name); 273 } 274 return new StandardColumn(this.name); 275 } 276} 277 278class StdlibFunctionArgImpl implements SqlArgument { 279 name: string; 280 description: string; 281 type: string; 282 283 constructor(docs: DocsArgOrColSchemaType) { 284 this.type = docs.type; 285 this.description = docs.desc; 286 this.name = docs.name; 287 } 288} 289 290const ARG_OR_COL_SCHEMA = z.object({ 291 name: z.string(), 292 type: z.string(), 293 desc: z.string(), 294}); 295type DocsArgOrColSchemaType = z.infer<typeof ARG_OR_COL_SCHEMA>; 296 297const DATA_OBJECT_SCHEMA = z.object({ 298 name: z.string(), 299 desc: z.string(), 300 summary_desc: z.string(), 301 type: z.string(), 302 cols: z.array(ARG_OR_COL_SCHEMA), 303}); 304type DocsDataObjectSchemaType = z.infer<typeof DATA_OBJECT_SCHEMA>; 305 306const FUNCTION_SCHEMA = z.object({ 307 name: z.string(), 308 desc: z.string(), 309 summary_desc: z.string(), 310 args: z.array(ARG_OR_COL_SCHEMA), 311 return_type: z.string(), 312 return_desc: z.string(), 313}); 314type DocsFunctionSchemaType = z.infer<typeof FUNCTION_SCHEMA>; 315 316const TABLE_FUNCTION_SCHEMA = z.object({ 317 name: z.string(), 318 desc: z.string(), 319 summary_desc: z.string(), 320 args: z.array(ARG_OR_COL_SCHEMA), 321 cols: z.array(ARG_OR_COL_SCHEMA), 322}); 323type DocsTableFunctionSchemaType = z.infer<typeof TABLE_FUNCTION_SCHEMA>; 324 325const MACRO_SCHEMA = z.object({ 326 name: z.string(), 327 desc: z.string(), 328 summary_desc: z.string(), 329 return_desc: z.string(), 330 return_type: z.string(), 331 args: z.array(ARG_OR_COL_SCHEMA), 332}); 333type DocsMacroSchemaType = z.infer<typeof MACRO_SCHEMA>; 334 335const MODULE_SCHEMA = z.object({ 336 module_name: z.string(), 337 data_objects: z.array(DATA_OBJECT_SCHEMA), 338 functions: z.array(FUNCTION_SCHEMA), 339 table_functions: z.array(TABLE_FUNCTION_SCHEMA), 340 macros: z.array(MACRO_SCHEMA), 341}); 342type DocsModuleSchemaType = z.infer<typeof MODULE_SCHEMA>; 343 344const PACKAGE_SCHEMA = z.object({ 345 name: z.string(), 346 modules: z.array(MODULE_SCHEMA), 347}); 348type DocsPackageSchemaType = z.infer<typeof PACKAGE_SCHEMA>; 349 350export const SQL_MODULES_DOCS_SCHEMA = z.array(PACKAGE_SCHEMA); 351export type SqlModulesDocsSchema = z.infer<typeof SQL_MODULES_DOCS_SCHEMA>; 352