Code Monkey home page Code Monkey logo

hammer's Introduction

hammer

hammer is a command-line tool to schema management for Google Cloud Spanner.

Installation

Download the single-binary executable from:

https://github.com/daichirata/hammer/releases

or

$ go install github.com/daichirata/hammer@latest

Usage

$ hammer -h
hammer is a command-line tool to schema management for Google Cloud Spanner.

Usage:
  hammer [command]

Examples:

* Export spanner schema
  hammer export spanner://projects/projectId/instances/instanceId/databases/databaseName > schema.sql

* Apply local schema file
  hammer apply spanner://projects/projectId/instances/instanceId/databases/databaseName /path/to/file

* Create database and apply local schema (faster than running database creation and schema apply separately)
  hammer create spanner://projects/projectId/instances/instanceId/databases/databaseName /path/to/file

* Copy database
  hammer create spanner://projects/projectId/instances/instanceId/databases/databaseName1 spanner://projects/projectId/instances/instanceId/databases/databaseName2

* Compare local files
  hammer diff /path/to/file /another/path/to/file

* Compare local file against spanner schema
  hammer diff /path/to/file spanner://projects/projectId/instances/instanceId/databases/databaseName

* Compare spanner schema against spanner schema
  hammer diff spanner://projects/projectId/instances/instanceId/databases/databaseName1 spanner://projects/projectId/instances/instanceId/databases/databaseName2

Available Commands:
  apply       Apply schema
  create      Create database and apply schema
  diff        Diff schema
  export      Export schema
  help        Help about any command

Flags:
  -h, --help   help for hammer

Use "hammer [command] --help" for more information about a command.

The DSN must be given in the following format.

spanner://projects/{projectId}/instances/{instanceId}/databases/{databaseName}?credentials=/path/to/file.json
Param Required Description
projectId true The Google Cloud Platform project id
instanceId true The id of the instance running Spanner
databaseName true The name of the Spanner database
credentials false The path to the keyfile. If not present, client will use your default application credentials.

Flags

apply, create, diff and export can accept the flags defined below

--ignore-alter-database   ignore alter database statements
--ignore-change-streams   ignore change streams statements

Examples

Suppose you have an existing SQL schema like the following:

CREATE TABLE users (
  user_id STRING(36) NOT NULL,
  email STRING(MAX),
) PRIMARY KEY(user_id);

And you want "upgrade" your schema to the following:

CREATE TABLE users (
  user_id STRING(36) NOT NULL,
  email STRING(MAX) NOT NULL,
  age INT64,
  name STRING(MAX) NOT NULL,
) PRIMARY KEY(user_id);
CREATE INDEX idx_users_name ON users (name);

Hammer changes the schema by applying the following SQL to the spanner:

hammer diff old.sql new.sql

UPDATE users SET email = '' WHERE email IS NULL;
ALTER TABLE users ALTER COLUMN email STRING(MAX) NOT NULL;
ALTER TABLE users ADD COLUMN age INT64;
ALTER TABLE users ADD COLUMN name STRING(MAX) NOT NULL DEFAULT ("");
ALTER TABLE users ALTER COLUMN name DROP DEFAULT;
CREATE INDEX idx_users_name ON users(name);
  • When altering a nullable column to add the NOT NULL attribute, hammer update the column with the default value, and then add the NOT NULL attribute. (e.g. email)
  • When adding a column with the NOT NULL attribute without the DEFAULT attribute, hammer add a default value to the column implicitly, and then drop the DEFAULT attribute. (e.g. name)

LICENSE

Unless otherwise noted, the hammer source files are distributed under the MIT License found in the LICENSE file.

hammer's People

Contributors

chidakiyo avatar daichirata avatar gecko655 avatar genkami avatar iffyio avatar iwata avatar k-yomo avatar konboi avatar lithammer avatar nametake avatar naoina avatar neglect-yp avatar neguse avatar nktks avatar reedom avatar sonatard avatar tomrom-pomelo avatar yokoyama10 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

hammer's Issues

JSON_QUERY not recognized

The following fails when running hammer diff:

CREATE TABLE SomeTable (
  Id String(40),
  Data JSON,
  HasSomeValue BOOL AS (IF(JSON_QUERY(Data, '$.value') IS NOT NULL), true, false)) STORED
) PRIMARY KEY (Id);

