npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

adonis-lucid-slugify-dev2

v0.0.1

Published

Generate unique slugs for your Lucid models. This package is forked from official @adonisjs/lucid-slugify package and has been changed as per my requirement

Downloads

10

Readme

Lucid Slugify


gh-workflow-image npm-image license-image typescript-image

Generating slugs is easy, but keeping them unique and within a maximum length range is hard. This package abstracts the hard parts and gives you a simple API to generate unique slugs.

Features

  • Define a maximum length for the slug
  • Complete words when truncating the slug
  • Generate unique slugs using different strategies
  • Add your custom strategies

Usage

Install the package from the npm registry as follows:

npm i adonis-lucid-slugify-dev2

And then configure the package as follows:

node ace configure adonis-lucid-slugify-dev2

Once done, you need to use the following decorator on the field for which you want to generate the slug. Following is an example with the Post model generating slug from the post title.

import { BaseModel, column } from '@ioc:Adonis/Lucid/Orm'
import { slugify } from '@ioc:Adonis/Addons/LucidSlugify'

class Post extends BaseModel {
  @column({ isPrimary: true })
  public id: number

  @column()
  @slugify({
    strategy: 'dbIncrement',
    fields: ['title']
  })
  public slug: string

  @column()
  public title: string
}

In the above example, the slug property will be set based upon the value of the title property.

Updating slugs

By default, slugs are not updated when you update a model instance, and this is how it should be when slugs are used to look up a record, as changing a slug will result in a broken URL.

However, if slugs are not primarily used to look up records, you may want to update them.

You can enable updates by using the allowUpdates flag.

@slugify({
  strategy: 'dbIncrement',
  fields: ['title'],
  allowUpdates: true,
})
public slug: string

Generate slug from multiple properties

The fields array can accept multiple model properties and generate a slug by concatenating the values of all the fields.

@slugify({
  strategy: 'dbIncrement',
  fields: ['country', 'state', 'city'],
  allowUpdates: true,
})
public location: string

Null values and slug generation

The slugify decorator does not generate slugs when the source field(s) value is not defined or null.

In other words, all of the source fields should have a value for the slug to be generated. It is an opinionated choice and not likely to change.

Available options

Following is the list of available options accepted by the @slugify decorator.

Strategies

Strategies decide how to generate a slug and then make it unique. This package ships with three different strategies.

  • simple: Just the slug is generated. No uniqueness guaranteed.
  • dbIncrement: Generates unique slugs by adding a counter to the existing similar slug.
  • shortId: Appends a short id to the initial slug value to ensure uniqueness.

Db Increment

The Db Increment strategy uses a counter to generate unique slugs. Given the following table structure and data.

+----+-------------+-------------+
| id | title       | slug        |
+----+-------------+-------------+
| 1  | Hello world | hello-world |
+----+-------------+-------------+

If you generate another slug for the Hello world title, the dbIncrement strategy will append -1 to ensure slug uniqueness.

Model definition

import { BaseModel, column } from '@ioc:Adonis/Lucid/Orm'
import { slugify } from '@ioc:Adonis/Addons/LucidSlugify'

class Post extends BaseModel {
  @column({ isPrimary: true })
  public id: number

  @column()
  @slugify({
    strategy: 'dbIncrement',
    fields: ['title']
  })
  public slug: string

  @column()
  public title: string
}

Create a new record

const post = new Post()
post.title = 'Hello world'

await post.save()

Database state

+----+-------------+---------------+
| id | title       | slug          |
+----+-------------+---------------+
| 1  | Hello world | hello-world   |
| 2  | Hello world | hello-world-1 |
+----+-------------+---------------+

Implementation details

The implementation details vary a lot across different database drivers.

  • PostgreSQL, MsSQL 8.0, and Redshift performs optimized queries to fetch only matching record with the largest counter.
  • For SQLite, MySQL < 8.0, and MSSQL, we have to fetch all the matching rows and then find the largest counter in JavaScript.
  • The OracleDB implementation is untested (feel free to contribute the tests). However, it also performs an optimized query to fetch only matching records with the largest counter.

Simple

The simple strategy just generates a slug respecting the maxLength and completeWords config options. No uniqueness is guaranteed when using this strategy.

import { BaseModel, column } from '@ioc:Adonis/Lucid/Orm'
import { slugify } from '@ioc:Adonis/Addons/LucidSlugify'

class Post extends BaseModel {
  @column({ isPrimary: true })
  public id: number

  @column()
  @slugify({
    strategy: 'simple',
    fields: ['title']
  })
  public slug: string

  @column()
  public title: string
}

Short Id

The shortId strategy appends a ten-digit long random short id to the initial slug value for uniqueness. Following is an example of using the shortId strategy.

import { BaseModel, column } from '@ioc:Adonis/Lucid/Orm'
import { slugify } from '@ioc:Adonis/Addons/LucidSlugify'

class Post extends BaseModel {
  @column({ isPrimary: true })
  public id: number

  @column()
  @slugify({
    strategy: 'shortId',
    fields: ['title']
  })
  public slug: string

  @column()
  public title: string
}
+----+-------------+------------------------+
| id | title       | slug                   |
+----+-------------+------------------------+
| 1  | Hello world | hello-world-yRPZZIWGgC |
+----+-------------+------------------------+

Adding a custom strategy

You can add custom strategies using two different ways.

Inline within the slugify decorator

The simplest way is to define the strategy inline in the decorator options. A strategy must implement the following two methods.

import { SlugifyStrategyContract } from '@ioc:Adonis/Addons/LucidSlugify'

const myCustomStrategy: SlugifyStrategyContract = {
  makeSlug (model, field, value) {
    return // slug for the value
  },
  makeSlugUnique(model, field, slug) {
    return // make slug unique
  },
}

@slugify({
  strategy: myCustomStrategy,
  fields: ['title']
})

Extending the slugify package

This is the recommended approach when you are distributing your strategy as an npm package. Every strategy must implement the SlugifyStrategyContract interface.

Define strategy

import {
  SlugifyConfig,
  SlugifyStrategyContract
} from '@ioc:Adonis/Addons/LucidSlugify'

class MyStrategy implements SlugifyStrategyContract {
  constructor (private config: SlugifyConfig) {}

  makeSlug (
    model: LucidModel,
    field: string,
    value: string
  ) {}

  makeSlugUnique (
    model: LucidModel,
    field: string,
    slug: string
  ) {}
}

Register the strategy

Register the strategy using the Slugify.extend method. You must write the following code inside the provider boot method.

import { ApplicationContract } from '@ioc:Adonis/Core/Application'

export default class AppProvider {
  constructor(protected app: ApplicationContract) {}

  public async boot() {
    const { Slugify } = this.app.container.use('Adonis/Addons/LucidSlugify')

    Slugify.extend('strategyName', (slugify, config) => {
      return new MyStrategy(config)
    })
  }
}

Inform typescript about the strategy

Finally, you will also have to inform typescript about the new strategy you added using the Slugify.extend method. We will use declaration merging to add the property to the StrategiesList interface.

declare module '@ioc:Adonis/Addons/LucidSlugify' {
  interface StrategiesList {
    strategyName: SlugifyStrategyContract
  }
}