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 🙏

© 2026 – Pkg Stats / Ryan Hefner

gcyphrq-ext-apoc-commons

v0.1.1

Published

Common APOC utility functions for gcyphrq (text, collection, map, math, date)

Readme

gcyphrq-ext-apoc-commons

Common APOC utility functions for gcyphrq.

Provides text, collection, map, math, and date utility functions mirroring the most-used functions from Neo4j's APOC library.

Install

npm install gcyphrq-ext-apoc-commons

Usage

CLI

gcyphrq -g graph.json --ext-fn apoc-commons \
  -e 'RETURN apoc.text.join(", ", ["a", "b", "c"]) AS joined'

# Multiple extensions can be combined
gcyphrq -g graph.json --ext-fn apoc-commons --ext-fn apoc-crypto \
  -e 'RETURN apoc.text.capitalize("hello") AS greeting'

Library

import { registerFunctionExtension, executeQuery } from 'gcyphrq';

await registerFunctionExtension('apoc-commons');

const results = await executeQuery(graphData, 'RETURN apoc.text.capitalize("hello")');

Available Functions

text.*

| Function | Description | Example | |----------|-------------|---------| | apoc.text.join(sep, values...) | Join values with separator | apoc.text.join(", ", "a", "b")"a, b" | | apoc.text.capitalize(str) | Capitalize first letter | apoc.text.capitalize("hello")"Hello" | | apoc.text.replaceAll(str, pattern, replacement) | Replace all occurrences | apoc.text.replaceAll("hello", "l", "r")"herro" | | apoc.text.substring(str, start[, end]) | Extract substring | apoc.text.substring("hello", 0, 3)"hel" | | apoc.text.defaultIfBlank(str, fallback) | Return fallback if blank | apoc.text.defaultIfBlank(" ", "hi")"hi" | | apoc.text.split(str, delimiter) | Split string into list | apoc.text.split("a,b,c", ",")["a","b","c"] | | apoc.text.repeat(str, count) | Repeat string n times | apoc.text.repeat("ab", 3)"ababab" | | apoc.text.toLowerCase(str) | Convert to lowercase | apoc.text.toLowerCase("HELLO")"hello" | | apoc.text.toUpperCase(str) | Convert to uppercase | apoc.text.toUpperCase("hello")"HELLO" | | apoc.text.trim(str) | Remove leading/trailing whitespace | apoc.text.trim(" hi ")"hi" |

coll.*

| Function | Description | Example | |----------|-------------|---------| | apoc.coll.sort(list) | Sort a list | apoc.coll.sort([3,1,2])[1,2,3] | | apoc.coll.reverse(list) | Reverse a list | apoc.coll.reverse([1,2,3])[3,2,1] | | apoc.coll.distinct(list) | Remove duplicates | apoc.coll.distinct([1,2,1])[1,2] | | apoc.coll.flatten(list) | Flatten nested arrays | apoc.coll.flatten([[1],[2,3]])[1,2,3] | | apoc.coll.zip(list1, list2, ...) | Combine lists element-wise | apoc.coll.zip([1,2], ["a","b"])[[1,"a"],[2,"b"]] | | apoc.coll.union(list1, list2) | Union of lists | apoc.coll.union([1,2],[2,3])[1,2,3] | | apoc.coll.intersection(list1, list2) | Intersection of lists | apoc.coll.intersection([1,2,3],[2,3,4])[2,3] | | apoc.coll.disjunction(list1, list2) | Items in exactly one list | apoc.coll.disjunction([1,2],[2,3])[1,3] | | apoc.coll.size(list) | Size of collection | apoc.coll.size([1,2,3])3 | | apoc.coll.min(list) | Minimum value | apoc.coll.min([3,1,2])1 | | apoc.coll.max(list) | Maximum value | apoc.coll.max([3,1,2])3 | | apoc.coll.sum(list) | Sum of values | apoc.coll.sum([1,2,3])6 | | apoc.coll.avg(list) | Average of values | apoc.coll.avg([1,2,3])2 | | apoc.coll.contains(list, item) | Check membership | apoc.coll.contains([1,2,3], 2)true | | apoc.coll.indexOf(list, item) | Find index | apoc.coll.indexOf([1,2,3], 2)1 | | apoc.coll.tail(list) | All but first | apoc.coll.tail([1,2,3])[2,3] | | apoc.coll.head(list) | First element | apoc.coll.head([1,2,3])1 | | apoc.coll.page(list, offset, size) | Slice a list | apoc.coll.page([1,2,3,4,5], 1, 3)[2,3,4] |

map.*

| Function | Description | Example | |----------|-------------|---------| | apoc.map.merge(map1, map2, ...) | Merge maps | apoc.map.merge({a:1}, {b:2}){a:1,b:2} | | apoc.map.keys(map) | Get keys | apoc.map.keys({a:1,b:2})["a","b"] | | apoc.map.values(map) | Get values | apoc.map.values({a:1,b:2})[1,2] | | apoc.map.entries(map) | Get entries | apoc.map.entries({a:1})[["a",1]] | | apoc.map.contains(map, key) | Check key exists | apoc.map.contains({a:1}, "a")true | | apoc.map.containsEntry(map, key) | Check key with non-null value | apoc.map.containsEntry({a:null}, "a")false | | apoc.map.get(map, key[, fallback]) | Get value with fallback | apoc.map.get({a:1}, "b", "default")"default" | | apoc.map.put(map, key, value) | Add/replace key-value | apoc.map.put({a:1}, "b", 2){a:1,b:2} | | apoc.map.remove(map, key) | Remove key | apoc.map.remove({a:1,b:2}, "a"){b:2} |

math.*

| Function | Description | Example | |----------|-------------|---------| | apoc.math.clamp(value, min, max) | Clamp to range | apoc.math.clamp(15, 0, 10)10 | | apoc.math.round(value[, precision]) | Round to precision | apoc.math.round(3.14159, 2)3.14 | | apoc.math.random([min, max]) | Random number | apoc.math.random(1, 10)7 | | apoc.math.abs(value) | Absolute value | apoc.math.abs(-5)5 | | apoc.math.sign(value) | Sign of number | apoc.math.sign(-5)-1 | | apoc.math.floor(value) | Floor | apoc.math.floor(3.7)3 | | apoc.math.ceil(value) | Ceiling | apoc.math.ceil(3.2)4 | | apoc.math.pow(base, exponent) | Power | apoc.math.pow(2, 10)1024 | | apoc.math.sqrt(value) | Square root | apoc.math.sqrt(16)4 | | apoc.math.log(value) | Natural logarithm | apoc.math.log(apoc.math.e())1 | | apoc.math.log10(value) | Base-10 logarithm | apoc.math.log10(100)2 | | apoc.math.exp(value) | e^x | apoc.math.exp(1)2.718... | | apoc.math.min(values...) | Minimum of values | apoc.math.min(3, 1, 2)1 | | apoc.math.max(values...) | Maximum of values | apoc.math.max(3, 1, 2)3 | | apoc.math.e() | Euler's number | apoc.math.e()2.718... | | apoc.math.pi() | Pi | apoc.math.pi()3.14159... |

date.*

| Function | Description | Example | |----------|-------------|---------| | apoc.date.parse(dateString[, format]) | Parse date string | apoc.date.parse("2024-01-15") | | apoc.date.format(date, format) | Format date | apoc.date.format(timestamp, "yyyy-MM-dd")"2024-01-15" | | apoc.date.now() | Current timestamp | apoc.date.now()1705312200000 | | apoc.date.toString(date) | ISO string | apoc.date.toString(timestamp)"2024-01-15T00:00:00.000Z" | | apoc.date.diff(from, to[, unit]) | Date difference | apoc.date.diff("2024-01-01", "2024-01-08", "days")7 |

Supported date diff units: milliseconds, seconds, minutes, hours, days, weeks, months, years.

util.*

| Function | Description | Example | |----------|-------------|---------| | apoc.util.isNumber(value) | Check if number | apoc.util.isNumber(42)true | | apoc.util.isString(value) | Check if string | apoc.util.isString("hi")true | | apoc.util.isBoolean(value) | Check if boolean | apoc.util.isBoolean(true)true | | apoc.util.isMap(value) | Check if map/object | apoc.util.isMap({a:1})true | | apoc.util.isList(value) | Check if list/array | apoc.util.isList([1,2])true | | apoc.util.toString(value) | Convert to string | apoc.util.toString(42)"42" | | apoc.util.toBoolean(value) | Convert to boolean | apoc.util.toBoolean("yes")true | | apoc.util.toInteger(value) | Convert to integer | apoc.util.toInteger("42")42 | | apoc.util.toFloat(value) | Convert to float | apoc.util.toFloat("3.14")3.14 | | apoc.util.coalesce(values...) | First non-null value | apoc.util.coalesce(null, "hi")"hi" | | apoc.util.null() | Return null | apoc.util.null()null |

Aggregations

| Function | Description | |----------|-------------| | apoc.aggregation.avgOrNull(values) | Average or null if empty | | apoc.aggregation.collectDistinct(values) | Collect unique values | | apoc.aggregation.minOrNull(values) | Minimum or null if empty | | apoc.aggregation.maxOrNull(values) | Maximum or null if empty |

Example Queries

Five ready-to-run queries demonstrating the extension with the example graphs in examples/.

1. Reader statistics — sort, average, and size

Uses the bookstore.json graph to compute per-reader reading stats: sorted book list, average rating, and total count.

