GithubHelp home page GithubHelp logo

alash3al / sqler Goto Github PK

View Code? Open in Web Editor NEW
2.1K 45.0 116.0 93 KB

write APIs using direct SQL queries with no hassle, let's rethink about SQL

Home Page: https://www.sqler.dev/

License: Apache License 2.0

HCL 14.17% Go 80.82% Dockerfile 1.01% HTML 4.00%
mysql sqlite3 postgresql cockroach mssql api-rest restful baas

sqler's Introduction

SQLer

SQL-er is a tiny portable server enables you to write APIs using SQL query to be executed when anyone hits it, also it enables you to define validation rules so you can validate the request body/query params, as well as data transformation using simple javascript syntax. sqler uses nginx style configuration language (HCL) and javascript engine for custom expressions.

Table Of Contents

Features

  • Standalone with no dependencies.
  • Works with most of SQL databases out there including (SQL Server, MYSQL, SQLITE, PostgreSQL, Cockroachdb)
  • Built-in RESTful server
  • Built-in RESP Redis Protocol, you connect to SQLer using any redis client
  • Built-in Javascript interpreter to easily transform the result
  • Built-in Validators
  • Automatically uses prepared statements
  • Uses (HCL) configuration language
  • You can load multiple configuration files not just one, based on unix glob style pattern
  • Each SQL query could be named as Macro
  • Uses Javascript custom expressions.
  • Each macro has its own Context (query params + body params) as .Input which is map[string]interface{}, and .Utils which is a list of helper functions, currently it contains only SQLEscape.
  • You can define authorizers, an authorizer is just a simple webhook that enables sqler to verify whether the request should be done or not.
  • Trigger a webhook or another macro when a specific macro get executed.
  • Schedule specific macros to run at specific time using simple cron syntax.

Quick Tour

  • You install sqler using the right binary for your os from the releases page.
  • Let's say that you downloaded sqler_darwin_amd64
  • Let's rename it to sqler, and copy it to /usr/local/bin
  • Now just run sqler -h, you will the next
                         ____   ___  _
                        / ___| / _ \| |    ___ _ __
                        \___ \| | | | |   / _ \ '__|
                         ___) | |_| | |__|  __/ |
                        |____/ \__\_\_____\___|_|

        turn your SQL queries into safe valid RESTful apis.


  -config string
        the config file(s) that contains your endpoints configs, it accepts comma seprated list of glob style pattern (default "./config.example.hcl")
  -driver string
        the sql driver to be used (default "mysql")
  -dsn string
        the data source name for the selected engine (default "root:root@tcp(127.0.0.1)/test?multiStatements=true")
  -resp string
        the resp (redis protocol) server listen address (default ":3678")
  -rest string
        the http restful api listen address (default ":8025")
  -workers int
        the maximum workers count (default 4)
  • you can specifiy multiple files for -config as configuration, i.e -config="/my/config/dir/*.hcl,/my/config/dir2/*.hcl"
  • you need specify which driver you need and its dsn from the following:
Driver DSN
mysql usrname:password@tcp(server:port)/dbname?option1=value1&...
postgres postgresql://username:password@server:port/dbname?option1=value1
sqlite3 /path/to/db.sqlite?option1=value1
sqlserver sqlserver://username:password@host/instance?param1=value&param2=value
sqlserver://username:password@host:port?param1=value&param2=value
sqlserver://sa@localhost/SQLExpress?database=master&connection+timeout=30
mssql server=localhost\\SQLExpress;user id=sa;database=master;app name=MyAppName
server=localhost;user id=sa;database=master;app name=MyAppName
odbc:server=localhost\\SQLExpress;user id=sa;database=master;app name=MyAppName
odbc:server=localhost;user id=sa;database=master;app name=MyAppName
hdb (SAP HANA) hdb://user:password@host:port
clickhouse (Yandex ClickHouse) tcp://host1:9000?username=user&password=qwerty&database=clicks&read_timeout=10&write_timeout=20&alt_hosts=host2:9000,host3:9000

Supported DBMSs

  • MYSQL, TiDB, MariaDB, Percona and any MYSQL compatible server uses mysql driver.
  • PostgreSQL, CockroachDB and any PostgreSQL compatible server uses postgres driver.
  • SQL Server, MSSQL, ADO, ODBC uses sqlserver or mssql driver.
  • SQLITE, uses sqlite3 driver.
  • HANA (SAP), uses hdb driver.
  • Clickhouse, uses clickhouse driver.

