Code Monkey home page Code Monkey logo

Comments (7)

benjie avatar benjie commented on July 19, 2024 2

This is working as designed. Ignoring smart comments the issue is basically this:

create table something(
  some_id integer not null primary key,
  name text
);
create table something_data(
  something_data_id integer not null primary key,
  some_id integer not null references something on delete cascade,
  data text
);

Since the table/type name for something is something (and not some), the some_id reference is inferred to have a special meaning rather than a simple relationship. It's hard to explain with this nonsense schema, so let's come up with a more reasonable one:

create table people (
  id serial primary key,
  name text
);

create table books (
  id serial primary key,
  title text,
  author_id int not null references people,
  publisher_id int not null references people
);

In this table we generate type Book { author: Person } as expected. Also type Book { publisher: Person }. Now we can't add a field on People called books because it effectively points to two different places - once for author and once for publisher, so instead you'd get booksByAuthorId: [Book] and booksByPublisherId: [Book]*. Now imagine if our books table was:

create table books (
  id serial primary key,
  title text,
  author_id int not null references people
);

Here we only have one reference to people, so we could add type Person { books: [Book] } but if we were to do so and then later add the publisher_id field, we'd introduce a breaking schema change, and all our GraphQL queries would become invalid. For this reason we only use the simplified books name if the relationship is itself simple (i.e. in this case if the books.author_id column was instead called books.person_id).

I hope this clarifies why your request cannot be granted in general, and why you need to add custom naming because your problem doesn't generalise to all databases.

  • Actually, we have workarounds for this called getOppositeBaseName (which you can extend) which notes if it's author_id then the reverse can be called authoredBooks rather than bookByAuthorId, but this isn't something we can do in general because we don't have a list of all the possible relationships.

from pg-simplify-inflector.

benjie avatar benjie commented on July 19, 2024

I've moved this issue to the simplify inflectors plugin repo, since I believe that's really what you're asking about.

from pg-simplify-inflector.

benjie avatar benjie commented on July 19, 2024

We currently use the resulting column name rather than the original column name for this:

getBaseNameFromKeys(detailedKeys) {
if (detailedKeys.length === 1) {
const key = detailedKeys[0];
const columnName = this._columnName(key);
return this.getBaseName(columnName);
}
return null;
},

I'd expect it to work from a scan over the code, I wonder if there's something else going on? Failing that, I'd need to step through the inflector code line by line in this:

singleRelationByKeys(detailedKeys, table, _foreignTable, constraint) {
if (constraint.tags.fieldName) {
return constraint.tags.fieldName;
}
const baseName = this.getBaseNameFromKeys(detailedKeys);
if (baseName) {
return this.camelCase(baseName);
}
if (this.baseNameMatches(baseName, table.name)) {
return this.camelCase(`${this._singularizedTableName(table)}`);
}
return oldInflection.singleRelationByKeys(
detailedKeys,
table,
_foreignTable,
constraint
);
},

Namely: I'd expect baseName to equal some and thus for it to work, but judging by what you're saying that's not the case.

from pg-simplify-inflector.

gbogarinb avatar gbogarinb commented on July 19, 2024

I tried to replicate this on a new database and got a slightly different result, the first time I actually executed this

comment on column something_data.something_id is E'@name some_id;';

with a semicolon at the end of the comment, what's strange is that it does change the field to some_id (doesn't complain about the semicolon), but it doesn't work with the foreign key field for some reason, after executing it without the semicolon I do get the result that you suggested but only in the second schema:

  somethingDatum(somethingDataId: 10) {
    someId
    some {
      name
    }
  }

The first schema still remains with somethingDataBySomeIdConnection.

from pg-simplify-inflector.

benjie avatar benjie commented on July 19, 2024

Maybe there's something else in there - invisible whitespace or something - that's tricking it?

from pg-simplify-inflector.

gbogarinb avatar gbogarinb commented on July 19, 2024

The problem seems to be here:

manyRelationByKeys(detailedKeys, table, foreignTable, constraint) {
if (constraint.tags.foreignFieldName) {
if (constraint.tags.foreignSimpleFieldName) {
return constraint.tags.foreignFieldName;
} else {
return constraint.tags.foreignFieldName + ConnectionSuffix;
}
}
const base = this._manyRelationByKeysBase(
detailedKeys,
table,
foreignTable,
constraint
);
if (base) {
return base + ConnectionSuffix;
}
return (
oldInflection.manyRelationByKeys(
detailedKeys,
table,
foreignTable,
constraint
) + ConnectionSuffix
);
},

Here is a log before and after the comment.

Before
getBaseNameFromKeys something
_foreignTable.name something
baseNameMatches singularizedName something
baseNameMatches result true
_manyRelationByKeysBase somethingData
manyRelationByKeys somethingDataConnection

After
getBaseNameFromKeys some
_foreignTable.name something
baseNameMatches singularizedName something
baseNameMatches result false
_manyRelationByKeysBase null
manyRelationByKeys somethingDataBySomeIdConnection

_manyRelationByKeysBase is returning null since now baseName and singularizedName (computed from _foreignTable.name) aren't the same anymore thus making manyRelationByKeys ending up using oldInflection.manyRelationByKeys.

from pg-simplify-inflector.

gbogarinb avatar gbogarinb commented on July 19, 2024

My current solution is to change this:

if (this.baseNameMatches(baseName, table.name)) {

if (this.baseNameMatches(baseName, table.name)) {

if (this.baseNameMatches(baseName, _foreignTable.name)) {

by this:

if (detailedKeys[0].tags.name || this.baseNameMatches(baseName, [table or _foreignTable].name)) {

The reasoning being that if there is a name tag then baseNameMatches will always return false, I didn't find any side effect so far but I'm not sure if this reasoning makes sense because I didn't have enough time to actually understand what that method was supposed to do.

Edit: I did find some side effects, but I'm not entirely sure if they're actually harmful.

create table person(
person_id integer not null primary key generated by default as identity);

create table person_cart(
person_id integer not null primary key references person on delete cascade);

create table person_address(
person_id integer not null references person on delete cascade);

Instead of generating this:

person(personId: 10) {
    personAddressesConnection {
      totalCount
    }
    personCartByPersonId {
      personId
    }
  }

it generates this:

person(personId: 10) {
    personAddressesConnection {
      totalCount
    }
    personCart {
      personId
    }
  }

Of course only if person_cart has a smart tag.

person_cart: {
	attribute: {
		person_id: {
			tags: {
				name: "person_id"
			}
		}
	}
},

from pg-simplify-inflector.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.