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

qqtag

v1.2.1

Published

quasi quote library for javascript template literals

Downloads

3

Readme

qqtag

Quasi quote library for javascript template literals.

Motivation

Some database libraries like mssql supports embedding query parameters using tagged literals:

const sql = require('mssql')

sql.connect(config).then(() => {
    return sql.query`select * from mytable where id = ${value}`
}).then(result => {
    console.dir(result)
}).catch(err => {
    // ... error checks
})

But what to do if you want to embed a table name variable, or if you want to add optional WHERE conditions based on values of variables ?

Usage

  • quasiquote expresses a template literal that is not yet evaluated and can be passed to other tag functions.

    import { quasiquote as qq } from 'qqtag'
    
    const sql = require('mssql')
    
    sql.connect(config).then(() => {
      const query = qq`select * from mytable where id = ${value}`
      return query.sendTo(sql.query.bind(sql))
    }) // ...
  • quote can embed a string as a part of literals instead of passing it to a template literal place holder.

    import { quasiquote as qq, quote as qt } from 'qqtag'
    
    const tableName = 'tab1'
    const query1 = qq`select col1 from ${tableName}`
    const query2 = qq`select col1 from ${qt(tableName)}`
    
    query1.sendTo((ss, ...vs) => {
      console.log([ss, vs])
      // -> [ [ 'select col1 from ', '' ], [ 'tab1' ] ]
      //    This is not what is wanted.
    })
    query2.sendTo((ss, ...vs) => {
      console.log([ss, vs])
      // -> [ [ 'select col1 from tab1' ], [] ]
    })
  • unquote can embed another quasiquote .

    import { quasiquote as qq, unquote as uq } from 'qqtag'
    
    let colvalue = '2'
    
    const query = qq`select col1 from tab1
    ${uq(() => {
      if (colvalue != null) {
        return qq`where col2 = ${colvalue}`
      }
    })}
    `
    query.sendTo((ss, ...vs) => {
      console.log([ss, vs])
      // -> [ [ 'select col1 from tab1\n  where col2 = ', '\n' ], [ '2' ] ]
    })
    
    colvalue = null
    
    query.sendTo((ss, ...vs) => {
      console.log([ss, vs])
      // -> [ [ 'select col1 from tab1\n  \n' ], [] ]
    })

Example

(These examples may be stale and may not work, but the concept will be apply.)

mysql

const newQuery = (conn) =>
  (ss, ...vs) => new Promise((resolve, reject) => {
    conn.query(newQueryOpts(ss, ...vs), (error, results, fields) => {
      if (error) return reject(error)
      return resolve({ results, fields })
    })
  })

const newQueryOpts = (ss, ...vs) => {
  const values = vs
  const sql = ss.slice(1).reduce((a, s, i) => `${a} ? ${s}`, ss[0])
  return { sql, values }
}

const newSql = (conn) =>
  (ss, ...vs) => vs.reduce((a, c, i) => `${a}${conn.escape(c)}${ss[i + 1]}`, ss[0])


const listUsers = async (conn, opts) => {
  return await qq`\
select * from users \
${uq(() => opts.userId != null ? qq`where user_id=${opts.userId}` : undefined)} ;\
`.sendTo(newQuery(conn))
}

const getLiteralSqlForListUsers = async (conn, opts) => {
  return await qq`\
select * from users \
${uq(() => opts.userId != null ? qq`where user_id=${opts.userId}` : undefined)} ;\
`.sendTo(newSql(conn))
}

@azure/cosmos (v2)

const newQuery = (ss, ...vs) => {
  const parameters = vs.reduce((a, v, i) => (a.push({ name: `@p_${i}`, value: vs[i] }), a), [])
  const query = ss.slice(1).reduce((a, s, i) => `${a} ${parameters[i].name} ${s}`, ss[0])
  return { query, parameters }
}

const querySpec = qq`select * from ${qt(collectionName)} t where t.UserId = ${userId}`.sendTo(newQuery)
const feedOptios = {
  // ...
}
const queryIterator = collection.container.items.query(querySpec, feedOptios)

mssql: pass typed query parameters

class BaseCustomSqlType {
  constructor(value) {
    this.value = value
  }
  valueOf() {
    return this.value
  }
}
class VarChar extends BaseCustomSqlType {}
class Numeric extends BaseCustomSqlType {}

sql.map.register(VarChar, sql.VarChar)
sql.map.register(Numeric, sql.Numeric)

const value = 123
const query = qq`select * from tab1 where col1 = ${new Numeric(value)}`

Public API

  • quasiquote: (ss: TemplateStringsArray, ...vs: any[]) => QuasiQuote
    • Construct a quasisquote.
  • quote: (value: any) => Quote
    • Construct a quote that can be embeded in a quasiquote.
  • unquote: (qq: Quote | QuasiQuote | (() => any) | Promise<Quote> | Promise<QuasiQuote> | (() => Promise<any>)) => UnQuote
    • Construct an unquote that can be embeded in a quasiquote.
  • concatQ: (sep: string, qs: QuasiQuote[]) => QuasiQuote
    • Concatenate quasiquotes.
  • stringify: (ss: TemplateStringsArray, ...vs: any[]) => any
    • A tag function that stringify a string literal to the same string as that string literal.
  • class QuasiQuote
    • (constructor is not intended to be used to create a instance directly)
    • sendTo<T>(f: ((ss: TemplateStringsArray, ...vs: any[]) => T) | ((ss: readonly string[], ...vs: any[]) => T)): T
      • Pass a quasiquote to a tag function.
    • sendToAsync<T>(f: ((ss: TemplateStringsArray, ...vs: any[]) => (T | Promise<T>)) | ((ss: readonly string[], ...vs: any[]) => (T | Promise<T>))): Promise<T>
      • The async version of sendTo.
        • If Promises are embedded in unquotes, the async version should be used.
        • If f returns a promise, it is also awaited.
    • intoTag(): [TemplateStringsArray, ...any[]]
      • Convert a quasiquote to a captured tagged literal that can be passed to a tag function.
    • intoTagAsync(): Promise<[TemplateStringsArray, ...any[]]>
      • The async version of intoTag.
        • If Promises are embedded in unquotes, the async version should be used.
    • evaluated(): QuasiQuote
      • Evaluate a captured quasiquote.
        • Before evaluated, sendTo or intoTag of a quasiquote evaluates embeded functions in unquotes lazily.
    • evaluatedAsync(): Promise<QuasiQuote>
      • The async version of evaluated.
    • get isEmpty(): boolean
      • Return if a quasiquote is empty (that is, just `` .)
    • static empty(): QuasiQuote
      • Construct an empty quasiquote.
    • static joinQ(sep: string, q1: QuasiQuote, q2: QuasiQuote): QuasiQuote
      • Join two quasiquotes.
  • class Quote
    • (constructor is not intended to be used to create a instance directly)
  • class UnQuote
    • (constructor is not intended to be used to create a instance directly)

References

License

This library is licensed under the MIT License.