Restrict variable to itself and to other certain package

Issue

I have this structure:

├── app
│   ├── app.go
│   ├── handler
│   │   ├── common.go
│   │   └── users.go
│   ├── model
│   │   └── model.go
│   └── queries
│       └── queries.go
├── config
│   └── config.go
└── main.go

All my queries (SQL ones) are in queries.go:

queries.go:

package queries

const (
    QueryFindUser = `SELECT * FROM users WHERE id=$1` // <------ HERE
)

users.go:

package handler

import (
    "GO_APP/app/model"
    "GO_APP/app/queries"
    "fmt"
    "net/http"
    "strconv"
    "github.com/julienschmidt/httprouter"
    _ "github.com/jinzhu/gorm/dialects/postgres"
    "github.com/jmoiron/sqlx"
)

var db *sqlx.DB

// getUserOr404 gets a User instance if exists, or respond the 404 error otherwise
func getUserOr404(db *sqlx.DB, id int, w http.ResponseWriter, r *http.Request) (*model.User, error) {
    user := model.User{}
    err := db.Get(&user, queries.QueryFindUser, id) // <----- Here
    return &user, err
}

If I use QueryFindUser (capital first letter) then it will become exportable to all the other packages. But I don’t want this to be accessible by say config/config.go

I want it to be restricted to handler‘s modules only exlcluding the model/model.go.

If I declare queryFindUser this will be limited to the package queries only and then I won’t be able to use it anywhere.

How to solve this thing? Without making it exportable to every other package.
I am quite new to golang/java and this issue will be same in java as well.
So what to do in this case?
If you can provide resources that will also be helpful to me.

Solution

Access permission to identifiers is not so fine grained that you can specify who you’re granting access. And there’s no need. This would unnecessarily complicate both the uses (source code) and the implementation (compilation time, compiled package object and executable binary size).

If you want to give access to a specific package only, easiest is to merge the packages and make the identifiers unexported.

If you want to give access to multiple packages or the package would get unpleasantly big, you may use internal packages. Internal packages were introduced so you can break "big" packages into multiple, smaller ones, and still keep the implementation detail hidden and protected from the "outside" (from other packages).

Internal packages may define exported identifiers, but access to them is only allowed to the "internal group".

For example:

├── app
│   ├── app.go
│   ├── handler
│   │   ├── internal
│   │   │   ├── queries
│   │   │   │   └── queries.go
│   │   │   └── foo
│   │   │       └── foo.go
│   │   ├── users.go
│   │   ├── common.go
│   │   └── users.go
│   └── model
│       └── model.go
├── config
│   └── config.go
└── main.go

In this example the queries package is accessible by the handler package and by the foo package, but is not accessible by the model or config packages.

In general, internal packages (packages that are inside a folder that has an internal folder in their path) can only be imported from packages rooted at the parent of the internal folder.

See related questions:

Can I develop a go package in multiple source directories?

Use of internal package not allowed

Answered By – icza

Answer Checked By – Cary Denson (GoLangFix Admin)

Leave a Reply

Your email address will not be published.