0

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.

Pygirl
  • 12,969
  • 5
  • 30
  • 43
  • 1
    What you want is not possible. Also, not sure why this would be a problem? You still have to manually import a package to use its exported items. – Thijs van der Heijden Jun 01 '22 at 12:38
  • @ThijsvanderHeijden: so that means I have to change the file structure? put `user.go` and `queries.go` together? – Pygirl Jun 01 '22 at 12:42
  • @ThijsvanderHeijden: I thought may be there is other way like creating an interaface creating function(Exportable) that uses those and by calling that function to do operation using those const variable I can keep them hidden, just exposing the function using them. – Pygirl Jun 01 '22 at 12:44

1 Answers1

1

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

icza
  • 389,944
  • 63
  • 907
  • 827
  • Let say I want this `queries` to be used by all the modules mentioned inside the `app` including handler, model as well. Everything that is inside app should be able to use queries.go. What do in this case? Currently `users.go` and `model.go` required that variable. – Pygirl Jun 01 '22 at 12:55
  • @Pygirl Added an example of an `internal` package and explanation who can access it. – icza Jun 01 '22 at 12:57
  • :O Thanks for explaining internal things. I thought internal as directory name was just a normal name. I didn't know that naming internal was related to the package. One last request can you tell me how to search related to this directory convention thing. `internal` as a directory was new to me – Pygirl Jun 01 '22 at 13:06
  • 1
    @Pygirl The `internal` name is special and is reserved for this purpose. – icza Jun 01 '22 at 13:07
  • Can you share the resources if possible where I can learn all these things because I didn't see that `internal` thing I did see the name convention CamelCase converting into snake_case in db. But not this package related stuffs. :) Thanks a lot. – Pygirl Jun 01 '22 at 13:13
  • 1
    I linked the source in the answer: https://pkg.go.dev/cmd/go – icza Jun 01 '22 at 13:15
  • 1
    Other special names are: `internal`, `vendor`, `testdata`. – icza Jun 01 '22 at 13:17
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/245232/discussion-between-pygirl-and-icza). – Pygirl Jun 01 '22 at 13:38