neo4j-javascript-driver icon indicating copy to clipboard operation
neo4j-javascript-driver copied to clipboard

Expand Record Object Mapping to allow Parameter Mapping

Open MaxAake opened this issue 3 weeks ago • 0 comments

closes DRIVERS-107

This PR provides support for typechecking and automatic conversion of parameters, as well using the object mapping registry to register mapping strategies for classes. This lets users directly pass objects even with problematic properties that can not be sent over bolt (like functions), by automatically converting them or by omitting them from the mapping strategy.


class Obj {
    constructor (obj) {
        this.string = obj?.string ?? 'hi'
        this.number = obj?.number ?? 1
        this.bigint = obj?.bigint ?? BigInt(1)
        this.date = obj?.date ?? "2024-01-01"
        this.localDate = obj?.localDate ?? "2024-01-01"
        this.dateTime = obj?.dateTime ?? new neo4j.DateTime(1, 1, 1, 1, 1, 1, 1, 0)._toUTC()
        this.localDateTime = obj?.localDateTime ?? new neo4j.LocalDateTime(1, 1, 1, 1, 1, 1, 1).toString()
        this.duration = obj?.duration ?? "P1DT5.00007S"
        this.time = obj?.time ?? "10:11:12.13Z"
        this.localTime = obj?.localTime ?? "10:11:12.0001"
        this.list = obj?.list ?? ["hi"]
        this.function = () => "function string" // bolt cannot send functions
        this.node = new neo4j.Node("123", [], {}) // nor can it send nodes
    }
}

const session = driver.session()
const rules = {
    number: neo4j.rule.asNumber(),
    string: neo4j.rule.asString(),
    bigint: neo4j.rule.asBigInt({acceptNumber: true}),
    date: neo4j.rule.asDate({stringify: true}), // this will ensure date is stored as a Date in the DB and retrieved as a string 
    localDate: neo4j.rule.asDate({stringify: true}),
    dateTime: neo4j.rule.asDateTime({stringify: true}),
    localDateTime: neo4j.rule.asLocalDateTime({stringify: true}),
    duration: neo4j.rule.asDuration({stringify: true}),
    time: neo4j.rule.asTime({from: "dob", stringify: true}),
    localTime: neo4j.rule.asLocalTime({stringify: true}),
    list: neo4j.rule.asList({ apply: neo4j.rule.asString() }),
} // not including function and node here will make the driver skip sending them. They could alternatively be converted to a bolt-compatible type.

neo4j.RecordObjectMapping.register(Obj, rules)

//This allows us to use camelCase for our object properties and snake_case for the properties on our node in the DB
neo4j.RecordObjectMapping.translateIdentifiers(neo4j.RecordObjectMapping.getCaseTranslator("snake_case", "camelCase"))

session.run(
  'MERGE (n {string: $string, number: $number, bigint: $bigint, date: $date, local_date: $local_date, date_time: $date_time, local_date_time: $local_date_time, duration: $duration, dob: $dob, local_time: $local_time, list: $list}) RETURN n',
  new Obj(),
  {}
).as({n: {convert: (n) => new Obj(n.as(rules))}})
.then((res) => {
    console.log(res.records[0])
    session.close()
    driver.close()
})

MaxAake avatar Nov 19 '25 14:11 MaxAake