with the error:

failed to parse ddl: schema.ddl:<line_num>: got "(" while expecting ","

When I replace JSON_QUERY with JSON_VALUE, though not semantically correct, the tool is able to produce a correct diff.

Version command for hammer

It would be great if hammer app could include an additional command of something like hammer -v or hammer version or something on the similar lines, to be able identify which version the executable is on, if there already exists one such command or option, please feel free to close this ticket but do give reference for the same, since it gets tricky once the executable is moved out of it source directory.

Table Creation Order matters for Foreign Keys

When I applied diff on my dev db, the generated sql diff did not execute correctly to my prod db.
When I applied it I got Error: rpc error: code = NotFound desc = Table not found: Images.

Example failure:

CREATE TABLE Posts (
  PostId STRING(2048) NOT NULL,
  Text STRING(MAX),
  FOREIGN KEY (ImageId) REFERENCES Images (ImageId),
) PRIMARY KEY(PostId);

CREATE TABLE Images (
  ImageId STRING(2048) NOT NULL,
  URL STRING(2048),
) PRIMARY KEY(ImageId);

Order matters here due to foreign key so should be:


CREATE TABLE Images (
  ImageId STRING(2048) NOT NULL,
  URL STRING(16),
) PRIMARY KEY(ImageId);

CREATE TABLE Posts (
  PostId STRING(2048) NOT NULL,
  PairSymbol STRING(16),
  FOREIGN KEY (ImageId) REFERENCES Images (ImageId),
) PRIMARY KEY(PostId);

I verified by switching manually that this solved the problem. I think we just need some clever ordering in the library to handle this case.

Add support for foreign keys

Currently hammer ignores foreign keys so that e.g the following detects no diff.

from:

CREATE TABLE T2 (
  ID INT64,
);

to:

CREATE TABLE T2 (
  ID INT64,
  CONSTRAINT FK_T2_ID FOREIGN KEY (ID) REFERENCES T1 (ID)
);

expected:

ALTER TABLE T2 ADD CONSTRAINT FK_T2_ID FOREIGN KEY (ID) REFERENCES T1 (ID)

Support Spanner Views

When adding a spanner view like

CREATE VIEW SomeView
SQL SECURITY INVOKER
AS SELECT
  Table1.Id,
  Table2.SomeColumn
FROM Table1 LEFT JOIN Table2
ON Table1.Id = Table2.Table1Id;

hammer diff fails with the following error:

Error: unexpected ddl statement: &spansql.CreateView{Name:"SomeView", OrReplace:false, Query:spansql.Query{Select:spansql.Select{Distinct:false, List:[]spansql.Expr{spansql.PathExp{"Table1", "Id"}, spansql.PathExp{"Table2", "SomeColumn"}}, From:[]spansql.SelectFrom{spansql.SelectFromJoin{Type:3, LHS:spansql.SelectFromTable{Table:"Table1", Alias:"", Hints:map[string]string(nil)}, RHS:spansql.SelectFromTable{Table:"Table2", Alias:"", Hints:map[string]string(nil)}, On:spansql.ComparisonOp{Op:4, LHS:spansql.PathExp{"Table1", "Id"}, RHS:spansql.PathExp{"Table2", "Table1Id"}, RHS2:spansql.Expr(nil)}, Using:[]spansql.ID(nil), Hints:map[string]string(nil)}}, Where:spansql.BoolExpr(nil), GroupBy:[]spansql.Expr(nil), TableSamples:[]*spansql.TableSample(nil), ListAliases:[]spansql.ID(nil)}, Order:[]spansql.Order(nil), Limit:spansql.LiteralOrParam(nil), Offset:spansql.LiteralOrParam(nil)}, Position:spansql.Position{Line:153, Offset:7819}}

Is there/will there be support for diffing and applying views?

Support timestamp functions

Hello,
On hammer apply or hammer diff, while creating a table with a generated column using a timestamp function, such as:

CREATE TABLE examples (
  inserted_at TIMESTAMP  NOT NULL,
  examples_id STRING(36) NOT NULL,
  examples_timestamp TIMESTAMP  AS(TIMESTAMP_ADD(inserted_at, INTERVAL 1 DAY)) STORED
) PRIMARY KEY(examples_id);

