Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: auto-increment for entity id #244

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

0xTitan
Copy link

@0xTitan 0xTitan commented Jul 6, 2023

Hello.
Implementation done. Auto increment annotation can be added only once on entity definition. Only Int, BigInt and ID (for nested object) are managed.

Eg :
`scalar Text

type Post {
id: Int! @autoincrement
author: String!
content: Text!
tag: String
tx_hash: String!
created_at: Int!
created_at_block: Int!
poster: Poster
}

type Poster {
id: ID! @autoincrement
name: String!
}`

Unfortunately i'm struggling with knex implementation and the primaryKey definition. There is normally the possiblity to define if an autoIncrement field should be defined as primaryKey, this is not working when i'm setting it false. Due to that i can only managed one autoIncrement field per table. Maybe enought for now.

Eg :

Knex increment

knex.schema.createTable('users', function (table) { table.increments('id'); table.increments('other_id', { primaryKey: false }); });

I added two more tests :

  • should work with autoincrement
  • should work with autoincrement and nested objects

image

I put the constant needed under type.ts. Let me know if it's suitable.

The result under myssql for the schema above :
image

Copy link
Contributor

@Sekhmet Sekhmet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@autoincrement can be handled as native GraphQL directive, like @derivedFrom

@0xTitan
Copy link
Author

0xTitan commented Jul 10, 2023

Ok thx, will check that.

@0xTitan
Copy link
Author

0xTitan commented Jul 26, 2023

Update done. New directive @autoincrement added.

* @param schema
* @returns A map where key is table name and values a list of fields with annotation autoIncrement
*/
private extractAutoIncrementFields(schema: string) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be handled with regexes. Directive can be handled natively with GraphQL.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, can you guide me to some example of what you want. From my understanding autoIncrement directive is not native in GraphQL so i need to implement the logic behind this new directive. Thank you.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we extended GraphQL with our custom directive here, we can then access that directive directly from our GraphQL tree.

This way you can look at the field (id field in this example, and check if it has @autoincrement directive, same as we do with @derivedFrom:

const directives = field.astNode?.directives ?? [];
const derivedFromDirective = directives.find(dir => dir.name.value === 'derivedFrom');
if (!derivedFromDirective) {
throw new Error(`field ${field.name} is missing derivedFrom directive`);
}

That means we don't have to bother with writing our own dummy parser for GraphQL to extract autoIncrementFields, and just check for field.astNode.directives here:

if (
autoIncrementFieldsMap.size == 0 ||
autoIncrementFieldsMap.get(tableName)?.length === 0
) {
t.primary(['id']);
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK thx for the hint. I will check it and modify accordingly.

@Sekhmet
Copy link
Contributor

Sekhmet commented Oct 19, 2023

@0xTitan thank you for your contribution so far. Are you still expecting to work on this issue? If not I could push it across finish line.

@0xTitan
Copy link
Author

0xTitan commented Oct 19, 2023

Hello @Sekhmet, sorry i didn't had time to continue on this, i was involved in other starknet project. I would like to finish this task. But if it's easier for you can push it across finish line and i can create a new PR later with correct implementation.
Thank you.

@0xTitan
Copy link
Author

0xTitan commented Nov 4, 2023

Hi @Sekhmet, i pushed changes to remove regex and use directive. Huge thanks for your help and your patience !

Copy link
Contributor

@Sekhmet Sekhmet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks way cleaner thank you!

General thoughts:

  • can you revert any unrelated changes to the formatting? Most of it would be solved by running Prettier or yarn lint.
  • the comments added are a bit too much in my opinion as they explain pretty self-explanatory code, so they could be removed
  • we have added ORM since and it won't work well with it (as currently ORM requires you to create new instances of ORM models by passing ID to a constructor) - is this something you are also willing to take a look at? Otherwise we probably should at least prevent ORM models from being created for entities with autoincrement fields until it's implemented. If you don't want to work on that I could at this logic so we could get your PR merged.

@@ -56,7 +56,7 @@ type Vote {
});

it('should work', async () => {
const controller = new GqlEntityController(`
const schema = `
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd use just a single test case to test everything (just put autoincrement and nested properties in here) or
use it.each to avoid duplication of code.

Comment on lines 227 to 235
//if there is no autoIncrement fields on current table, mark the id as primary
const tableHasAutoIncrement = this.getTypeFields(type).some(field => {
const directives = field.astNode?.directives ?? [];
const autoIncrementDirective = directives.find(dir => dir.name.value === 'autoIncrement');
return autoIncrementDirective;
})

if (!tableHasAutoIncrement)
t.primary(['id']);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code duplicates quite a bit of logic from below.
I wonder if it wouldn't be cleaner to remove this initial lookup and instead use original forEach:

let tableHasAutoIncrement = false

// ...
this.getTypeFields(type).forEach(field => {
  // ...
  if (autoIncrementDirective) {
    tableHasAutoIncrement = true
    t.increments(field.name, { primaryKey: true });
  }
}

// ...
if (!tableHasAutoIncrement) {
  t.primary(['id'])
}

Copy link
Author

@0xTitan 0xTitan Nov 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the review. I updated code based on your comments.
Regarding ORM, i could take a look ?

package.json Outdated
@@ -61,4 +61,4 @@
"dist/**/*",
"src/**/*"
]
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you revert this change?

const directives = field.astNode?.directives ?? [];
const autoIncrementDirective = directives.find(dir => dir.name.value === 'autoIncrement');

//Check if field is declared as autoincrement
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//Check if field is declared as autoincrement

expect(createQuery).toMatchSnapshot();
});

it('should work with autoincrement and nested objects', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like it could just be the only test case in this file (it should work).

@0xTitan
Copy link
Author

0xTitan commented Nov 6, 2023

Thanks for your comments. Update done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants