From c036649a70757164466ef422ec2e3ff63dfbc59d Mon Sep 17 00:00:00 2001 From: Hadi <112569860+anotherhadi@users.noreply.github.com> Date: Sat, 4 Oct 2025 16:33:03 +0200 Subject: [PATCH] init dataleak sample feature Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com> --- back/api/api.go | 15 +++ back/search/dataleak/dataleak.go | 46 +++++++ .../index/search/datawell-popup.svelte | 118 ++++++++++++++++++ .../components/index/search/datawells.svelte | 7 +- front/src/lib/components/table.svelte | 14 ++- front/src/lib/types.ts | 1 + 6 files changed, 193 insertions(+), 8 deletions(-) create mode 100644 front/src/lib/components/index/search/datawell-popup.svelte diff --git a/back/api/api.go b/back/api/api.go index b04d4b2..792c14b 100644 --- a/back/api/api.go +++ b/back/api/api.go @@ -6,6 +6,7 @@ import ( "time" "github.com/anotherhadi/eleakxir/backend/search" + "github.com/anotherhadi/eleakxir/backend/search/dataleak" "github.com/anotherhadi/eleakxir/backend/server" "github.com/gin-gonic/gin" ) @@ -116,6 +117,20 @@ func routes(s *server.Server, cache *map[string]*search.Result, searchQueue chan } c.JSON(http.StatusOK, r) }) + + s.Router.GET("/dataleak/sample", func(c *gin.Context) { + path := c.Query("path") + if path == "" { + c.JSON(http.StatusBadRequest, gin.H{"Error": "path is required"}) + return + } + sample, err := dataleak.GetDataleakSample(*s, path) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"Error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"Sample": sample}) + }) } func Init(s *server.Server) { diff --git a/back/search/dataleak/dataleak.go b/back/search/dataleak/dataleak.go index 6f1417d..9874079 100644 --- a/back/search/dataleak/dataleak.go +++ b/back/search/dataleak/dataleak.go @@ -217,3 +217,49 @@ func getFromClause(s *server.Server) string { } return fmt.Sprintf("read_parquet([%s], union_by_name=true, filename=true)", strings.Join(parquets, ", ")) } + +func GetDataleakSample(s server.Server, path string) ([][]string, error) { + rowsData := [][]string{} + + query := fmt.Sprintf("SELECT * FROM read_parquet('%s') LIMIT 5", path) + rows, err := s.Duckdb.Query(query) + if err != nil { + return rowsData, err + } + defer rows.Close() + + cols, err := rows.Columns() + if err != nil { + return rowsData, err + } + + rowsData = append(rowsData, cols) + + rawResult := make([][]byte, len(cols)) + dest := make([]any, len(cols)) + for i := range rawResult { + dest[i] = &rawResult[i] + } + + for rows.Next() { + if err := rows.Scan(dest...); err != nil { + return rowsData, err + } + + row := make([]string, len(cols)) + for i := range cols { + if rawResult[i] == nil { + row[i] = "" + } else { + row[i] = string(rawResult[i]) + } + } + rowsData = append(rowsData, row) + } + + if err = rows.Err(); err != nil { + return rowsData, err + } + + return rowsData, nil +} diff --git a/front/src/lib/components/index/search/datawell-popup.svelte b/front/src/lib/components/index/search/datawell-popup.svelte new file mode 100644 index 0000000..729d23e --- /dev/null +++ b/front/src/lib/components/index/search/datawell-popup.svelte @@ -0,0 +1,118 @@ + + + + + diff --git a/front/src/lib/components/index/search/datawells.svelte b/front/src/lib/components/index/search/datawells.svelte index cd19d88..ca87fa0 100644 --- a/front/src/lib/components/index/search/datawells.svelte +++ b/front/src/lib/components/index/search/datawells.svelte @@ -1,7 +1,8 @@
- {#if ( key.toLowerCase() == "url" || key.toLowerCase().endsWith("_url")) && value !== null && value !== ""}
+ {#if (key.toLowerCase() == "url" || key
+ .toLowerCase()
+ .endsWith("_url")) && value !== null && value !== ""}
{/each}
- {:else}
+ {:else if row && Object.keys(row).length > 0}
{#each Object.entries(row) as [key, value]}
{#if key !== "source" && value !== null && value !== ""}
@@ -56,7 +58,9 @@
>
|
- {#if key.toLowerCase() == "url" || key.toLowerCase().endsWith("_url")}
+ {#if key.toLowerCase() == "url" || key
+ .toLowerCase()
+ .endsWith("_url")}
| |
|---|