SQL Generator for mingru-models
npm install mingru



Convert mingru-models to Go code.
All APIs are subject to change before 1.0.0
Goals:
- No performance penalty at runtime, mingru is an SQL builder, not an ORM
- Strongly typed models, models are defined in TypeScript not Go
- Currently focuses on Go and MySQL/MariaDB
---
---
Models are defined in mingru-models. Let's create a simple user model user.ts:
``ts
// ----------- User table model (user.ts) -----------
import * as mm from 'mingru-models';
class User extends mm.Table {
id = mm.pk();
name = mm.varChar(100);
sig = mm.text().nullable;
age = mm.int();
}
export default mm.table(User);
`
Create another file (userTA.ts) for table actions and import the user table (user.ts) we just defined above:
`ts
// ----------- User table actions (userTA.ts) -----------
import * as mm from 'mingru-models';
import user from './user';
export class UserTA extends mm.TableActions {
// Select a user by ID.
selectUser = mm.selectRow(user.id, user.name, user.sig).byID();
// Select all users and order by their names.
selectAllUsers = mm.selectRows(user.id, user.name, user.sig).orderByAsc(user.name);
// Select a single user signature field by ID.
selectUserSig = mm.selectField(user.sig).byID();
// Update a user by ID.
updateUser = mm.updateOne().setParams(user.name, user.sig).byID();
// Update all user signatures to an empty string.
updateAllSigToEmpty = mm.unsafeUpdateAll().set(user.sig, mm.sql'');
// Delete a user by ID.
deleteByID = mm.deleteOne().byID();
// Delete all users by a specified name.
deleteByName = mm.deleteSome().whereSQL(user.name.isEqualToParam());
// Delete all users.
deleteAll = mm.unsafeDeleteAll();
// Insert a new user.
insertUser = mm
.insertOne()
.set(user.sig, mm.sql'Default signature!')
.setParams(user.name, user.age);
}
export default mm.tableActions(user, UserTA);
`
Install mingru-tsconfig:
`sh`
yarn add mingru-tsconfig -D
Set extends to mingru-tsconfig in your local tsconfig.json:
`json`
{
"extends": "mingru-tsconfig"
}
Create a mingru.ts file, which will start the build process to generate Go and SQL code.
`ts
import * as mr from 'mingru';
// Import table actions.
import userTA from './userTA';
// Import tables if you need to generate CREATE TABLE SQL files.
import user from './user';
(async () => {
const dialect = new mr.MySQL();
// Build Go code to '../da/ directory.
const builder = new mr.Builder(dialect, './data_access_layer/', {
// Clean build directory on each build.
cleanBuild: true,
});
const actions = [userTA];
const tables = [user];
// Start the build process by calling the build method.
await builder.buildAsync(async () => {
// Generate Go source files.
await builder.buildActionsAsync(actions);
// Generate CREATE TABLE SQL files.
await builder.buildCreateTableSQLFilesAsync(tables);
});
})();
``
It's also recommended to use ts-node and add a build command to package.json scripts section:
`json`
{
"scripts": {
"build": "ts-node mingru.ts"
}
}
Now you can build your project using yarn build.
Below is the code generated by mingru:
` package da import "github.com/mgenware/mingru-go-lib" // TableTypeUser ... // User ... // ------------ Actions ------------ // DeleteAll ... // DeleteByID ... // DeleteByName ... // InsertUser ... // UserTableSelectAllUsersResult ... // SelectAllUsers ... // UserTableSelectUserResult ... // SelectUser ... // SelectUserSig ... // UpdateAllSigToEmpty ... // UpdateUser ...user_ta.go
(click to expand/collapse)go
/
* This file was automatically generated by mingru (https://github.com/mgenware/mingru)
* Do not edit this file manually, your changes will be overwritten.
/
type UserAGType struct {
}
var User = &UserAGType{}
func (mrTable *UserAGType) DeleteAll(mrQueryable mingru.Queryable) (int, error) {
result, err := mrQueryable.Exec("DELETE FROM user")
return mingru.GetRowsAffectedIntWithError(result, err)
}
func (mrTable *UserAGType) DeleteByID(mrQueryable mingru.Queryable, id uint64) error {
result, err := mrQueryable.Exec("DELETE FROM user WHERE id = ?", id)
return mingru.CheckOneRowAffectedWithError(result, err)
}
func (mrTable *UserAGType) DeleteByName(mrQueryable mingru.Queryable, name string) (int, error) {
result, err := mrQueryable.Exec("DELETE FROM user WHERE name = ?", name)
return mingru.GetRowsAffectedIntWithError(result, err)
}
func (mrTable *UserAGType) InsertUser(mrQueryable mingru.Queryable, name string, age int) (uint64, error) {
result, err := mrQueryable.Exec("INSERT INTO user (sig, name, age) VALUES ('Default signature!', ?, ?)", name, age)
return mingru.GetLastInsertIDUint64WithError(result, err)
}
type UserTableSelectAllUsersResult struct {
ID uint64
Name string
Sig *string
}
func (mrTable UserAGType) SelectAllUsers(mrQueryable mingru.Queryable) ([]UserTableSelectAllUsersResult, error) {
rows, err := mrQueryable.Query("SELECT id, name, sig FROM user ORDER BY name")
if err != nil {
return nil, err
}
result := make([]*UserTableSelectAllUsersResult, 0)
defer rows.Close()
for rows.Next() {
item := &UserTableSelectAllUsersResult{}
err = rows.Scan(&item.ID, &item.Name, &item.Sig)
if err != nil {
return nil, err
}
result = append(result, item)
}
err = rows.Err()
if err != nil {
return nil, err
}
return result, nil
}
type UserTableSelectUserResult struct {
ID uint64
Name string
Sig *string
}
func (mrTable UserAGType) SelectUser(mrQueryable mingru.Queryable, id uint64) (UserTableSelectUserResult, error) {
result := &UserTableSelectUserResult{}
err := mrQueryable.QueryRow("SELECT id, name, sig FROM user WHERE id = ?", id).Scan(&result.ID, &result.Name, &result.Sig)
if err != nil {
return nil, err
}
return result, nil
}
func (mrTable UserAGType) SelectUserSig(mrQueryable mingru.Queryable, id uint64) (string, error) {
var result *string
err := mrQueryable.QueryRow("SELECT sig FROM user WHERE id = ?", id).Scan(&result)
if err != nil {
return result, err
}
return result, nil
}
func (mrTable *UserAGType) UpdateAllSigToEmpty(mrQueryable mingru.Queryable) (int, error) {
result, err := mrQueryable.Exec("UPDATE user SET sig = ''")
return mingru.GetRowsAffectedIntWithError(result, err)
}
func (mrTable UserAGType) UpdateUser(mrQueryable mingru.Queryable, id uint64, name string, sig string) error {
result, err := mrQueryable.Exec("UPDATE user SET name = ?, sig = ? WHERE id = ?", name, sig, id)`
return mingru.CheckOneRowAffectedWithError(result, err)
}
`user.sql
for creating table (click to expand/collapse)sqluser
CREATE TABLE (id
BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,name
VARCHAR(100) NOT NULL,sig
TEXT NULL DEFAULT NULL,age
INT NOT NULL,id
PRIMARY KEY ()`
)
CHARACTER SET=utf8mb4
COLLATE=utf8mb4_unicode_ci
;
`go
func main() {
// Open a DB connection on localhost.
db, err := sql.Open("mysql", "root:123456@/test")
if err != nil {
panic(err)
}
// Select all user profiles.
users, err := da.User.SelectAllUserProfiles(db)
if err != nil {
panic(err)
}
// Loop through the result.
for _, user := range users {
fmt.Printf("ID: %v, Name: %v, Sig: %v\n", user.ID, user.Name, user.Sig)
}
}
`
For a more detailed and runnable example, visit mingru-go-example
MySQL doesn't allow you to use a non-constant value as a default value for a column because CREATE TABLE doesn't allow it. mingru supports arbitrary default values for both CREATE and UPDATE actions by simply passing default values into generated SQL.
#### limit
Pagination can be achieved by calling limit following a call to selectRows:
`ts`
selectUsersWithLimit = mm.selectRows(user.id, user.name).limit();
Implementations should expose arguments to set the underlying SQL LIMIT and OFFSET values, here is the Go method signature generated by mingru from the action above:
`go`
func (mrTable UserAGType) SelectUsersWithLimit(mrQueryable mingru.Queryable, limit int, offset int, max int) ([]SelectUsersWithLimitResult, int, error)
#### selectPage
Pagination can also be done via selectPage method, selectPage usually generates a method built upon the SQL LIMIT and OFFSET clauses but exposes higher level arguments thus provides more convenience:
`ts`
selectPagedUsers = mm.selectPage(user.id, user.name);
mingru converts the action above to the following Go func:
`go`
func (mrTable UserAGType) SelectPagedUsers(mrQueryable mingru.Queryable, page int, pageSize int) ([]SelectPagedUsersResult, bool, error)
Notice the limit and offset arguments are gone, page and pageSize are exposed instead. Also the second return value changed from rowsFetched(int) to hasNextPage(bool`).