produces the following error:
Error: spanner://projects/test-project/instances/test-instance/databases/example_dev failed to parse ddl: spanner://projects/test-project/instances/test-instance/databases/example_dev:4: got "1", want ")" or ","

Cannot add NOT NULL column on Numeric Type

Adding a NOT NULL Numeric type to the schema and applying it with Hammer results in an error.

CREATE TABLE Test (
   ID STRING(MAX) NOT NULL,
+   A NUMERIC NOT NULL,
) PRIMARY KEY(ID);
$ hammer apply spanner://projects/xxx/instances/yyy/databases/zzz schema.sql
Error: rpc error: code = Unimplemented desc = Cannot add NOT NULL column Test.A to existing table Test.
exit status 1

$ hammer diff spanner://projects/xxx/instances/yyy/databases/zzz ./ddl/schema.sql
ALTER TABLE Test ADD COLUMN A NUMERIC NOT NULL;
ALTER TABLE Test ALTER COLUMN A DROP DEFAULT;

Hammer does not support default values for the Numeric type.

I am expecting the following results.

$ hammer diff spanner://projects/xxx/instances/yyy/databases/zzz ./ddl/schema.sql
ALTER TABLE Test ADD COLUMN A NUMERIC NOT NULL DEFAULT (0);
ALTER TABLE Test ALTER COLUMN A DROP DEFAULT;

Differences between the case of table and column names are treated as differences

Spanner does not distinguish between uppercase and lowercase in table and column names. However, in the case of hammer, it does, which leads to the generation of ALTER TABLE statements for renaming when differences are detected.
I would like to avoid outputting differences in this case.

When applying an ALTER TABLE statement that changes only the case of letters, the following error occurs.

Column names in table SampleTable differ only in case: SampleColumn, SAMPLECOLUMN.
Failed to execute migration, Column names in table SampleTable differ only in case: SampleColumn, SAMPLECOLUMN.

Could hammer support generated columns?

Hi there,
We want to add a generated column to our schema, but hammer doesn't like the syntax. The DDL is like:
expiry TIMESTAMP AS (IF(status IS NULL, updated_at, '10000-01-01 00:00:00 UTC')) STORED

Thanks.

James

Suggestion: option to ignore `ALTER DATABASE` statement

It is great for me if hammer has an option to ignore ALTER DATABASE statement while diff, apply, etc.

Backgrounds:

  • The go spanner library (currently hammer is using it) has 2 critical issues involving the ALTER DATABASE statement. These issues prevent me to use hammer completely.
  • ALTER DATABASE statement needs "database name" to run. it means an sql file that is synced to a database named "db1" cannot be directly used in a database named "db2", because the file has the DB name in SQL statement, like:
    ALTER DATABASE db1 SET OPTIONS (version_retention_period='7d');
    It will be great for me to ignore the "ALTER DATABASE" statement to share/apply the same sql file.

Terminate the resulting queries of `hammer diff` with a semicolon.

I would like to use the output of hammer diff for my migration tool, but those queries are not terminated with a specific character (e.g. semicolon), so I can't separate multiple queries.
It would be great if each query could be terminated with a semicolon!

Thanks.

Add support for column options

spanner v1.2.0 or later spansql supports column options, so I want to upgrade the version of spanner I'm using in hammer.

Should hammer diffs account for "invalid" changes?

Hello!

This isn't quite a bug report or feature request, but could be either. I had the following table:

table Foos {
      BarID INT64 NOT NULL,

      CONSTRAINT FK_FoosBar FOREIGN KEY (BarID) REFERENCES Bars (ID),
}

I then wanted to remove the NOT NULL, i.e,

table Foo {
      BarID INT64,

      CONSTRAINT FK_FooBar FOREIGN KEY (BarID) REFERENCES Bars (ID),
}

And the diff said:

ALTER TABLE Foos ALTER COLUMN BarID INT64

However, this isn't a legal change! Since BarID is part of a foreign key it doesn't apply. Instead, the correct change is to drop the foreign key, change the table, and then readd the foreign key.

The question is: should hammer (a) refuse the diff, (b) warn about it, (c) generate a diff that does the correct drop/regen dance, or (d) ignore this and leave it up to the user to know?

Not saying either is wrong, or what I'd expect, but I think (d) is the least helpful (and works bad with "automation").

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.