This commit is contained in:
Lukas Bachschwell 2018-11-06 12:31:49 +01:00
commit d6ff222741
26 changed files with 3105 additions and 0 deletions

11
Readme.md Normal file
View File

@ -0,0 +1,11 @@
# MutlitenantStack
This is a project to demonstrate multi tenancy usage in beego using postgres and seperated databases
The api was scaffolded using:
`bee api multitenantStack -driver=postgres -conn="host=127.0.0.1 port=5435 user=postgres password=postgre dbname=company_template sslmode=disable"`
then `bee run -downdoc=true``
To regenerate docs simply run `bee generate docs`

6
conf/app.conf Normal file
View File

@ -0,0 +1,6 @@
appname = multitenantStack
httpport = 8080
runmode = dev
autorender = false
copyrequestbody = true
EnableDocs = true

171
controllers/company_data.go Normal file
View File

@ -0,0 +1,171 @@
package controllers
import (
"encoding/json"
"errors"
"multitenantStack/models"
"strconv"
"strings"
"github.com/astaxie/beego"
)
// CompanyDataController operations for CompanyData
type CompanyDataController struct {
beego.Controller
}
// URLMapping ...
func (c *CompanyDataController) URLMapping() {
c.Mapping("Post", c.Post)
c.Mapping("GetOne", c.GetOne)
c.Mapping("GetAll", c.GetAll)
c.Mapping("Put", c.Put)
c.Mapping("Delete", c.Delete)
}
// Post ...
// @Title Post
// @Description create CompanyData
// @Param body body models.CompanyData true "body for CompanyData content"
// @Success 201 {int} models.CompanyData
// @Failure 403 body is empty
// @router / [post]
func (c *CompanyDataController) Post() {
var v models.CompanyData
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil {
if _, err := models.AddCompanyData(&v); err == nil {
c.Ctx.Output.SetStatus(201)
c.Data["json"] = v
} else {
c.Data["json"] = err.Error()
}
} else {
c.Data["json"] = err.Error()
}
c.ServeJSON()
}
// GetOne ...
// @Title Get One
// @Description get CompanyData by id
// @Param id path string true "The key for staticblock"
// @Success 200 {object} models.CompanyData
// @Failure 403 :id is empty
// @router /:id [get]
func (c *CompanyDataController) GetOne() {
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.Atoi(idStr)
v, err := models.GetCompanyDataById(id)
if err != nil {
c.Data["json"] = err.Error()
} else {
c.Data["json"] = v
}
c.ServeJSON()
}
// GetAll ...
// @Title Get All
// @Description get CompanyData
// @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..."
// @Param fields query string false "Fields returned. e.g. col1,col2 ..."
// @Param sortby query string false "Sorted-by fields. e.g. col1,col2 ..."
// @Param order query string false "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..."
// @Param limit query string false "Limit the size of result set. Must be an integer"
// @Param offset query string false "Start position of result set. Must be an integer"
// @Success 200 {object} models.CompanyData
// @Failure 403
// @router / [get]
func (c *CompanyDataController) GetAll() {
var fields []string
var sortby []string
var order []string
var query = make(map[string]string)
var limit int64 = 10
var offset int64
// fields: col1,col2,entity.col3
if v := c.GetString("fields"); v != "" {
fields = strings.Split(v, ",")
}
// limit: 10 (default is 10)
if v, err := c.GetInt64("limit"); err == nil {
limit = v
}
// offset: 0 (default is 0)
if v, err := c.GetInt64("offset"); err == nil {
offset = v
}
// sortby: col1,col2
if v := c.GetString("sortby"); v != "" {
sortby = strings.Split(v, ",")
}
// order: desc,asc
if v := c.GetString("order"); v != "" {
order = strings.Split(v, ",")
}
// query: k:v,k:v
if v := c.GetString("query"); v != "" {
for _, cond := range strings.Split(v, ",") {
kv := strings.SplitN(cond, ":", 2)
if len(kv) != 2 {
c.Data["json"] = errors.New("Error: invalid query key/value pair")
c.ServeJSON()
return
}
k, v := kv[0], kv[1]
query[k] = v
}
}
l, err := models.GetAllCompanyData(query, fields, sortby, order, offset, limit)
if err != nil {
c.Data["json"] = err.Error()
} else {
c.Data["json"] = l
}
c.ServeJSON()
}
// Put ...
// @Title Put
// @Description update the CompanyData
// @Param id path string true "The id you want to update"
// @Param body body models.CompanyData true "body for CompanyData content"
// @Success 200 {object} models.CompanyData
// @Failure 403 :id is not int
// @router /:id [put]
func (c *CompanyDataController) Put() {
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.Atoi(idStr)
v := models.CompanyData{Id: id}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil {
if err := models.UpdateCompanyDataById(&v); err == nil {
c.Data["json"] = "OK"
} else {
c.Data["json"] = err.Error()
}
} else {
c.Data["json"] = err.Error()
}
c.ServeJSON()
}
// Delete ...
// @Title Delete
// @Description delete the CompanyData
// @Param id path string true "The id you want to delete"
// @Success 200 {string} delete success!
// @Failure 403 id is empty
// @router /:id [delete]
func (c *CompanyDataController) Delete() {
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.Atoi(idStr)
if err := models.DeleteCompanyData(id); err == nil {
c.Data["json"] = "OK"
} else {
c.Data["json"] = err.Error()
}
c.ServeJSON()
}

171
controllers/company_user.go Normal file
View File

@ -0,0 +1,171 @@
package controllers
import (
"encoding/json"
"errors"
"multitenantStack/models"
"strconv"
"strings"
"github.com/astaxie/beego"
)
// CompanyUserController operations for CompanyUser
type CompanyUserController struct {
beego.Controller
}
// URLMapping ...
func (c *CompanyUserController) URLMapping() {
c.Mapping("Post", c.Post)
c.Mapping("GetOne", c.GetOne)
c.Mapping("GetAll", c.GetAll)
c.Mapping("Put", c.Put)
c.Mapping("Delete", c.Delete)
}
// Post ...
// @Title Post
// @Description create CompanyUser
// @Param body body models.CompanyUser true "body for CompanyUser content"
// @Success 201 {int} models.CompanyUser
// @Failure 403 body is empty
// @router / [post]
func (c *CompanyUserController) Post() {
var v models.CompanyUser
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil {
if _, err := models.AddCompanyUser(&v); err == nil {
c.Ctx.Output.SetStatus(201)
c.Data["json"] = v
} else {
c.Data["json"] = err.Error()
}
} else {
c.Data["json"] = err.Error()
}
c.ServeJSON()
}
// GetOne ...
// @Title Get One
// @Description get CompanyUser by id
// @Param id path string true "The key for staticblock"
// @Success 200 {object} models.CompanyUser
// @Failure 403 :id is empty
// @router /:id [get]
func (c *CompanyUserController) GetOne() {
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.Atoi(idStr)
v, err := models.GetCompanyUserById(id)
if err != nil {
c.Data["json"] = err.Error()
} else {
c.Data["json"] = v
}
c.ServeJSON()
}
// GetAll ...
// @Title Get All
// @Description get CompanyUser
// @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..."
// @Param fields query string false "Fields returned. e.g. col1,col2 ..."
// @Param sortby query string false "Sorted-by fields. e.g. col1,col2 ..."
// @Param order query string false "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..."
// @Param limit query string false "Limit the size of result set. Must be an integer"
// @Param offset query string false "Start position of result set. Must be an integer"
// @Success 200 {object} models.CompanyUser
// @Failure 403
// @router / [get]
func (c *CompanyUserController) GetAll() {
var fields []string
var sortby []string
var order []string
var query = make(map[string]string)
var limit int64 = 10
var offset int64
// fields: col1,col2,entity.col3
if v := c.GetString("fields"); v != "" {
fields = strings.Split(v, ",")
}
// limit: 10 (default is 10)
if v, err := c.GetInt64("limit"); err == nil {
limit = v
}
// offset: 0 (default is 0)
if v, err := c.GetInt64("offset"); err == nil {
offset = v
}
// sortby: col1,col2
if v := c.GetString("sortby"); v != "" {
sortby = strings.Split(v, ",")
}
// order: desc,asc
if v := c.GetString("order"); v != "" {
order = strings.Split(v, ",")
}
// query: k:v,k:v
if v := c.GetString("query"); v != "" {
for _, cond := range strings.Split(v, ",") {
kv := strings.SplitN(cond, ":", 2)
if len(kv) != 2 {
c.Data["json"] = errors.New("Error: invalid query key/value pair")
c.ServeJSON()
return
}
k, v := kv[0], kv[1]
query[k] = v
}
}
l, err := models.GetAllCompanyUser(query, fields, sortby, order, offset, limit)
if err != nil {
c.Data["json"] = err.Error()
} else {
c.Data["json"] = l
}
c.ServeJSON()
}
// Put ...
// @Title Put
// @Description update the CompanyUser
// @Param id path string true "The id you want to update"
// @Param body body models.CompanyUser true "body for CompanyUser content"
// @Success 200 {object} models.CompanyUser
// @Failure 403 :id is not int
// @router /:id [put]
func (c *CompanyUserController) Put() {
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.Atoi(idStr)
v := models.CompanyUser{Id: id}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil {
if err := models.UpdateCompanyUserById(&v); err == nil {
c.Data["json"] = "OK"
} else {
c.Data["json"] = err.Error()
}
} else {
c.Data["json"] = err.Error()
}
c.ServeJSON()
}
// Delete ...
// @Title Delete
// @Description delete the CompanyUser
// @Param id path string true "The id you want to delete"
// @Success 200 {string} delete success!
// @Failure 403 id is empty
// @router /:id [delete]
func (c *CompanyUserController) Delete() {
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.Atoi(idStr)
if err := models.DeleteCompanyUser(id); err == nil {
c.Data["json"] = "OK"
} else {
c.Data["json"] = err.Error()
}
c.ServeJSON()
}

171
controllers/contact.go Normal file
View File

@ -0,0 +1,171 @@
package controllers
import (
"encoding/json"
"errors"
"multitenantStack/models"
"strconv"
"strings"
"github.com/astaxie/beego"
)
// ContactController operations for Contact
type ContactController struct {
beego.Controller
}
// URLMapping ...
func (c *ContactController) URLMapping() {
c.Mapping("Post", c.Post)
c.Mapping("GetOne", c.GetOne)
c.Mapping("GetAll", c.GetAll)
c.Mapping("Put", c.Put)
c.Mapping("Delete", c.Delete)
}
// Post ...
// @Title Post
// @Description create Contact
// @Param body body models.Contact true "body for Contact content"
// @Success 201 {int} models.Contact
// @Failure 403 body is empty
// @router / [post]
func (c *ContactController) Post() {
var v models.Contact
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil {
if _, err := models.AddContact(&v); err == nil {
c.Ctx.Output.SetStatus(201)
c.Data["json"] = v
} else {
c.Data["json"] = err.Error()
}
} else {
c.Data["json"] = err.Error()
}
c.ServeJSON()
}
// GetOne ...
// @Title Get One
// @Description get Contact by id
// @Param id path string true "The key for staticblock"
// @Success 200 {object} models.Contact
// @Failure 403 :id is empty
// @router /:id [get]
func (c *ContactController) GetOne() {
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.Atoi(idStr)
v, err := models.GetContactById(id)
if err != nil {
c.Data["json"] = err.Error()
} else {
c.Data["json"] = v
}
c.ServeJSON()
}
// GetAll ...
// @Title Get All
// @Description get Contact
// @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..."
// @Param fields query string false "Fields returned. e.g. col1,col2 ..."
// @Param sortby query string false "Sorted-by fields. e.g. col1,col2 ..."
// @Param order query string false "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..."
// @Param limit query string false "Limit the size of result set. Must be an integer"
// @Param offset query string false "Start position of result set. Must be an integer"
// @Success 200 {object} models.Contact
// @Failure 403
// @router / [get]
func (c *ContactController) GetAll() {
var fields []string
var sortby []string
var order []string
var query = make(map[string]string)
var limit int64 = 10
var offset int64
// fields: col1,col2,entity.col3
if v := c.GetString("fields"); v != "" {
fields = strings.Split(v, ",")
}
// limit: 10 (default is 10)
if v, err := c.GetInt64("limit"); err == nil {
limit = v
}
// offset: 0 (default is 0)
if v, err := c.GetInt64("offset"); err == nil {
offset = v
}
// sortby: col1,col2
if v := c.GetString("sortby"); v != "" {
sortby = strings.Split(v, ",")
}
// order: desc,asc
if v := c.GetString("order"); v != "" {
order = strings.Split(v, ",")
}
// query: k:v,k:v
if v := c.GetString("query"); v != "" {
for _, cond := range strings.Split(v, ",") {
kv := strings.SplitN(cond, ":", 2)
if len(kv) != 2 {
c.Data["json"] = errors.New("Error: invalid query key/value pair")
c.ServeJSON()
return
}
k, v := kv[0], kv[1]
query[k] = v
}
}
l, err := models.GetAllContact(query, fields, sortby, order, offset, limit)
if err != nil {
c.Data["json"] = err.Error()
} else {
c.Data["json"] = l
}
c.ServeJSON()
}
// Put ...
// @Title Put
// @Description update the Contact
// @Param id path string true "The id you want to update"
// @Param body body models.Contact true "body for Contact content"
// @Success 200 {object} models.Contact
// @Failure 403 :id is not int
// @router /:id [put]
func (c *ContactController) Put() {
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.Atoi(idStr)
v := models.Contact{Id: id}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil {
if err := models.UpdateContactById(&v); err == nil {
c.Data["json"] = "OK"
} else {
c.Data["json"] = err.Error()
}
} else {
c.Data["json"] = err.Error()
}
c.ServeJSON()
}
// Delete ...
// @Title Delete
// @Description delete the Contact
// @Param id path string true "The id you want to delete"
// @Success 200 {string} delete success!
// @Failure 403 id is empty
// @router /:id [delete]
func (c *ContactController) Delete() {
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.Atoi(idStr)
if err := models.DeleteContact(id); err == nil {
c.Data["json"] = "OK"
} else {
c.Data["json"] = err.Error()
}
c.ServeJSON()
}

171
controllers/post.go Normal file
View File

@ -0,0 +1,171 @@
package controllers
import (
"encoding/json"
"errors"
"multitenantStack/models"
"strconv"
"strings"
"github.com/astaxie/beego"
)
// PostController operations for Post
type PostController struct {
beego.Controller
}
// URLMapping ...
func (c *PostController) URLMapping() {
c.Mapping("Post", c.Post)
c.Mapping("GetOne", c.GetOne)
c.Mapping("GetAll", c.GetAll)
c.Mapping("Put", c.Put)
c.Mapping("Delete", c.Delete)
}
// Post ...
// @Title Post
// @Description create Post
// @Param body body models.Post true "body for Post content"
// @Success 201 {int} models.Post
// @Failure 403 body is empty
// @router / [post]
func (c *PostController) Post() {
var v models.Post
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil {
if _, err := models.AddPost(&v); err == nil {
c.Ctx.Output.SetStatus(201)
c.Data["json"] = v
} else {
c.Data["json"] = err.Error()
}
} else {
c.Data["json"] = err.Error()
}
c.ServeJSON()
}
// GetOne ...
// @Title Get One
// @Description get Post by id
// @Param id path string true "The key for staticblock"
// @Success 200 {object} models.Post
// @Failure 403 :id is empty
// @router /:id [get]
func (c *PostController) GetOne() {
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.Atoi(idStr)
v, err := models.GetPostById(id)
if err != nil {
c.Data["json"] = err.Error()
} else {
c.Data["json"] = v
}
c.ServeJSON()
}
// GetAll ...
// @Title Get All
// @Description get Post
// @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..."
// @Param fields query string false "Fields returned. e.g. col1,col2 ..."
// @Param sortby query string false "Sorted-by fields. e.g. col1,col2 ..."
// @Param order query string false "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..."
// @Param limit query string false "Limit the size of result set. Must be an integer"
// @Param offset query string false "Start position of result set. Must be an integer"
// @Success 200 {object} models.Post
// @Failure 403
// @router / [get]
func (c *PostController) GetAll() {
var fields []string
var sortby []string
var order []string
var query = make(map[string]string)
var limit int64 = 10
var offset int64
// fields: col1,col2,entity.col3
if v := c.GetString("fields"); v != "" {
fields = strings.Split(v, ",")
}
// limit: 10 (default is 10)
if v, err := c.GetInt64("limit"); err == nil {
limit = v
}
// offset: 0 (default is 0)
if v, err := c.GetInt64("offset"); err == nil {
offset = v
}
// sortby: col1,col2
if v := c.GetString("sortby"); v != "" {
sortby = strings.Split(v, ",")
}
// order: desc,asc
if v := c.GetString("order"); v != "" {
order = strings.Split(v, ",")
}
// query: k:v,k:v
if v := c.GetString("query"); v != "" {
for _, cond := range strings.Split(v, ",") {
kv := strings.SplitN(cond, ":", 2)
if len(kv) != 2 {
c.Data["json"] = errors.New("Error: invalid query key/value pair")
c.ServeJSON()
return
}
k, v := kv[0], kv[1]
query[k] = v
}
}
l, err := models.GetAllPost(query, fields, sortby, order, offset, limit)
if err != nil {
c.Data["json"] = err.Error()
} else {
c.Data["json"] = l
}
c.ServeJSON()
}
// Put ...
// @Title Put
// @Description update the Post
// @Param id path string true "The id you want to update"
// @Param body body models.Post true "body for Post content"
// @Success 200 {object} models.Post
// @Failure 403 :id is not int
// @router /:id [put]
func (c *PostController) Put() {
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.Atoi(idStr)
v := models.Post{Id: id}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil {
if err := models.UpdatePostById(&v); err == nil {
c.Data["json"] = "OK"
} else {
c.Data["json"] = err.Error()
}
} else {
c.Data["json"] = err.Error()
}
c.ServeJSON()
}
// Delete ...
// @Title Delete
// @Description delete the Post
// @Param id path string true "The id you want to delete"
// @Success 200 {string} delete success!
// @Failure 403 id is empty
// @router /:id [delete]
func (c *PostController) Delete() {
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.Atoi(idStr)
if err := models.DeletePost(id); err == nil {
c.Data["json"] = "OK"
} else {
c.Data["json"] = err.Error()
}
c.ServeJSON()
}

21
main.go Normal file
View File

@ -0,0 +1,21 @@
package main
import (
_ "multitenantStack/routers"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
_ "github.com/lib/pq"
)
func init() {
orm.RegisterDataBase("default", "postgres", "host=127.0.0.1 port=5435 user=postgres password=postgre dbname=company_template sslmode=disable")
if beego.BConfig.RunMode == "dev" {
beego.BConfig.WebConfig.DirectoryIndex = true
beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
}
}
func main() {
beego.Run()
}

155
models/company_data.go Normal file
View File

@ -0,0 +1,155 @@
package models
import (
"errors"
"fmt"
"reflect"
"strings"
"time"
"github.com/astaxie/beego/orm"
)
type CompanyData struct {
Id int `orm:"column(id);pk"`
Key string `orm:"column(key)"`
Value string `orm:"column(value);null"`
Data string `orm:"column(data);null"`
Created time.Time `orm:"column(created);type(timestamp with time zone);auto_now_add"`
Modified time.Time `orm:"column(modified);type(timestamp with time zone);auto_now_add"`
}
func (t *CompanyData) TableName() string {
return "company_data"
}
func init() {
orm.RegisterModel(new(CompanyData))
}
// AddCompanyData insert a new CompanyData into database and returns
// last inserted Id on success.
func AddCompanyData(m *CompanyData) (id int64, err error) {
o := orm.NewOrm()
id, err = o.Insert(m)
return
}
// GetCompanyDataById retrieves CompanyData by Id. Returns error if
// Id doesn't exist
func GetCompanyDataById(id int) (v *CompanyData, err error) {
o := orm.NewOrm()
v = &CompanyData{Id: id}
if err = o.Read(v); err == nil {
return v, nil
}
return nil, err
}
// GetAllCompanyData retrieves all CompanyData matches certain condition. Returns empty list if
// no records exist
func GetAllCompanyData(query map[string]string, fields []string, sortby []string, order []string,
offset int64, limit int64) (ml []interface{}, err error) {
o := orm.NewOrm()
qs := o.QueryTable(new(CompanyData))
// query k=v
for k, v := range query {
// rewrite dot-notation to Object__Attribute
k = strings.Replace(k, ".", "__", -1)
if strings.Contains(k, "isnull") {
qs = qs.Filter(k, (v == "true" || v == "1"))
} else {
qs = qs.Filter(k, v)
}
}
// order by:
var sortFields []string
if len(sortby) != 0 {
if len(sortby) == len(order) {
// 1) for each sort field, there is an associated order
for i, v := range sortby {
orderby := ""
if order[i] == "desc" {
orderby = "-" + v
} else if order[i] == "asc" {
orderby = v
} else {
return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
}
sortFields = append(sortFields, orderby)
}
qs = qs.OrderBy(sortFields...)
} else if len(sortby) != len(order) && len(order) == 1 {
// 2) there is exactly one order, all the sorted fields will be sorted by this order
for _, v := range sortby {
orderby := ""
if order[0] == "desc" {
orderby = "-" + v
} else if order[0] == "asc" {
orderby = v
} else {
return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
}
sortFields = append(sortFields, orderby)
}
} else if len(sortby) != len(order) && len(order) != 1 {
return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
}
} else {
if len(order) != 0 {
return nil, errors.New("Error: unused 'order' fields")
}
}
var l []CompanyData
qs = qs.OrderBy(sortFields...)
if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
if len(fields) == 0 {
for _, v := range l {
ml = append(ml, v)
}
} else {
// trim unused fields
for _, v := range l {
m := make(map[string]interface{})
val := reflect.ValueOf(v)
for _, fname := range fields {
m[fname] = val.FieldByName(fname).Interface()
}
ml = append(ml, m)
}
}
return ml, nil
}
return nil, err
}
// UpdateCompanyData updates CompanyData by Id and returns error if
// the record to be updated doesn't exist
func UpdateCompanyDataById(m *CompanyData) (err error) {
o := orm.NewOrm()
v := CompanyData{Id: m.Id}
// ascertain id exists in the database
if err = o.Read(&v); err == nil {
var num int64
if num, err = o.Update(m); err == nil {
fmt.Println("Number of records updated in database:", num)
}
}
return
}
// DeleteCompanyData deletes CompanyData by Id and returns error if
// the record to be deleted doesn't exist
func DeleteCompanyData(id int) (err error) {
o := orm.NewOrm()
v := CompanyData{Id: id}
// ascertain id exists in the database
if err = o.Read(&v); err == nil {
var num int64
if num, err = o.Delete(&CompanyData{Id: id}); err == nil {
fmt.Println("Number of records deleted in database:", num)
}
}
return
}

155
models/company_user.go Normal file
View File

@ -0,0 +1,155 @@
package models
import (
"errors"
"fmt"
"reflect"
"strings"
"time"
"github.com/astaxie/beego/orm"
)
type CompanyUser struct {
Id int `orm:"column(id);pk"`
Name string `orm:"column(name)"`
Role int16 `orm:"column(role)"`
Profile string `orm:"column(profile)"`
Created time.Time `orm:"column(created);type(timestamp with time zone);auto_now_add"`
Modified time.Time `orm:"column(modified);type(timestamp with time zone);auto_now_add"`
}
func (t *CompanyUser) TableName() string {
return "company_user"
}
func init() {
orm.RegisterModel(new(CompanyUser))
}
// AddCompanyUser insert a new CompanyUser into database and returns
// last inserted Id on success.
func AddCompanyUser(m *CompanyUser) (id int64, err error) {
o := orm.NewOrm()
id, err = o.Insert(m)
return
}
// GetCompanyUserById retrieves CompanyUser by Id. Returns error if
// Id doesn't exist
func GetCompanyUserById(id int) (v *CompanyUser, err error) {
o := orm.NewOrm()
v = &CompanyUser{Id: id}
if err = o.Read(v); err == nil {
return v, nil
}
return nil, err
}
// GetAllCompanyUser retrieves all CompanyUser matches certain condition. Returns empty list if
// no records exist
func GetAllCompanyUser(query map[string]string, fields []string, sortby []string, order []string,
offset int64, limit int64) (ml []interface{}, err error) {
o := orm.NewOrm()
qs := o.QueryTable(new(CompanyUser))
// query k=v
for k, v := range query {
// rewrite dot-notation to Object__Attribute
k = strings.Replace(k, ".", "__", -1)
if strings.Contains(k, "isnull") {
qs = qs.Filter(k, (v == "true" || v == "1"))
} else {
qs = qs.Filter(k, v)
}
}
// order by:
var sortFields []string
if len(sortby) != 0 {
if len(sortby) == len(order) {
// 1) for each sort field, there is an associated order
for i, v := range sortby {
orderby := ""
if order[i] == "desc" {
orderby = "-" + v
} else if order[i] == "asc" {
orderby = v
} else {
return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
}
sortFields = append(sortFields, orderby)
}
qs = qs.OrderBy(sortFields...)
} else if len(sortby) != len(order) && len(order) == 1 {
// 2) there is exactly one order, all the sorted fields will be sorted by this order
for _, v := range sortby {
orderby := ""
if order[0] == "desc" {
orderby = "-" + v
} else if order[0] == "asc" {
orderby = v
} else {
return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
}
sortFields = append(sortFields, orderby)
}
} else if len(sortby) != len(order) && len(order) != 1 {
return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
}
} else {
if len(order) != 0 {
return nil, errors.New("Error: unused 'order' fields")
}
}
var l []CompanyUser
qs = qs.OrderBy(sortFields...)
if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
if len(fields) == 0 {
for _, v := range l {
ml = append(ml, v)
}
} else {
// trim unused fields
for _, v := range l {
m := make(map[string]interface{})
val := reflect.ValueOf(v)
for _, fname := range fields {
m[fname] = val.FieldByName(fname).Interface()
}
ml = append(ml, m)
}
}
return ml, nil
}
return nil, err
}
// UpdateCompanyUser updates CompanyUser by Id and returns error if
// the record to be updated doesn't exist
func UpdateCompanyUserById(m *CompanyUser) (err error) {
o := orm.NewOrm()
v := CompanyUser{Id: m.Id}
// ascertain id exists in the database
if err = o.Read(&v); err == nil {
var num int64
if num, err = o.Update(m); err == nil {
fmt.Println("Number of records updated in database:", num)
}
}
return
}
// DeleteCompanyUser deletes CompanyUser by Id and returns error if
// the record to be deleted doesn't exist
func DeleteCompanyUser(id int) (err error) {
o := orm.NewOrm()
v := CompanyUser{Id: id}
// ascertain id exists in the database
if err = o.Read(&v); err == nil {
var num int64
if num, err = o.Delete(&CompanyUser{Id: id}); err == nil {
fmt.Println("Number of records deleted in database:", num)
}
}
return
}

158
models/contact.go Normal file
View File

@ -0,0 +1,158 @@
package models
import (
"errors"
"fmt"
"reflect"
"strings"
"time"
"github.com/astaxie/beego/orm"
)
type Contact struct {
Id int `orm:"column(id);pk"`
FirstName string `orm:"column(firstName);null"`
LastName string `orm:"column(lastName)"`
PhoneNumber string `orm:"column(phoneNumber);null"`
Email string `orm:"column(email);null"`
LastContact time.Time `orm:"column(lastContact);type(date);null"`
Meta string `orm:"column(meta)"`
Created time.Time `orm:"column(created);type(timestamp with time zone);auto_now_add"`
Modified time.Time `orm:"column(modified);type(timestamp with time zone);auto_now_add"`
}
func (t *Contact) TableName() string {
return "contact"
}
func init() {
orm.RegisterModel(new(Contact))
}
// AddContact insert a new Contact into database and returns
// last inserted Id on success.
func AddContact(m *Contact) (id int64, err error) {
o := orm.NewOrm()
id, err = o.Insert(m)
return
}
// GetContactById retrieves Contact by Id. Returns error if
// Id doesn't exist
func GetContactById(id int) (v *Contact, err error) {
o := orm.NewOrm()
v = &Contact{Id: id}
if err = o.Read(v); err == nil {
return v, nil
}
return nil, err
}
// GetAllContact retrieves all Contact matches certain condition. Returns empty list if
// no records exist
func GetAllContact(query map[string]string, fields []string, sortby []string, order []string,
offset int64, limit int64) (ml []interface{}, err error) {
o := orm.NewOrm()
qs := o.QueryTable(new(Contact))
// query k=v
for k, v := range query {
// rewrite dot-notation to Object__Attribute
k = strings.Replace(k, ".", "__", -1)
if strings.Contains(k, "isnull") {
qs = qs.Filter(k, (v == "true" || v == "1"))
} else {
qs = qs.Filter(k, v)
}
}
// order by:
var sortFields []string
if len(sortby) != 0 {
if len(sortby) == len(order) {
// 1) for each sort field, there is an associated order
for i, v := range sortby {
orderby := ""
if order[i] == "desc" {
orderby = "-" + v
} else if order[i] == "asc" {
orderby = v
} else {
return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
}
sortFields = append(sortFields, orderby)
}
qs = qs.OrderBy(sortFields...)
} else if len(sortby) != len(order) && len(order) == 1 {
// 2) there is exactly one order, all the sorted fields will be sorted by this order
for _, v := range sortby {
orderby := ""
if order[0] == "desc" {
orderby = "-" + v
} else if order[0] == "asc" {
orderby = v
} else {
return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
}
sortFields = append(sortFields, orderby)
}
} else if len(sortby) != len(order) && len(order) != 1 {
return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
}
} else {
if len(order) != 0 {
return nil, errors.New("Error: unused 'order' fields")
}
}
var l []Contact
qs = qs.OrderBy(sortFields...)
if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
if len(fields) == 0 {
for _, v := range l {
ml = append(ml, v)
}
} else {
// trim unused fields
for _, v := range l {
m := make(map[string]interface{})
val := reflect.ValueOf(v)
for _, fname := range fields {
m[fname] = val.FieldByName(fname).Interface()
}
ml = append(ml, m)
}
}
return ml, nil
}
return nil, err
}
// UpdateContact updates Contact by Id and returns error if
// the record to be updated doesn't exist
func UpdateContactById(m *Contact) (err error) {
o := orm.NewOrm()
v := Contact{Id: m.Id}
// ascertain id exists in the database
if err = o.Read(&v); err == nil {
var num int64
if num, err = o.Update(m); err == nil {
fmt.Println("Number of records updated in database:", num)
}
}
return
}
// DeleteContact deletes Contact by Id and returns error if
// the record to be deleted doesn't exist
func DeleteContact(id int) (err error) {
o := orm.NewOrm()
v := Contact{Id: id}
// ascertain id exists in the database
if err = o.Read(&v); err == nil {
var num int64
if num, err = o.Delete(&Contact{Id: id}); err == nil {
fmt.Println("Number of records deleted in database:", num)
}
}
return
}

155
models/post.go Normal file
View File

@ -0,0 +1,155 @@
package models
import (
"errors"
"fmt"
"reflect"
"strings"
"time"
"github.com/astaxie/beego/orm"
)
type Post struct {
Id int `orm:"column(id);pk"`
Name string `orm:"column(name);null"`
Data string `orm:"column(data)"`
Meta string `orm:"column(meta)"`
Created time.Time `orm:"column(created);type(timestamp with time zone);auto_now_add"`
Modified time.Time `orm:"column(modified);type(timestamp with time zone);auto_now_add"`
}
func (t *Post) TableName() string {
return "post"
}
func init() {
orm.RegisterModel(new(Post))
}
// AddPost insert a new Post into database and returns
// last inserted Id on success.
func AddPost(m *Post) (id int64, err error) {
o := orm.NewOrm()
id, err = o.Insert(m)
return
}
// GetPostById retrieves Post by Id. Returns error if
// Id doesn't exist
func GetPostById(id int) (v *Post, err error) {
o := orm.NewOrm()
v = &Post{Id: id}
if err = o.Read(v); err == nil {
return v, nil
}
return nil, err
}
// GetAllPost retrieves all Post matches certain condition. Returns empty list if
// no records exist
func GetAllPost(query map[string]string, fields []string, sortby []string, order []string,
offset int64, limit int64) (ml []interface{}, err error) {
o := orm.NewOrm()
qs := o.QueryTable(new(Post))
// query k=v
for k, v := range query {
// rewrite dot-notation to Object__Attribute
k = strings.Replace(k, ".", "__", -1)
if strings.Contains(k, "isnull") {
qs = qs.Filter(k, (v == "true" || v == "1"))
} else {
qs = qs.Filter(k, v)
}
}
// order by:
var sortFields []string
if len(sortby) != 0 {
if len(sortby) == len(order) {
// 1) for each sort field, there is an associated order
for i, v := range sortby {
orderby := ""
if order[i] == "desc" {
orderby = "-" + v
} else if order[i] == "asc" {
orderby = v
} else {
return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
}
sortFields = append(sortFields, orderby)
}
qs = qs.OrderBy(sortFields...)
} else if len(sortby) != len(order) && len(order) == 1 {
// 2) there is exactly one order, all the sorted fields will be sorted by this order
for _, v := range sortby {
orderby := ""
if order[0] == "desc" {
orderby = "-" + v
} else if order[0] == "asc" {
orderby = v
} else {
return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
}
sortFields = append(sortFields, orderby)
}
} else if len(sortby) != len(order) && len(order) != 1 {
return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
}
} else {
if len(order) != 0 {
return nil, errors.New("Error: unused 'order' fields")
}
}
var l []Post
qs = qs.OrderBy(sortFields...)
if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
if len(fields) == 0 {
for _, v := range l {
ml = append(ml, v)
}
} else {
// trim unused fields
for _, v := range l {
m := make(map[string]interface{})
val := reflect.ValueOf(v)
for _, fname := range fields {
m[fname] = val.FieldByName(fname).Interface()
}
ml = append(ml, m)
}
}
return ml, nil
}
return nil, err
}
// UpdatePost updates Post by Id and returns error if
// the record to be updated doesn't exist
func UpdatePostById(m *Post) (err error) {
o := orm.NewOrm()
v := Post{Id: m.Id}
// ascertain id exists in the database
if err = o.Read(&v); err == nil {
var num int64
if num, err = o.Update(m); err == nil {
fmt.Println("Number of records updated in database:", num)
}
}
return
}
// DeletePost deletes Post by Id and returns error if
// the record to be deleted doesn't exist
func DeletePost(id int) (err error) {
o := orm.NewOrm()
v := Post{Id: id}
// ascertain id exists in the database
if err = o.Read(&v); err == nil {
var num int64
if num, err = o.Delete(&Post{Id: id}); err == nil {
fmt.Println("Number of records deleted in database:", num)
}
}
return
}

44
routers/router.go Normal file
View File

@ -0,0 +1,44 @@
// @APIVersion 1.0.0
// @Title beego Test API
// @Description beego has a very cool tools to autogenerate documents for your API
// @Contact astaxie@gmail.com
// @TermsOfServiceUrl http://beego.me/
// @License Apache 2.0
// @LicenseUrl http://www.apache.org/licenses/LICENSE-2.0.html
package routers
import (
"multitenantStack/controllers"
"github.com/astaxie/beego"
)
func init() {
ns := beego.NewNamespace("/v1",
beego.NSNamespace("/contact",
beego.NSInclude(
&controllers.ContactController{},
),
),
beego.NSNamespace("/company_data",
beego.NSInclude(
&controllers.CompanyDataController{},
),
),
beego.NSNamespace("/post",
beego.NSInclude(
&controllers.PostController{},
),
),
beego.NSNamespace("/company_user",
beego.NSInclude(
&controllers.CompanyUserController{},
),
),
)
beego.AddNamespace(ns)
}

BIN
swagger/favicon-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

BIN
swagger/favicon-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

93
swagger/index.html Normal file
View File

@ -0,0 +1,93 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body {
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0">
<defs>
<symbol viewBox="0 0 20 20" id="unlocked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
</symbol>
<symbol viewBox="0 0 20 20" id="locked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="close">
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow">
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow-down">
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="jump-to">
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="expand">
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>
</symbol>
</defs>
</svg>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js"> </script>
<script src="./swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
// Build a system
const ui = SwaggerUIBundle({
url: "swagger.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
window.ui = ui
}
</script>