0.63.0 • Published 11 months ago

mingru v0.63.0

Weekly downloads
66
License
MIT
Repository
github
Last release
11 months ago

mingru (WIP)

Build Status MEAN Module npm version Node.js Version

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

NOTE: The documentation below is outdated!!! We are working on a brand new documentation site. Stay tuned.


A quick example

Step 1: Define models

Models are defined in mingru-models. Let's create a simple user model user.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);

Step 2: Define actions

Create another file (userTA.ts) for table actions and import the user table (user.ts) we just defined above:

// ----------- 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);

Step 3: Generate Go Code

Install mingru-tsconfig:

yarn add mingru-tsconfig -D

Set extends to mingru-tsconfig in your local tsconfig.json:

{
  "extends": "mingru-tsconfig"
}

Create a mingru.ts file, which will start the build process to generate Go and SQL code.

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:

{
  "scripts": {
    "build": "ts-node mingru.ts"
  }
}

Now you can build your project using yarn build.

Below is the code generated by mingru:

/******************************************************************************************
 * This file was automatically generated by mingru (https://github.com/mgenware/mingru)
 * Do not edit this file manually, your changes will be overwritten.
 ******************************************************************************************/

package da

import "github.com/mgenware/mingru-go-lib"

// TableTypeUser ...
type UserAGType struct {
}

// User ...
var User = &UserAGType{}

// ------------ Actions ------------

// DeleteAll ...
func (mrTable *UserAGType) DeleteAll(mrQueryable mingru.Queryable) (int, error) {
	result, err := mrQueryable.Exec("DELETE FROM `user`")
	return mingru.GetRowsAffectedIntWithError(result, err)
}

// DeleteByID ...
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)
}

// DeleteByName ...
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)
}

// InsertUser ...
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)
}

// UserTableSelectAllUsersResult ...
type UserTableSelectAllUsersResult struct {
	ID   uint64
	Name string
	Sig  *string
}

// SelectAllUsers ...
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
}

// UserTableSelectUserResult ...
type UserTableSelectUserResult struct {
	ID   uint64
	Name string
	Sig  *string
}

// SelectUser ...
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
}

// SelectUserSig ...
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
}

// UpdateAllSigToEmpty ...
func (mrTable *UserAGType) UpdateAllSigToEmpty(mrQueryable mingru.Queryable) (int, error) {
	result, err := mrQueryable.Exec("UPDATE `user` SET `sig` = ''")
	return mingru.GetRowsAffectedIntWithError(result, err)
}

// UpdateUser ...
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)
}
CREATE TABLE `user` (
	`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
	`name` VARCHAR(100) NOT NULL,
	`sig` TEXT NULL DEFAULT NULL,
	`age` INT NOT NULL,
	PRIMARY KEY (`id`)
)
CHARACTER SET=utf8mb4
COLLATE=utf8mb4_unicode_ci
;

Step 4: Use the generated code in your Go project

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)
	}
}

More examples

For a more detailed and runnable example, visit mingru-go-example

Advanced Topics

Default Values

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.

Pagination

limit

Pagination can be achieved by calling limit following a call to selectRows:

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:

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:

selectPagedUsers = mm.selectPage(user.id, user.name);

mingru converts the action above to the following Go func:

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).

0.62.0

11 months ago

0.63.0

11 months ago

0.61.0

1 year ago

0.60.7

2 years ago

0.60.9

2 years ago

0.60.8

2 years ago

0.60.10

2 years ago

0.60.6

2 years ago

0.60.3

2 years ago

0.60.2

2 years ago

0.60.5

2 years ago

0.59.2

2 years ago

0.59.3

2 years ago

0.59.0

2 years ago

0.59.1

2 years ago

0.59.4

2 years ago

0.59.5

2 years ago

0.60.1

2 years ago

0.60.0

2 years ago

0.58.3

2 years ago

0.57.0

2 years ago

0.58.1

2 years ago

0.58.2

2 years ago

0.58.0

2 years ago

0.55.0

2 years ago

0.53.2

2 years ago

0.53.0

2 years ago

0.53.1

2 years ago

0.51.0

2 years ago

0.56.1

2 years ago

0.54.1

2 years ago

0.56.0

2 years ago

0.54.0

2 years ago

0.52.0

2 years ago

0.50.3

2 years ago

0.50.2

2 years ago

0.50.1

3 years ago

0.50.0

3 years ago

0.49.0

3 years ago

0.48.0

3 years ago

0.47.1

3 years ago

0.47.0

3 years ago

0.46.1

3 years ago

0.46.0

3 years ago

0.45.1

3 years ago

0.45.0

3 years ago

0.44.2

3 years ago

0.44.1

3 years ago

0.44.0

3 years ago

0.43.0

3 years ago

0.42.0

3 years ago

0.41.0

3 years ago

0.40.0

3 years ago

0.39.0

3 years ago

0.38.0

3 years ago

0.37.0

4 years ago

0.36.0

4 years ago

0.35.1

4 years ago

0.35.0

4 years ago

0.34.0

4 years ago

0.33.0

4 years ago

0.32.0

4 years ago

0.31.0

4 years ago

0.30.0

4 years ago

0.29.1

4 years ago

0.29.0

4 years ago

0.28.1

4 years ago

0.28.0

4 years ago

0.27.0

4 years ago

0.26.0

4 years ago

0.25.0

4 years ago

0.24.0

4 years ago

0.23.0

4 years ago

0.22.0

4 years ago

0.21.0

4 years ago

0.20.0

4 years ago

0.19.0

4 years ago

0.18.0

4 years ago

0.17.0

5 years ago

0.16.0

5 years ago

0.15.1

5 years ago

0.15.0

5 years ago

0.14.1

5 years ago

0.14.0

5 years ago

0.13.1

5 years ago

0.13.0

5 years ago

0.12.1

5 years ago

0.12.0

5 years ago

0.11.0

5 years ago

0.10.0

5 years ago

0.9.0

5 years ago

0.8.0

5 years ago

0.7.2

5 years ago

0.7.1

5 years ago

0.7.0

5 years ago

0.6.0

5 years ago

0.5.0

5 years ago

0.4.3

5 years ago

0.4.2

5 years ago

0.4.1

5 years ago

0.4.0

5 years ago

0.3.0

5 years ago

0.2.2

5 years ago

0.2.1

5 years ago

0.2.0

5 years ago

0.1.5

5 years ago

0.1.4

5 years ago

0.1.3

5 years ago

0.1.2

5 years ago

0.1.1

5 years ago

0.1.0

5 years ago

0.0.2

6 years ago