Docker

SQLer has a docker image called alash3al/sqler it is an automated build, you can use it like the following:

# run the help message
docker run --rm alash3al/sqler --help

# connect to a local mysql
docker run --network=host alash3al/sqler -driver=mysql -dsn=usr:pass@tcp(127.0.0.1:3306)/dbname

# connect to another mysql container
docker run -link mysql alash3al/sqler -driver=mysql -dsn=usr:pass@tcp(mysql:3306)/dbname

Configuration Overview

// create a macro/endpoint called "_boot",
// this macro is private "used within other macros" 
// because it starts with "_".
_boot {
    // the query we want to execute
    exec = <<SQL
        CREATE TABLE IF NOT EXISTS `users` (
            `ID` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
            `name` VARCHAR(30) DEFAULT "@anonymous",
            `email` VARCHAR(30) DEFAULT "@anonymous",
            `password` VARCHAR(200) DEFAULT "",
            `time` INT UNSIGNED
        );
    SQL
}

// adduser macro/endpoint, just hit `/adduser` with
// a `?user_name=&user_email=` or json `POST` request
// with the same fields.
adduser {
    validators {
        user_name_is_empty = "$input.user_name && $input.user_name.trim().length > 0"
        user_email_is_empty = "$input.user_email && $input.user_email.trim(' ').length > 0"
        user_password_is_not_ok = "$input.user_password && $input.user_password.trim(' ').length > 5"
    }

    bind {
        name = "$input.user_name"
        email = "$input.user_email"
        password = "$input.user_password"
    }

    methods = ["POST"]

    authorizer = <<JS
        (function(){
            log("use this for debugging")
            token = $input.http_authorization
            response = fetch("http://requestbin.fullcontact.com/zxpjigzx", {
                headers: {
                    "Authorization": token
                }
            })
            if ( response.statusCode != 200 ) {
                return false
            }
            return true
        })()
    JS

    // include some macros we declared before
    include = ["_boot"]

    exec = <<SQL
        INSERT INTO users(name, email, password, time) VALUES(:name, :email, :password, UNIX_TIMESTAMP());
        SELECT * FROM users WHERE id = LAST_INSERT_ID();
    SQL
}

// list all databases, and run a transformer function
databases {
    exec = "SHOW DATABASES"
    cron = "* * * * *"
    trigger {
        webhook = "http://some.url/hook"
    }
}

// list all tables from all databases
tables {
    exec = "SELECT `table_schema` as `database`, `table_name` as `table` FROM INFORMATION_SCHEMA.tables"
}

// a macro that aggregates `databases` macro and `tables` macro into one macro
databases_tables {
    aggregate = ["databases", "tables"]
}

REST vs RESP

RESTful server could be used to interact directly with i.e mobile, browser, ... etc, in this mode SQLer is protected by authorizers, which gives you the ability to check authorization against another 3rd-party api.
Each macro you add to the configuration file(s) you can access to it by issuing a http request to /<macro-name>, every query param and json body will be passed to the macro .Input.

RESP server is just a basic REDIS compatible server, you connect to it using any REDIS client out there, even redis-cli, just open redis-cli -p 3678 list to list all available macros (commands), you can execute any macro as a redis command and pass the arguments as a json encoded data, i.e redis-cli -p 3678 adduser "{\"user_name\": \"u6\", \"user_email\": \"[email protected]\", \"user_password\":\"pass@123\"}".

Sanitization

SQLer uses prepared statements, you can bind inputs like the following:

addpost {
    // $input is a global variable holds all request inputs,
    // including the http headers too (prefixed with `http_`)
    // all http header keys are normalized to be in this form 
    // `http_x_header_example`, `http_authorization` ... etc in lower case.
    bind {
        title = "$input.post_title"
        content = "$input.post_content"
        user_id = "$input.post_user"
    }

    exec = <<SQL
        INSERT INTO posts(user_id, title, content) VALUES(:user_id, :title, :content);
        SELECT * FROM posts WHERE id = LAST_INSERT_ID();
    SQL
}

Validation

Data validation is very easy in SQLer, it is all about simple javascript expression like this:

addpost {
    // if any rule returns false, 
    // SQLer will return 422 code, with invalid rules.
    // 
    // $input is a global variable holds all request inputs,
    // including the http headers too (prefixed with `http_`)
    // all http header keys are normalized to be in this form 
    // `http_x_header_example`, `http_authorization` ... etc in lower case.
    validators {
        post_title_length = "$input.post_title && $input.post_title.trim().length > 0"
        post_content_length = "$input.post_content && $input.post_content.length > 0"
        post_user = "$input.post_user"
    }

    bind {
        title = "$input.post_title"
        content = "$input.post_content"
        user_id = "$input.post_user"
    }

    exec = <<SQL
        INSERT INTO posts(user_id, title, content) VALUES(:user_id, :title, :content);
        SELECT * FROM posts WHERE id = LAST_INSERT_ID();
    SQL
}

Authorization

If you want to expose SQLer as a direct api to API consumers, you will need to add an authorization layer on top of it, let's see how to do that

addpost {
    authorizer = <<JS
        (function(){
            // $input is a global variable holds all request inputs,
            // including the http headers too (prefixed with `http_`)
            // all http header keys are normalized to be in this form 
            // `http_x_header_example`, `http_authorization` ... etc in lower case.
            token = $input.http_authorization
            response = fetch("http://requestbin.fullcontact.com/zxpjigzx", {
                headers: {
                    "Authorization": token
                }
            })
            if ( response.statusCode != 200 ) {
                return false
            }
            return true
        })()
    JS
}

using that trick, you can use any third-party Authentication service that will remove that hassle from your code.

Data Transformation

In some cases we need to transform the resulted data into something more friendly to our API consumers, so I added javascript interpreter to SQLer so we can transform our data, each js code has a global variable called $result, it holds the result of the exec section, you should write your code like the following:

// list all databases, and run a transformer function
databases {
    exec = "SHOW DATABASES"

    transformer = <<JS
        // there is a global variable called `$result`,
        // `$result` holds the result of the sql execution.
        (function(){
            newResult = []

            for ( i in $result ) {
                newResult.push($result[i].Database)
            }

            return newResult
        })()
    JS
}

Aggregators

SQLer helps you to merge multiple macros into one to minimize the API calls number, see the example bellow

databases {
    exec = "SHOW DATABASES"

    transformer = <<JS
        // there is a global variable called `$result`,
        // `$result` holds the result of the sql execution.
        (function(){
            newResult = []

            for ( i in $result ) {
                newResult.push($result[i].Database)
            }

            return newResult
        })()
    JS
}

tables {
    exec = "SELECT `table_schema` as `database`, `table_name` as `table` FROM INFORMATION_SCHEMA.tables"
    transformer = <<JS
        (function(){
            $ret = {}
            for (  i in $result ) {
                if ( ! $ret[$result[i].database] ) {
                    $ret[$result[i].database] = [];
                }
                $ret[$result[i].database].push($result[i].table)
            }
            return $ret
        })()
    JS
}

databasesAndTables {
    aggregate {
        databases = "current_databases"
        tables = "current_tables"
    }
}

Issue/Suggestion/Contribution ?

SQLer is your software, feel free to open an issue with your feature(s), suggestions, ... etc, also you can easily contribute even you aren't a Go developer, you can write wikis it is open for all, let's make SQLer more powerful.

Author

I'm Mohamed Al Ashaal, just a problem solver :), you can view more projects from me here, and here is my email [email protected]

License

Copyright 2019 The SQLer Authors. All rights reserved. Use of this source code is governed by a Apache 2.0 license that can be found in the LICENSE file.

sqler's People

Contributors

0xflotus avatar alash3al avatar erjanmx avatar jonasjurczok avatar ngaut avatar repodevs avatar sdmg15 avatar sub6resources 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  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  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

sqler's Issues

open wiki

please open the Wiki for documentation

Adding Aggregator

// list all databases, and run a transformer function
databases {
    exec = "SHOW DATABASES"

    transformer = <<JS
        // there is a global variable called `$result`,
        // `$result` holds the result of the sql execution.
        (function(){
            newResult = []

            for ( i in $result ) {
                newResult.push($result[i].Database)
            }

            return newResult
        })()
    JS
}

// list all tables from all databases
tables {
    exec = "SELECT `table_schema` as `database`, `table_name` as `table` FROM INFORMATION_SCHEMA.tables"
    transformer = <<JS
        (function(){
            $ret = {}
            for (  i in $result ) {
                if ( ! $ret[$result[i].database] ) {
                    $ret[$result[i].database] = [];
                }
                $ret[$result[i].database].push($result[i].table)
            }
            return $ret
        })()
    JS
}

