prisma-archive / graphcool-templates

πŸ“— Collection of Graphcool Templates
MIT License
360 stars 100 forks source link

Unique slug generation #24

Open mwickett opened 6 years ago

mwickett commented 6 years ago

With the help of @kbrandwijk (thank you!), I've got a much more robust slug function that seems to be working well and handling every case (that I've thought of yet).

  1. It takes a title value from a new record, slugifies it (using slugs, rather than regex. Handles far more inputs - unicode, other language characters, etc.))
  2. then queries for a slug with the same value. If one exists, it appends -n+1 to the end. (e.g. title-of-post-1, title-of-post-2

I feel like this could be implemented as a schema extension as well, although I'm fairly new to that, so may be wrong.

It also needs to be adjusted heavily based on the particular project schema and naming etc.

'use latest';

const { GraphQLClient } = require('graphql-request')
const slugify = require('slugs')

const client = new GraphQLClient('__ENDPOINT__', {
  headers: {
    Authorization: 'Bearer __PAT-TOKEN__',
  }
})

module.exports = function (event) {
  // This query returns only the highest numbered slug (which could be the
  // only existing slug that may not have a trailing integer
  const query = `
    query($slug: String!) {
      allJobs(filter: {
        slug_starts_with: $slug
      }
      orderBy: slug_DESC
        first: 1
      ) {
        slug
      }
    }
  `

  const variables = {
    // Uses slugs to create slug - https://www.npmjs.com/package/slug
    slug: slugify(event.data.title)
  }

  return new Promise((resolve, reject) => {
    client.request(query, variables)
    .then(data => {
      let slug = variables.slug
      // If nothing comes back in the query, the slug doesn't already exist
      if (data.allJobs.length === 0) {
        const response = Object.assign({}, event.data, {slug})
        resolve({ data: response })
      } else {
        // Check the length of the returned result with the new slug to determine if there is
        // a trailing integer. If there isn't, use -2 or else create the next one.
        if (data.allJobs[0].slug.split('-').length === slug.split('-').length) {
            slug = `${slug}-2`
        } else {
            slug = `${slug}-${parseInt(data.allJobs[0].slug.split('-').pop()) + 1}`  
        }
        const response = Object.assign({}, event.data, {slug})
        resolve({ data: response })
      }
    })
    .catch(error => {
      console.log(error)
      reject(error)
    })
  })
}

I'm putting this in as an issue to look for guidance on whether this is worth writing up an including in these function examples. And should it be a Schema extension rather than a transform function?

marktani commented 6 years ago

Hey Mike, thanks a lot for putting this out here, this is exactly the kind of example I'd like to see in this repository! πŸ˜„

I think a transform function fits better, but you can also implement this with a Schema Extension function.

It also needs to be adjusted heavily based on the particular project schema and naming etc.

This is perfectly fine! The way I approached this in other examples is by providing a example.graphql schema file that can be used with the Graphcool CLI to bootstrap a project with the right structure. This way, you have something working quite fast that you can hopefully adjust easily to your own use case.

I'd love to collaborate on this! Maybe we can add another variant to the generate-slug, or add this as a new example advanced-generate-slug or similar?

mwickett commented 6 years ago

Hey Nilan,

Thanks for looking at this. I'd love to collaborate on this with you.

I'm away this weekend and back at it on Monday.

I'll draft an example schema to go with this and post. There are probably some things we can do to abstract this a bit for more use cases. Also documenting with some places where others may need to modify would probably be good.

On July 22, 2017 at 13:41:36, Nilan Marktanner (notifications@github.com) wrote:

Hey Mike, thanks a lot for putting this out here, this is exactly the kind of example I'd like to see in this repository! πŸ˜„

I think a transform function fits better, but you can also implement this with a Schema Extension function.

It also needs to be adjusted heavily based on the particular project schema and naming etc.

This is perfectly fine! The way I approached this in other examples is by providing a example.graphql schema file that can be used with the Graphcool CLI to bootstrap a project with the right structure. This way, you have something working quite fast that you can hopefully adjust easily to your own use case.

I'd love to collaborate on this! Maybe we can add another variant to the generate-slug, or add this as a new example advanced-generate-slug or similar?

β€” You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/graphcool-examples/functions/issues/24#issuecomment-317198928, or mute the thread https://github.com/notifications/unsubscribe-auth/AAzon36RmYJDfP5GD3vfLcCFW5hzR2-hks5sQjRQgaJpZM4OaKyG .