@@ -12,7 +12,6 @@ import (
1212 "fmt"
1313 "io/fs"
1414 "iter"
15- "log"
1615 "maps"
1716 "os"
1817 "path/filepath"
@@ -335,7 +334,7 @@ func (d *Database) CloseDB() {
335334
336335func (d * Database ) SourcesDataGet (ctx context.Context , sourceName , path string , principal string ) (any , []string , error ) {
337336 path = filepath .ToSlash (path )
338- return tx3 (ctx , d , sourcesDataGet (ctx , d , sourceName , path , principal ,
337+ return tx3 (ctx , d , sourcesDataGet (ctx , d , true , sourceName , path , principal ,
339338 func (bs []byte ) (data any , err error ) {
340339 return data , json .Unmarshal (bs , & data )
341340 }))
@@ -344,7 +343,7 @@ func (d *Database) SourcesDataGet(ctx context.Context, sourceName, path string,
344343func (d * Database ) SourcesDataPatch (ctx context.Context , sourceName , path string , principal string , patch jsonpatch.Patch ) error {
345344 path = filepath .ToSlash (path )
346345 return tx1 (ctx , d , func (tx * sql.Tx ) error {
347- previous , _ , err := sourcesDataGet (ctx , d , sourceName , path , principal , func (bs []byte ) ([]byte , error ) { return bs , nil })(tx )
346+ previous , _ , err := sourcesDataGet (ctx , d , false , sourceName , path , principal , func (bs []byte ) ([]byte , error ) { return bs , nil })(tx )
348347 if err != nil {
349348 return err
350349 }
@@ -356,7 +355,7 @@ func (d *Database) SourcesDataPatch(ctx context.Context, sourceName, path string
356355 })
357356}
358357
359- func sourcesDataGet [T any ](ctx context.Context , d * Database , sourceName , path string , principal string ,
358+ func sourcesDataGet [T any ](ctx context.Context , d * Database , returnFiles bool , sourceName , path string , principal string ,
360359 f func ([]byte ) (T , error ),
361360) func (* sql.Tx ) (T , []string , error ) {
362361 return func (tx * sql.Tx ) (T , []string , error ) {
@@ -375,57 +374,58 @@ func sourcesDataGet[T any](ctx context.Context, d *Database, sourceName, path st
375374 return zero , nil , err
376375 }
377376
378- conditions , args := expr .SQL (d .arg , []any {sourceName , path })
379-
380- offset := len (args )
381- upwardsPaths := upwardsPaths (path )
382- if len (upwardsPaths ) == 0 {
383- return zero , nil , err
384- }
385- inParams := make ([]string , len (upwardsPaths ))
386- for i := range upwardsPaths {
387- inParams [i ] = d .arg (i + 1 + offset )
388- }
389-
377+ var files []string
390378 prefix := filepath .Dir (path )
391379
392- values := make ([]any , 0 , len (args )+ 3 )
393- values = append (values , sourceName , "x" )
394- values = append (values , args [2 :]... ) // conditions
395- values = append (values , prefix + "/%" )
396- values = append (values , upwardsPaths ... )
380+ conditions , args := expr .SQL (d .arg , []any {sourceName , path })
381+ if returnFiles { // get "directory" contents
382+ offset := len (prefix ) + 2
383+ query := fmt .Sprintf (`SELECT DISTINCT
384+ SUBSTRING(
385+ SUBSTRING(path, %[1]d),
386+ 1,
387+ CASE
388+ WHEN %[2]s > 0
389+ THEN %[2]s - 1
390+ ELSE LENGTH(SUBSTRING(path, %[1]d))
391+ END
392+ ) AS entry
393+ FROM sources_data
394+ WHERE source_name = %[3]s
395+ AND path <> %[4]s
396+ AND (%[5]s)
397+ AND path LIKE %[6]s
398+ LIMIT 25` , // limit 25 is arbitrary: there could be a LOT of entries...
399+ offset , d .locate ("'/'" , fmt .Sprintf ("SUBSTRING(path, %d)" , offset )),
400+ d .arg (0 ), d .arg (1 ), conditions , d .arg (len (args )))
401+
402+ files , err = queryPaths (ctx , tx , query , append (args , prefix + "/%" )... )
403+ if err != nil {
404+ if ! errors .Is (err , sql .ErrNoRows ) { // no rows, no nested files to return
405+ return zero , nil , err
406+ }
407+ }
408+ }
397409
398- query := fmt .Sprintf (`SELECT path FROM sources_data
410+ // get file content at node
411+ args [1 ] = path
412+ query := fmt .Sprintf (`SELECT data FROM sources_data
399413WHERE source_name = %s
400- AND (%s <> '')
414+ AND path = %s
401415 AND (%s)
402- AND (path LIKE %s OR path in (%s))
403416ORDER BY path` ,
404- d .arg (0 ), d .arg (1 ), conditions , d . arg ( offset ), strings . Join ( inParams , "," ) )
417+ d .arg (0 ), d .arg (1 ), conditions )
405418
406- log .Println (query , values )
407-
408- files , err := queryPaths (ctx , tx , query , values ... )
409- if err != nil {
410- if ! errors .Is (err , sql .ErrNoRows ) { // no rows, no problem
411- return zero , nil , err
419+ var bs []byte
420+ if err := tx .QueryRowContext (ctx , query , args ... ).Scan (& bs ); err != nil {
421+ if errors .Is (err , sql .ErrNoRows ) { // no rows, no response data
422+ return zero , files , nil
412423 }
413- }
414- log .Printf ("%d files" , len (files ))
415-
416- if len (files ) == 0 {
417- return zero , nil , err
418- }
419-
420- fs0 := sourcedatafs .New (ctx , files , func (file string ) func (context.Context ) ([]byte , error ) {
421- return d .sourceData (tx , sourceName , file )
422- })
423- result , err := loader .NewFileLoader ().WithFS (fs0 ).All ([]string {"." })
424- if err != nil {
425424 return zero , files , err
426425 }
427- var a any = result .Documents
428- return a .(T ), files , nil
426+
427+ ret , err := f (bs )
428+ return ret , files , err
429429 }
430430}
431431
@@ -533,6 +533,9 @@ ORDER BY path LIMIT 4`,
533533
534534 files , err := queryPaths (ctx , tx , query , values ... )
535535 if err != nil {
536+ if errors .Is (err , sql .ErrNoRows ) { // no rows, no conflict
537+ return nil
538+ }
536539 return err
537540 }
538541 if len (files ) == 0 {
@@ -610,7 +613,8 @@ func (d *Database) SourcesDataDelete(ctx context.Context, sourceName, path strin
610613
611614 conditions , args := expr .SQL (d .arg , []any {sourceName , path })
612615
613- _ , err = tx .Exec (fmt .Sprintf (`DELETE FROM sources_data WHERE source_name = %s AND path = %s AND (` + conditions + ")" , d .arg (0 ), d .arg (1 )), args ... )
616+ query := fmt .Sprintf (`DELETE FROM sources_data WHERE source_name = %s AND path = %s AND (%s)` , d .arg (0 ), d .arg (1 ), conditions )
617+ _ , err = tx .ExecContext (ctx , query , args ... )
614618 return err
615619 })
616620}
@@ -781,7 +785,7 @@ func (d *Database) ListBundles(ctx context.Context, principal string, opts ListO
781785 args = append (args , opts .Limit )
782786 }
783787
784- rows , err := txn .Query ( query , args ... )
788+ rows , err := txn .QueryContext ( ctx , query , args ... )
785789 if err != nil {
786790 return nil , "" , err
787791 }
@@ -1839,6 +1843,16 @@ func (d *Database) arg(i int) string {
18391843 return "?"
18401844}
18411845
1846+ func (d * Database ) locate (needle string , haystack string ) string {
1847+ switch d .kind {
1848+ case sqlite :
1849+ return "INSTR(" + haystack + ", " + needle + ")"
1850+ case postgres :
1851+ return "POSITION(" + needle + " IN " + haystack + ")"
1852+ }
1853+ return "LOCATE(" + needle + ", " + haystack + ")"
1854+ }
1855+
18421856func (d * Database ) args (n int ) []string {
18431857 args := make ([]string , n )
18441858 for i := range n {
0 commit comments