volatiletech / sqlboiler

Generate a Go ORM tailored to your database schema.
BSD 3-Clause "New" or "Revised" License
6.73k stars 544 forks source link

Importing models after generation causes "both field and method" error #519

Closed davedbase closed 5 years ago

davedbase commented 5 years ago

If you're having a generation problem please answer these questions before submitting your issue. Thanks!

What version of SQLBoiler are you using (sqlboiler --version)?

SQLBoiler v3.2.0

If this happened at generation time what was the full SQLBoiler command you used to generate your models? (if not applicable leave blank)

Didn't happen at generation time, but for extra detail here's the command: sqlboiler -c sqlboiler.toml -p models -o models psql

If this happened at runtime what code produced the issue? (if not applicable leave blank)

Upon generating then attempting to import the module package, I'm getting the following error:

models/Bundles.go:431:6: type Bundle has both field and method named StatusID
models/Devices.go:439:6: type Device has both field and method named DeviceTypeID
models/Devices.go:453:6: type Device has both field and method named LicenseID
models/Devices.go:467:6: type Device has both field and method named OrganizationID
models/Devices.go:481:6: type Device has both field and method named StatusID
models/Files.go:450:6: type File has both field and method named FileTypeID
models/Files.go:464:6: type File has both field and method named DeviceID
models/Files.go:478:6: type File has both field and method named MimeTypeID
models/Files.go:492:6: type File has both field and method named StatusID
models/Files.go:506:6: type File has both field and method named MeasurementID
models/Files.go:506:6: too many errors

The schema I'm using is a port from a Version 1.0 of the project. I'm not totally sure if the schema is structurally sound as it's likely changed over time. However I can't imagine anything would be wrong enough to cause the above errors.

What is the output of the command above with the -d flag added to it? (Provided you are comfortable sharing this, it contains a blueprint of your schema)

Can't supply this unfortunately, however I did supply the compiled version of the model for review: Devices.txt

Please provide a relevant database schema so we can replicate your issue (Provided you are comfortable sharing this)

CREATE TABLE public."Devices" (
    "ID" uuid NOT NULL,
    "DeviceTypeID" character varying(25) NOT NULL,
    "OrganizationID" uuid NOT NULL,
    "LicenseID" uuid,
    "StatusID" character varying(20) NOT NULL,
    "Name" character varying(75) NOT NULL,
    "Identifier" character varying(100) NOT NULL,
    "Version" character varying(15) NOT NULL,
    "Created" timestamp without time zone DEFAULT now() NOT NULL,
    "Updated" timestamp without time zone DEFAULT now() NOT NULL
);

Further information. What did you do, what did you expect?

Expecting all the models to load and be callable in my application. Note that I have approximately 30 other tables generated and it seems to only be throwing errors for 3 specific files. Oddly enough they all seem to be related to ID fields (UUID) or possibly even foreign keys. I reviewed them in the database and they are set appropriately.

Thanks in advance for any help you can supply.

davedbase commented 5 years ago

In trying to answer my own question I've found some similar issues that point to the aliasing documentation: https://github.com/volatiletech/sqlboiler/tree/v3#aliases. So I'm assuming my issue is related to this, however I'm trying to understand why this is only occurring for these specific tables and not others. Perhaps in my specific situation DeviceTypeID is being inferred because the path is to DeviceTypes.ID. In which case this alias should do the trick?

[[aliases.tables.Devices.relationships]]
name  = "Devices_DeviceTypes"
local = "DeviceTypeIdentifier"
foreign = "DeviceType"

Doesn't seem to make a difference though :-/

Update: Ok seems like the documentation was adequate to get through getting a build. Seems like I needed to read up a bit more on TOML structures (oops). That being said, I was wondering if there was a more generic way ie. regular expressions to define aliases. I have almost 150 different aliases which is a result of the normalization pattern we used in our db. It would make a lot of sense of common patterns could be reduced to replacement expressions.

aarondl commented 5 years ago

I would expect that this only occurs for Foreign Keys named as you've named them. Is that a correct assertion? Reason being is that we apply some generic naming rules to name relationships. What it tries to do is take something that looks like video.user_id and turn it into a method called Video.User and User.Videos. Unfortunately for you sqlboiler only applies these naming rules if the input is as it expects (snake case, needs the _ to differentiate), even if it isn't able to trim the suffix it then runs the naming through the pluralizer/singularizer in order to come up with a proper noun for the method (Videos vs User). In your case it's StatusID and the pluralizer goes: "Uh, I have no idea" and just returns the same thing because how do you pluralize that as it's not really English I suppose.

In the end you get the bad naming that causes your duplicated names. You've found the fix for this already, and I apologize for not getting back to you sooner. Another fix is to go snake case for your table/column names but that's probably something you don't want to do.

There is unfortunately no generic way to define aliases currently, not too interested in supporting that but I'm never closed to ideas :)

Place1 commented 5 years ago

@ddibiase hey I think i'm running into the same problem as you. What toml did you use to get the alias working:

I'm trying to do the following

[psql]
...

[aliases.tables.CapitalTableName.relationships.CapitalTableName_OtherTable_fkey]
local = "MyAlias"

I think it's broken because I have capital letters in the fkey constraint name, the column name and the table name.

EDIT:

apologies, i didn't notice that this is documented further down in the readme.

for future googlers, here's the alternative syntax that supports capital letters:

[[aliases.tables]]
name = "CapitalTableName"
  [[aliases.tables.columns]]
  name = "MyColumn"
  alias = "MyAlias"

  [[aliases.tables.relationships]]
  name = "CapitalTableName_OtherTable_fkey"
  local = "MyAlias"