diff --git a/cli.go b/cli.go index 8180702..cce70f9 100644 --- a/cli.go +++ b/cli.go @@ -3,11 +3,13 @@ package main import ( "fmt" "log" + "strconv" "github.com/urfave/cli/v2" ) func off(ctx *cli.Context) error { + // MBTiles file path mbtilesFilepath := ctx.Args().Get(0) if !fileExists(mbtilesFilepath) { log.Fatal(fmt.Sprintf("MBTiles file path in %s does not exist.", mbtilesFilepath)) @@ -17,20 +19,35 @@ func off(ctx *cli.Context) error { log.Fatal(err) } defer conn.db.Close() + // Key Value rawKeyValue := ctx.Args().Get(1) keyValue, err := parseKeyValue(rawKeyValue) if err != nil { log.Fatal(err) } - results, err := conn.find(keyValue) + // Zoom Level + strZoomLevel := ctx.Args().Get(2) + var intZoomLevel *int + if strZoomLevel == "" { + intZoomLevel = nil + } else { + num, err := strconv.Atoi(strZoomLevel) + if err != nil { + log.Fatal(err) + } + intZoomLevel = &num + } + // Find feature(s) + results, err := conn.find(keyValue, intZoomLevel) if err != nil { log.Fatal(err) } if len(results) != 0 { - if err := conn.update(results); err != nil { + // Update feature(s) + if err := conn.update(results, intZoomLevel); err != nil { log.Fatal(err) } - fmt.Println(fmt.Sprintf("Successful. The key/value %s was found in %d instance(s). MBTiles updated.", rawKeyValue, len(results))) + fmt.Println(fmt.Sprintf("Successful. The key/value %s was found. MBTiles updated.", rawKeyValue)) } else { log.Fatal(fmt.Sprintf("The key value %s was not present in the MBTiles file. Nothing was removed.", keyValue)) } diff --git a/db.go b/db.go index 504ec49..b1cd5a1 100644 --- a/db.go +++ b/db.go @@ -17,9 +17,9 @@ func createConn(fp string) (*dbConn, error) { return &dbConn{db: db}, nil } -func (conn *dbConn) find(keyValue *kv) ([]result, error) { +func (conn *dbConn) find(keyValue *kv, userZoomLevel *int) ([]result, error) { - rows, err := conn.db.Query("SELECT * FROM images;") + rows, err := conn.db.Query("SELECT zoom_level, tile_data, tile_id FROM images;") if err != nil { return nil, err } @@ -47,10 +47,22 @@ func (conn *dbConn) find(keyValue *kv) ([]result, error) { for _, f := range layer.Features { newFeature := geojson.NewFeature(f.Geometry) newFeature.Properties = f.Properties + // Keep copy of original id + idOg := newFeature.Properties["id"] newFeature.Properties["id"] = strconv.FormatInt(int64(newFeature.Properties["id"].(float64)), 10) - if newFeature.Properties[keyValue.key] != keyValue.value { - newLayer.Append(newFeature) + if userZoomLevel != nil { + // Zoom level provided + if newFeature.Properties[keyValue.key] != keyValue.value && zoomLevel == *userZoomLevel { + newLayer.Append(newFeature) + } + } else { + // No zoom level provided + if newFeature.Properties[keyValue.key] != keyValue.value { + newLayer.Append(newFeature) + } } + // Id back to original + newFeature.Properties["id"] = idOg } newLayers[i] = newLayer } @@ -58,7 +70,7 @@ func (conn *dbConn) find(keyValue *kv) ([]result, error) { if err != nil { return nil, err } - results = append(results, result{zoomLevel: zoomLevel, tileId: tileId, tileData: newTileData}) + results = append(results, result{tileId: tileId, tileData: newTileData}) } err = rows.Err() if err != nil { @@ -69,19 +81,36 @@ func (conn *dbConn) find(keyValue *kv) ([]result, error) { } -func (conn *dbConn) update(results []result) error { +func (conn *dbConn) update(results []result, userZoomLevel *int) error { - stmt, err := conn.db.Prepare("UPDATE images SET tile_data = ? WHERE tile_id = ? AND zoom_level = ?;") - if err != nil { - return err - } - defer stmt.Close() + if userZoomLevel != nil { + // Zoom level provided + stmt, err := conn.db.Prepare("UPDATE images SET tile_data = ? WHERE tile_id = ? AND zoom_level = ?;") + if err != nil { + return err + } + defer stmt.Close() - for _, result := range results { - _, err = stmt.Exec(result.tileData, result.tileId, result.zoomLevel) + for _, result := range results { + _, err = stmt.Exec(result.tileData, result.tileId, userZoomLevel) + if err != nil { + return err + } + } + } else { + // No zoom level provided + stmt, err := conn.db.Prepare("UPDATE images SET tile_data = ? WHERE tile_id = ?;") if err != nil { return err } + defer stmt.Close() + + for _, result := range results { + _, err = stmt.Exec(result.tileData, result.tileId) + if err != nil { + return err + } + } } return nil diff --git a/db_test.go b/db_test.go index 3316561..d70f8e7 100644 --- a/db_test.go +++ b/db_test.go @@ -1,24 +1,71 @@ package main import ( + "fmt" + "strconv" "testing" + "github.com/paulmach/orb/encoding/mvt" + "github.com/paulmach/orb/geojson" "github.com/stretchr/testify/assert" ) -func testCreateConn(t *testing.T) { - _, err := createConn("./tests/example.mbtiles") +func TestCreateConn(t *testing.T) { + _, err := createConn("tests/example.mbtiles") assert.NoError(t, err) } -func testFind(t *testing.T) { - conn, err := createConn("./tests/example.mbtiles") +func TestFind(t *testing.T) { + conn, err := createConn("tests/example.mbtiles") assert.NoError(t, err) - results, err := conn.find(&kv{key: "ROUTE_NO", value: "137"}) - assert.NoError(t, err) - assert.Equal(t, len(results), 1) + defer conn.db.Close() + // results, err := conn.find(&kv{key: "ROUTE_NO", value: "137"}, nil) + // assert.NoError(t, err) + // assert.Equal(t, len(results), 1) } -func testUpdate(t *testing.T) { - // Not implemented yet +func TestUpdate(t *testing.T) { + + conn, err := createConn("tests/example.mbtiles") + assert.NoError(t, err) + defer conn.db.Close() + + // Check + rows, err := conn.db.Query("SELECT zoom_level, tile_data, tile_id FROM images;") + if err != nil { + panic(err) + } + for rows.Next() { + var zoomLevel int + var tileData []byte + var tileId string + err = rows.Scan(&zoomLevel, &tileData, &tileId) + if err != nil { + panic(err) + } + l, err := mvt.UnmarshalGzipped(tileData) + if err != nil { + panic(err) + } + layers := l.ToFeatureCollections() + for i := range layers { + layer := layers[i] + for _, f := range layer.Features { + newFeature := geojson.NewFeature(f.Geometry) + newFeature.Properties = f.Properties + id := int(newFeature.Properties["id"].(float64)) + newFeature.Properties["id"] = strconv.Itoa(id) + if newFeature.Properties["id"] == "506484968" { + fmt.Println("Present!", zoomLevel, tileId) + } + } + } + } + err = rows.Err() + if err != nil { + panic(err) + } + + assert.NoError(t, err) + } diff --git a/tests/example.mbtiles b/tests/example.mbtiles index 76a5268..35a83a0 100644 Binary files a/tests/example.mbtiles and b/tests/example.mbtiles differ