11import { createGzip } from 'node:zlib'
22
3- import { and , eq , ilike , or , sql } from 'drizzle-orm'
3+ import { and , desc , eq , ilike , inArray , or , sql } from 'drizzle-orm'
44import type { Context } from 'hono'
55import { stream } from 'hono/streaming'
66import { pack as tarPack } from 'tar-stream'
@@ -14,10 +14,10 @@ import { type AuthEnv } from './auth.server.js'
1414// Browse public collections
1515export async function list ( c : Context < AuthEnv > ) {
1616 const q = c . req . query ( 'q' )
17- const limit = c . req . query ( 'limit ' )
18- const offset = c . req . query ( 'offset ' )
19- const take = Math . min ( parseInt ( limit ?? '50' , 10 ) , 100 )
20- const skip = parseInt ( offset ?? '0' , 10 )
17+ const owner = c . req . query ( 'owner ' )
18+ const sort = c . req . query ( 'sort ' )
19+ const take = Math . min ( parseInt ( c . req . query ( ' limit' ) ?? '50' , 10 ) , 100 )
20+ const skip = parseInt ( c . req . query ( ' offset' ) ?? '0' , 10 )
2121
2222 const conditions = [ eq ( schema . collections . public , true ) ]
2323 if ( q ) {
@@ -28,6 +28,9 @@ export async function list(c: Context<AuthEnv>) {
2828 ) ! ,
2929 )
3030 }
31+ if ( owner ) {
32+ conditions . push ( eq ( schema . accounts . slug , owner ) )
33+ }
3134
3235 const results = await db
3336 . select ( {
@@ -45,9 +48,81 @@ export async function list(c: Context<AuthEnv>) {
4548 . where ( and ( ...conditions ) )
4649 . limit ( take )
4750 . offset ( skip )
48- . orderBy ( schema . collections . updatedAt )
51+ . orderBy ( sort === 'name' ? schema . collections . name : desc ( schema . collections . updatedAt ) )
52+
53+ const ids = results . map ( ( r ) => r . id )
54+ const statsMap = new Map <
55+ string ,
56+ {
57+ collectionId : string
58+ number : number
59+ semver : string
60+ recordCount : number
61+ fileCount : number
62+ totalBytes : number
63+ lastPushAt : Date
64+ }
65+ > ( )
4966
50- return c . json ( results )
67+ if ( ids . length > 0 ) {
68+ const allVersions = await db
69+ . select ( {
70+ collectionId : schema . versions . collectionId ,
71+ number : schema . versions . number ,
72+ semver : schema . versions . semver ,
73+ recordCount : schema . versions . recordCount ,
74+ fileCount : schema . versions . fileCount ,
75+ totalBytes : schema . versions . totalBytes ,
76+ lastPushAt : schema . versions . createdAt ,
77+ } )
78+ . from ( schema . versions )
79+ . where ( inArray ( schema . versions . collectionId , ids ) )
80+ . orderBy ( desc ( schema . versions . number ) )
81+
82+ for ( const v of allVersions ) {
83+ if ( ! statsMap . has ( v . collectionId ) ) {
84+ statsMap . set ( v . collectionId , v )
85+ }
86+ }
87+ }
88+
89+ const facetConditions = [ eq ( schema . collections . public , true ) ]
90+ if ( q ) {
91+ facetConditions . push (
92+ or (
93+ ilike ( schema . collections . name , `%${ q } %` ) ,
94+ ilike ( schema . collections . description , `%${ q } %` ) ,
95+ ) ! ,
96+ )
97+ }
98+
99+ const ownerFacets = await db
100+ . select ( {
101+ slug : schema . accounts . slug ,
102+ name : schema . accounts . displayName ,
103+ count : sql < number > `count(*)::int` ,
104+ } )
105+ . from ( schema . collections )
106+ . innerJoin ( schema . accounts , eq ( schema . collections . accountId , schema . accounts . id ) )
107+ . where ( and ( ...facetConditions ) )
108+ . groupBy ( schema . accounts . slug , schema . accounts . displayName )
109+ . orderBy ( sql `count(*) DESC` )
110+
111+ return c . json ( {
112+ collections : results . map ( ( r ) => {
113+ const stats = statsMap . get ( r . id )
114+ return {
115+ ...r ,
116+ latestVersion : stats ?. number ?? null ,
117+ semver : stats ?. semver ?? null ,
118+ recordCount : stats ?. recordCount ?? null ,
119+ fileCount : stats ?. fileCount ?? null ,
120+ totalBytes : stats ?. totalBytes ?? null ,
121+ lastPushAt : stats ?. lastPushAt ?? null ,
122+ }
123+ } ) ,
124+ facets : { owners : ownerFacets } ,
125+ } )
51126}
52127
53128// Create collection
0 commit comments