databasesAndTables {
    aggregate {
        databases = "current_databases"
        tables = "current_tables"
    }
}

Is this project still maintained?

Hey SQLer!

Just stumbled over this and it looks pretty intriguing. Is there still maintainance here or has it transitioned somewhere else? Forked maybe?

Cheers vuchl

Authorizer calls

Hello,
Are the authorize headers correctly used when contacting an authorizer endpoint? To me it seems the Authorize: BEARER etc isn't passed on to the endpoint.

QUESTION : Stored Procedures and Scalability

At first, I would like to say thanks for all your efforts ๐ŸŽ‰ ๐ŸŽ‰ ๐ŸŽ‰ ๐ŸŽ‰. You have built a fantastic product.

I would like to ask 2 questions

  1. I want to use it just for calling stored procedures, How do I call it from MSSQL?
  2. I would like to use it for huge systems like full-fledged ERP (db would be MSSQL only), so do I need to worry about scalability?

Thanks again for your all efforts and support.

result column order is not respected

In my sqler.hcl is the stanza

logins {
    methods = ["GET"]
    exec = "SELECT id,user,pass,source,time FROM logins ORDER BY id DESC LIMIT 50;"
}

however the resulting json has the columns in alphabetical order:-

id, pass, source, time, user

Manager Get method is not thread safe

I have noticed here that the (key to macro) map is not ensuring any thread safety.
This might cause problems because the Get method gets called here in the Rest server which is concurrent.
Please tell me if I am missing something out.
I would be glad to work on this in a pull request if no one is already working on it.

Not able to install docker on my machine

Hi,
I am not able to install docker on my machine using SQLServer connection string, we are using SQL server with windows authentication with which i am not able to install it. My connection string looks like:
sqler -dsn sqlserver://DIPL13LT42_BARN/SQLEXPRESS?Database=eSSLSmartOffice&connection+timeout=30

kindly help

Support for variations on the same endpoint

I'm attempting to use the following HCL config file to retrieve artists from the database,

artists "all" {
	methods = ["GET"]

	exec = <<SQL
		SELECT * FROM artists;
	SQL
}

artists "filterById" {
	bind {
		id = "$input.id"
	}

	methods = ["GET"]

	exec = <<SQL
		SELECT * FROM artists WHERE artistid = :id;
	SQL
}

This appears to be a valid config file, since the SQLer service starts up just fine

$ sqler -driver sqlite3 -dsn /home/restagner/sqlite/chinook.db -config /home/restagner/SQLer/config.hcl 


                         ____   ___  _              
                        / ___| / _ \| |    ___ _ __ 
                        \___ \| | | | |   / _ \ '__|
                         ___) | |_| | |__|  __/ |   
                        |____/ \__\_\_____\___|_|   

        turn your SQL queries into safe valid RESTful apis.


โ‡จ sqler server version: v1.0 
โ‡จ sqler used driver is sqlite3 
โ‡จ sqler used dsn is /home/restagner/sqlite/chinook.db 
โ‡จ sqler workers count: 4 
โ‡จ sqler resp server available at: :3678 
โ‡จ sqler rest server available at: :8025

However, when I attempt to use either of the following endpoints

curl -i -X GET 'http://localhost:8025/artists'
curl -i -X GET 'http://localhost:8025/artists?id=4'

I receive the following response

HTTP/1.1 500 Internal Server Error
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=UTF-8
Vary: Origin
Vary: Accept-Encoding
Date: Wed, 16 Jan 2019 15:54:27 GMT
Content-Length: 36

{"message":"Internal Server Error"}

And, the server reports with

