1
+ import { globalAPIRouter } from "@/api"
2
+ import { time } from "@rjweb/utils"
3
+ import { and , desc , eq , inArray , or , sql } from "drizzle-orm"
4
+
5
+ export = new globalAPIRouter . Path ( '/' )
6
+ . http ( 'GET' , '/' , ( http ) => http
7
+ . document ( {
8
+ description : 'Get the install-base of a blueprint extensions versions' ,
9
+ responses : {
10
+ 200 : {
11
+ description : 'Success' ,
12
+ content : {
13
+ 'application/json' : {
14
+ schema : {
15
+ type : 'object' ,
16
+ additionalProperties : {
17
+ type : 'number'
18
+ }
19
+ }
20
+ }
21
+ }
22
+ }
23
+ } , parameters : [
24
+ {
25
+ name : 'id' ,
26
+ in : 'path' ,
27
+ description : 'The ID or identifier of the extension' ,
28
+ required : true ,
29
+ schema : {
30
+ anyOf : [
31
+ { type : 'integer' } ,
32
+ { type : 'string' }
33
+ ]
34
+ }
35
+ }
36
+ ]
37
+ } )
38
+ . onRequest ( async ( ctr ) => {
39
+ const id = ctr . params . get ( 'id' , '' )
40
+ if ( ! id ) return ctr . status ( ctr . $status . BAD_REQUEST ) . print ( { errors : [ 'Invalid ID' ] } )
41
+
42
+ const idInt = parseInt ( id )
43
+
44
+ const [ extension ] = await ctr [ "@" ] . cache . use ( `extension::${ id } ` , ( ) => ctr [ "@" ] . database . select ( ctr [ "@" ] . database . fields . extension )
45
+ . from ( ctr [ "@" ] . database . schema . extensions )
46
+ . innerJoin ( ctr [ "@" ] . database . schema . authors , eq ( ctr [ "@" ] . database . schema . extensions . authorId , ctr [ "@" ] . database . schema . authors . id ) )
47
+ . where ( and (
48
+ eq ( ctr [ "@" ] . database . schema . extensions . hidden , false ) ,
49
+ or (
50
+ ! isNaN ( idInt ) ? eq ( ctr [ "@" ] . database . schema . extensions . id , idInt ) : undefined ,
51
+ eq ( ctr [ "@" ] . database . schema . extensions . identifier , id )
52
+ )
53
+ ) ) ,
54
+ time ( 5 ) . m ( )
55
+ )
56
+
57
+ if ( ! extension ) return ctr . status ( ctr . $status . NOT_FOUND ) . print ( { errors : [ 'Extension not found' ] } )
58
+
59
+ const versionStats = await ctr [ "@" ] . cache . use ( `versions::${ extension . id } ` , ( ) => ctr [ "@" ] . database . select ( {
60
+ version : sql < string > `ext->>'version'` . as ( 'version' ) ,
61
+ percentage : sql < number > `
62
+ (COUNT(*) * 100.0 / SUM(COUNT(*)) OVER ())::numeric(5,2)
63
+ ` . mapWith ( Number ) . as ( 'percentage' )
64
+ } )
65
+ . from (
66
+ ctr [ "@" ] . database . select ( {
67
+ ext : sql `jsonb_array_elements(data->'blueprint'->'extensions')` . as ( 'ext' )
68
+ } )
69
+ . from ( ctr [ "@" ] . database . schema . telemetryData )
70
+ . where ( and (
71
+ inArray (
72
+ ctr [ "@" ] . database . schema . telemetryData . id ,
73
+ ctr [ "@" ] . database . select ( { id : ctr [ "@" ] . database . schema . telemetryPanelsWithLatest . latest . latestTelemetryDataId } )
74
+ . from ( ctr [ "@" ] . database . schema . telemetryPanelsWithLatest )
75
+ ) ,
76
+ sql `created > NOW() - INTERVAL '2 days'`
77
+ ) )
78
+ . as ( 'subq' )
79
+ )
80
+ . where ( sql `ext->>'identifier' = ${ extension . identifier } ` )
81
+ . groupBy ( sql `ext->>'version'` )
82
+ . orderBy ( desc ( sql `ext->>'version'` ) ) ,
83
+ time ( 5 ) . m ( )
84
+ )
85
+
86
+ return ctr . print ( Object . fromEntries ( versionStats . map ( ( stat ) => [
87
+ stat . version ,
88
+ stat . percentage
89
+ ] ) ) )
90
+ } )
91
+ )
0 commit comments