Skip to content

Commit

Permalink
more stat apis
Browse files Browse the repository at this point in the history
  • Loading branch information
0x7d8 committed Dec 29, 2024
1 parent 6c3be96 commit 4b32319
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 2 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "api",
"version": "1.1.3",
"version": "1.2.0",
"scripts": {
"build": "rm -rf lib && esbuild `find src \\( -name '*.ts' -o -name '*.tsx' \\)` --platform='node' --sourcemap --ignore-annotations --format='cjs' --target='es2022' --outdir='lib' && esbuild src/index.ts --platform='node' --sourcemap --ignore-annotations --format='cjs' --target='es2022' --outdir='lib' --banner:js='require(\"module-alias\").addAlias(\"@\", __dirname);'",
"kit": "drizzle-kit",
Expand Down
2 changes: 1 addition & 1 deletion src/api/routes/global/extensions/{id}/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { globalAPIRouter } from "@/api"
import { time } from "@rjweb/utils"
import { and, eq, or, sql } from "drizzle-orm"
import { and, eq, or } from "drizzle-orm"

export = new globalAPIRouter.Path('/')
.http('GET', '/', (http) => http
Expand Down
91 changes: 91 additions & 0 deletions src/api/routes/global/extensions/{id}/versions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { globalAPIRouter } from "@/api"
import { time } from "@rjweb/utils"
import { and, desc, eq, inArray, or, sql } from "drizzle-orm"

export = new globalAPIRouter.Path('/')
.http('GET', '/', (http) => http
.document({
description: 'Get the install-base of a blueprint extensions versions',
responses: {
200: {
description: 'Success',
content: {
'application/json': {
schema: {
type: 'object',
additionalProperties: {
type: 'number'
}
}
}
}
}
}, parameters: [
{
name: 'id',
in: 'path',
description: 'The ID or identifier of the extension',
required: true,
schema: {
anyOf: [
{ type: 'integer' },
{ type: 'string' }
]
}
}
]
})
.onRequest(async(ctr) => {
const id = ctr.params.get('id', '')
if (!id) return ctr.status(ctr.$status.BAD_REQUEST).print({ errors: ['Invalid ID'] })

const idInt = parseInt(id)

const [ extension ] = await ctr["@"].cache.use(`extension::${id}`, () => ctr["@"].database.select(ctr["@"].database.fields.extension)
.from(ctr["@"].database.schema.extensions)
.innerJoin(ctr["@"].database.schema.authors, eq(ctr["@"].database.schema.extensions.authorId, ctr["@"].database.schema.authors.id))
.where(and(
eq(ctr["@"].database.schema.extensions.hidden, false),
or(
!isNaN(idInt) ? eq(ctr["@"].database.schema.extensions.id, idInt) : undefined,
eq(ctr["@"].database.schema.extensions.identifier, id)
)
)),
time(5).m()
)

if (!extension) return ctr.status(ctr.$status.NOT_FOUND).print({ errors: ['Extension not found'] })

const versionStats = await ctr["@"].cache.use(`versions::${extension.id}`, () => ctr["@"].database.select({
version: sql<string>`ext->>'version'`.as('version'),
percentage: sql<number>`
(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER ())::numeric(5,2)
`.mapWith(Number).as('percentage')
})
.from(
ctr["@"].database.select({
ext: sql`jsonb_array_elements(data->'blueprint'->'extensions')`.as('ext')
})
.from(ctr["@"].database.schema.telemetryData)
.where(and(
inArray(
ctr["@"].database.schema.telemetryData.id,
ctr["@"].database.select({ id: ctr["@"].database.schema.telemetryPanelsWithLatest.latest.latestTelemetryDataId })
.from(ctr["@"].database.schema.telemetryPanelsWithLatest)
),
sql`created > NOW() - INTERVAL '2 days'`
))
.as('subq')
)
.where(sql`ext->>'identifier' = ${extension.identifier}`)
.groupBy(sql`ext->>'version'`)
.orderBy(desc(sql`ext->>'version'`)),
time(5).m()
)

return ctr.print(Object.fromEntries(versionStats.map((stat) => [
stat.version,
stat.percentage
])))
})
)
63 changes: 63 additions & 0 deletions src/api/routes/global/stats/flags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { globalAPIRouter } from "@/api"
import { number, time } from "@rjweb/utils"
import { and, inArray, sql } from "drizzle-orm"

export = new globalAPIRouter.Path('/')
.http('GET', '/', (http) => http
.document({
description: 'Get the share of blueprint flags in percentage',
responses: {
200: {
description: 'Success',
content: {
'application/json': {
schema: {
type: 'object',
additionalProperties: {
type: 'number'
}
}
}
}
}
}
})
.onRequest(async(ctr) => {
const flagStats = await ctr["@"].cache.use('flags::all', () => ctr["@"].database.select({
flagName: sql<string>`flag.key`.as('flagName'),
percentageEnabled: sql<number>`
(COUNT(*) * 100.0 / (
SELECT COUNT(*)
FROM ${ctr["@"].database.schema.telemetryData}
WHERE id IN (
SELECT ${ctr["@"].database.schema.telemetryPanelsWithLatest.latest.latestTelemetryDataId}
FROM ${ctr["@"].database.schema.telemetryPanelsWithLatest}
)
AND created > NOW() - INTERVAL '2 days'
))::numeric(5,2)
`.mapWith(Number).as('percentageEnabled')
})
.from(ctr["@"].database.schema.telemetryData)
.leftJoin(sql`LATERAL jsonb_each(data->'blueprint'->'flags') AS flag(key, value)`, sql`true`)
.where(and(
inArray(
ctr["@"].database.schema.telemetryData.id,
ctr["@"].database.select({ id: ctr["@"].database.schema.telemetryPanelsWithLatest.latest.latestTelemetryDataId })
.from(ctr["@"].database.schema.telemetryPanelsWithLatest)
),
sql`created > NOW() - INTERVAL '2 days'`,
sql`flag.value = 'true'`
))
.groupBy(sql`flag.key`),
time(5).m()
)

return ctr.print(Object.fromEntries(flagStats.map((stat) => [
stat.flagName,
{
enabled: stat.percentageEnabled,
disabled: 100 - stat.percentageEnabled
}
])))
})
)

0 comments on commit 4b32319

Please sign in to comment.