{
  "time": "2019-01-16T07:38:36.301098256-08:00",
  "level": "-",
  "prefix": "echo",
  "file": "recover.go",
  "line": "73",
  "message": "[PANIC RECOVER] runtime error: slice bounds out of range goroutine 20 [running]:\ngithub.com/labstack/echo/middleware.RecoverWithConfig.func1.1.1(0xc6f338, 0x1000, 0x0, 0xd14dc0, 0xc000412070)\n\t/go/src/github.com/labstack/echo/middleware/recover.go:71 +0xf8\npanic(0xb7cb80, 0x1474620)\n\t/usr/local/go/src/runtime/panic.go:513 +0x1b9\nmain.(*Macro).execSQLQuery(0xc00045c280, 0xc0003d54f0, 0x1, 0x1, 0xc0004c8270, 0x0, 0x0, 0x0, 0x0)\n\t/go/src/github.com/alash3al/sqler/macro.go:92 +0x6fc\nmain.(*Macro).Call(0xc00045c280, 0xc0004c8270, 0xc0004101a0, 0xf, 0xc0000a6648, 0xc0004101a0)\n\t/go/src/github.com/alash3al/sqler/macro.go:59 +0x32d\nmain.routeExecMacro(0xd14dc0, 0xc000412070, 0x5, 0xbebb80)\n\t/go/src/github.com/alash3al/sqler/routes.go:41 +0x5b4\nmain.middlewareAuthorize.func1(0xd14dc0, 0xc000412070, 0xc00041c0f0, 0xc00006ba60)\n\t/go/src/github.com/alash3al/sqler/server_rest.go:95 +0x4dd\ngithub.com/labstack/echo.(*Echo).Add.func1(0xd14dc0, 0xc000412070, 0xc6f338, 0x1000)\n\t/go/src/github.com/labstack/echo/echo.go:490 +0x8a\ngithub.com/labstack/echo/middleware.RecoverWithConfig.func1.1(0xd14dc0, 0xc000412070, 0x0, 0x0)\n\t/go/src/github.com/labstack/echo/middleware/recover.go:78 +0xd8\ngithub.com/labstack/echo/middleware.GzipWithConfig.func1.1(0xd14dc0, 0xc000412070, 0x0, 0x0)\n\t/go/src/github.com/labstack/echo/middleware/compress.go:92 +0x15c\ngithub.com/labstack/echo/middleware.CORSWithConfig.func1.1(0xd14dc0, 0xc000412070, 0x3, 0xc00003a464)\n\t/go/src/github.com/labstack/echo/middleware/cors.go:117 +0x2df\ngithub.com/labstack/echo.(*Echo).ServeHTTP.func1(0xd14dc0, 0xc000412070, 0x1, 0xc00041c060)\n\t/go/src/github.com/labstack/echo/echo.go:585 +0x108\ngithub.com/labstack/echo/middleware.RemoveTrailingSlashWithConfig.func1.1(0xd14dc0, 0xc000412070, 0xc000412070, 0xc00006bd38)\n\t/go/src/github.com/labstack/echo/middleware/slash.go:116 +0x175\ngithub.com/labstack/echo.(*Echo).ServeHTTP(0xc0000d4540, 0xd08a20, 0xc00031e1c0, 0xc000116100)\n\t/go/src/github.com/labstack/echo/echo.go:593 +0x220\nnet/http.serverHandler.ServeHTTP(0xc000420750, 0xd08a20, 0xc00031e1c0, 0xc000116100)\n\t/usr/local/go/src/net/http/server.go:2741 +0xab\nnet/http.(*conn).serve(0xc00009e6e0, 0xd09220, 0xc000426140)\n\t/usr/local/go/src/net/http/server.go:1847 +0x646\ncreated by net/http.(*Server).Serve\n\t/usr/local/go/src/net/http/server.go:2851 +0x2f5\n\ngoroutine 1 [chan receive, 47 minutes]:\nmain.main()\n\t/go/src/github.com/alash3al/sqler/main.go:32 +0x5c9\n\ngoroutine 5 [chan receive]:\ngithub.com/kshvakov/clickhouse.init.0.func1()\n\t/go/src/github.com/kshvakov/clickhouse/bootstrap.go:44 +0x48\ncreated by github.com/kshvakov/clickhouse.init.0\n\t/go/src/github.com/kshvakov/clickhouse/bootstrap.go:41 +0x74\n\ngoroutine 8 [IO wait, 47 minutes]:\ninternal/poll.runtime_pollWait(0x7f99ce3f4e30, 0x72, 0x0)\n\t/usr/local/go/src/runtime/netpoll.go:173 +0x66\ninternal/poll.(*pollDesc).wait(0xc000356d18, 0x72, 0xc000426500, 0x0, 0x0)\n\t/usr/local/go/src/internal/poll/fd_poll_runtime.go:85 +0x9a\ninternal/poll.(*pollDesc).waitRead(0xc000356d18, 0xffffffffffffff00, 0x0, 0x0)\n\t/usr/local/go/src/internal/poll/fd_poll_runtime.go:90 +0x3d\ninternal/poll.(*FD).Accept(0xc000356d00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)\n\t/usr/local/go/src/internal/poll/fd_unix.go:384 +0x1a0\nnet.(*netFD).accept(0xc000356d00, 0xc38443, 0x6, 0x0)\n\t/usr/local/go/src/net/fd_unix.go:238 +0x42\nnet.(*TCPListener).accept(0xc00000e2f0, 0x434b42, 0xc000000008, 0xc0004264c0)\n\t/usr/local/go/src/net/tcpsock_posix.go:139 +0x2e\nnet.(*TCPListener).Accept(0xc00000e2f0, 0xc6f4f0, 0xc0002ac0c0, 0xc3768a, 0x5)\n\t/usr/local/go/src/net/tcpsock.go:260 +0x47\ngithub.com/tidwall/redcon.serve(0xc0002ac0c0, 0x0, 0x0)\n\t/go/src/github.com/tidwall/redcon/redcon.go:292 +0x84\ngithub.com/tidwall/redcon.(*Server).ListenServeAndSignal(0xc0002ac0c0, 0x0, 0xc02d01, 0xc0002ac0c0)\n\t/go/src/github.com/tidwall/redcon/redcon.go:259 +0xe7\ngithub.com/tidwall/redcon.(*Server).ListenAndServe(0xc0002ac0c0, 0xc0002ac0c0, 0xc00005e740)\n\t/go/src/github.com/tidwall/redcon/redcon.go:178 +0x34\ngithub.com/tidwall/redcon.ListenAndServeNetwork(0xc36a6e, 0x3, 0xc3768a, 0x5, 0xc6f9f8, 0xc6fa00, 0x0, 0x7, 0x0)\n\t/go/src/github.com/tidwall/redcon/redcon.go:2\n"
}