gcyphrq -g examples/bookstore.json --ext-fn apoc-commons \
  -e '
    MATCH (r:Reader)-[:READ]->(b:Book)
    WITH r, collect(b.title) AS books, collect(b.rating) AS ratings
    RETURN apoc.text.capitalize(r.name) AS reader,
           apoc.coll.sort(books) AS booksRead,
           apoc.math.round(apoc.coll.avg(ratings), 2) AS avgRating,
           apoc.coll.size(books) AS totalBooks
  '

Output:

| reader | booksRead | avgRating | totalBooks | |--------|-----------|-----------|------------| | Alice | ["1984", "Foundation", "Pride and Prejudice"] | 4.6 | 3 | | Bob | ["1984", "Animal Farm", "Murder on the Orient Express"] | 4.47 | 3 | | Charlie | ["Emma", "Murder on the Orient Express", "Pride and Prejudice"] | 4.33 | 3 |

2. Customer lifetime value — sum, average, and rounding

Uses the ecommerce.json graph to compute each customer's lifetime spend and average order value.

gcyphrq -g examples/ecommerce.json --ext-fn apoc-commons \
  -e '
    MATCH (c:Customer)-[:PLACED]->(o:Order)
    WITH c, collect(o) AS orders, collect(o.total) AS totals
    RETURN apoc.text.capitalize(c.name) AS customer,
           apoc.coll.size(orders) AS orderCount,
           apoc.coll.sum(totals) AS lifetimeSpend,
           apoc.math.round(apoc.coll.avg(totals), 2) AS avgOrder,
           c.tier AS tier
  '

Output:

| customer | orderCount | lifetimeSpend | avgOrder | tier | |----------|-----------|---------------|----------|------| | Alice Johnson | 2 | 2779.96 | 1389.98 | gold | | Bob Smith | 2 | 728.97 | 364.49 | silver | | Charlie Davis | 1 | 449.98 | 449.98 | bronze | | Diana Lee | 1 | 1449.98 | 1449.98 | gold |

3. Tag cloud per book — split, uppercase, and filtering

Uses the bookstore.json graph to extract and display tags for highly-rated books.

gcyphrq -g examples/bookstore.json --ext-fn apoc-commons \
  -e '
    MATCH (b:Book)
    WHERE b.rating >= 4.5
    RETURN apoc.text.toUpperCase(b.title) AS title,
           apoc.text.split(b.tags, ",") AS tags,
           b.rating
    ORDER BY b.rating DESC
  '

Output:

| title | tags | rating | |-------|------|--------| | 1984 | ["dystopian", "classic", "political"] | 4.7 | | FOUNDATION | ["science fiction", "space", "classic"] | 4.6 | | PRIDE AND PREJUDICE | ["romance", "classic", "english"] | 4.5 |

4. Order date formatting — parse, format, and clamp

Uses the ecommerce.json graph to parse ISO timestamps, format them as dates, and clamp stock levels.

gcyphrq -g examples/ecommerce.json --ext-fn apoc-commons \
  -e '
    MATCH (o:Order)-[:CONTAINS]->(p:Product)
    RETURN o.orderId AS orderId,
           apoc.date.format(apoc.date.parse(o.date), "yyyy-MM-dd") AS orderDate,
           p.name AS product,
           apoc.math.clamp(p.stock, 0, 100) AS stockLevel
    ORDER BY o.date, p.name
  '

Output:

| orderId | orderDate | product | stockLevel | |---------|-----------|---------|------------| | ORD-001 | 2024-01-15 | Laptop Pro | 50 | | ORD-001 | 2024-01-15 | Wireless Mouse | 100 | | ORD-002 | 2024-02-20 | Standing Desk | 30 | | ORD-002 | 2024-02-20 | USB-C Hub | 100 | | ORD-003 | 2024-03-05 | Laptop Pro | 50 | | ORD-003 | 2024-03-05 | Mechanical Keyboard | 80 | | ORD-004 | 2024-03-10 | Ergonomic Chair | 25 | | ORD-004 | 2024-03-10 | Wireless Mouse | 100 | | ORD-005 | 2024-04-01 | USB-C Hub | 100 | | ORD-005 | 2024-04-01 | Wireless Mouse | 100 |

5. Contact info with coalesce — type checking and fallbacks

Uses the bookstore.json graph to safely handle missing properties with coalesce and type guards.

gcyphrq -g examples/bookstore.json --ext-fn apoc-commons \
  -e '
    MATCH (r:Reader)
    RETURN apoc.text.capitalize(r.name) AS name,
           apoc.util.coalesce(r.email, "No email on file") AS contact,
           apoc.util.toBoolean(apoc.util.isString(r.email)) AS hasEmail,
           apoc.util.isMap(r) AS isNode
  '

Output:

| name | contact | hasEmail | isNode | |------|---------|----------|--------| | Alice | [email protected] | true | true | | Bob | [email protected] | true | true | | Charlie | [email protected] | true | true |

License

MIT