How can I support variations on the same endpoint within the HCL?

Best practise for having sqler always running on the server

Hi, just wondering what's the best practise for always running the sql on a windows server.

I can setup a batch file to run the sql with the connections & config files and set a windows task to execute it on windows login, but wondering if there is a better way of doing this?

Thanks

Cannot get source to build due to everything being in main package

I have downloaded the source, and I wanted to see if I could build it (go get github.com/alash3al/sqler && cd ~/go/src/github.com/alash3al/sqler && go build main.go) so that I could either Dockerize it or build from source since I am on a Mac. I wasn't able to do so as all of the constants are in different files, but under the same main which causes build errors. Is there a way I can submit a PR organizing the files better into packages and adding a MakeFile or some other way to so that not only will these errors stop popping up when building from source, but also so that the build process/install process is easier on you and the community?

how can I get the POST json?

When I POST the json payload:

`
import requests

payload = {'a':'v1','u':'v2'}

r = requests.post("http://127.0.0.1:8025/call", data=payload)
`

I got $input :

{"http_content_type":"application/x-www-form-urlencoded","http_user_agent":"python-requests/2.22.0","http_accept_encoding":"gzip, deflate","http_accept":"*/*","http_connection":"keep-alive","http_content_length":"9"}

How can I get the http_content?

Thanks.

gRPC support

Thanks for the great package!

I'll just ask the obligatory question: any plans to support gRPC?

Support data migrations

I presume this is needed as a formal method because you need to check what version the db is at.

Normally data migrations check versions so that they know which migration scripts should be run.
There are other approaches too like naming each script with a daytime stamp and internally storing the datetine inside the db so that a user can just through all scripts at the db and it only runs the scripts after its internal datetime stamp.

sqlite3 is not supported ?

It does not appear that sqlite3 is supported under Linux. I downloaded the latest vesion (2.0) onto my Linux workstation and attempted to run the following

$ sqler -driver sqlite3 -dsn /home/restagner/sqlite/roberts.db -config /home/restagner/SQLer/config.hcl 
[sqlite3] /home/restagner/sqlite/roberts.db - connection error - (Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work. This is a stub)

Am I missing something obvious, here?

Error reporting (Question)

Can SQLer be used to run a sql script (.sql file) that include multiple sql statements (including temp tables, views, etc.)?

If so, how does it return errors if they occur in some of the statements?

Thanks.

Error 1064: You have an error in your SQL syntax from config.example.hcl

{"data":"Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT * FROM users WHERE id = LAST_INSERT_ID()' at line 9","error":"Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT * FROM users WHERE id = LAST_INSERT_ID()' at line 9","success":false}

Pass html templates back over rest

This is really quite innovative.
Light weight scriptin

Can I pass back html using the macros ?

For example
On a get to /index, return html template to the browser.

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.