This is an automated email from the ASF dual-hosted git repository.

Cole-Greer pushed a commit to branch simplePDT
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 435f10d14a69e0dfc88db618b5c983d181e62966
Author: Cole Greer <[email protected]>
AuthorDate: Wed Jun 24 21:17:19 2026 -0700

    Document PrimitivePDT: provider guide, gremlin-lang literal, upgrade note, 
CHANGELOG
    
    Documentation for the PrimitivePDT (0xF1 / g:PrimitivePdt) feature.
    
    - docs/src/dev/provider/index.asciidoc: new "Primitive Provider Defined 
Types"
      section (anchor primitive-provider-defined-types) — when to use a 
primitive
      PDT (a single opaque stringified value for types with no native TinkerPop
      representation, e.g. unsigned integers), per-GLV adapter registration
      (Java PrimitivePDTAdapter, Python register_primitive, JS 
registerPrimitive,
      Go RegisterPrimitiveFuncs, .NET IPrimitivePdtAdapter), and the
      adapter-over-annotation/attribute precedence.
    - docs/src/reference/gremlin-variants.asciidoc: document both PDT literal 
forms
      — composite PDT("name",[map]) and primitive PDT("name","value").
    - docs/src/upgrade/release-4.x.x.asciidoc: PrimitivePDT upgrade note.
    - CHANGELOG.asciidoc: entry in the current unreleased section.
    
    The GraphBinary (0xf1, {type}{value} two fully-qualified Strings) and 
GraphSON
    (g:PrimitivePdt, untyped string value) spec sections already matched the
    implementation and required no changes.
    
    tinkerpop-2gy.13
    
    Assisted-by: Kiro:claude-opus-4.8
---
 CHANGELOG.asciidoc                           |   1 +
 docs/src/dev/provider/index.asciidoc         | 111 +++++++++++++++++++++++++++
 docs/src/reference/gremlin-variants.asciidoc |  21 +++++
 docs/src/upgrade/release-4.x.x.asciidoc      |  14 ++++
 4 files changed, 147 insertions(+)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 4971f79217..20b93a608a 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -30,6 +30,7 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Added typed numeric wrappers and `preciseNumbers` connection option to 
`gremlin-javascript` for explicit control over numeric type serialization and 
deserialization.
 * Added `NextN(n)` to `Traversal` in `gremlin-go` for batched result 
iteration, providing API parity with `next(n)` in the Java, Python, and .NET 
GLVs, and updated the Go translators in `gremlin-core` and `gremlin-javascript` 
to emit `NextN(n)` for the batched form.
 * Added Provider Defined Types (PDT) support — graph providers can define 
custom types via `@ProviderDefined` annotation that serialize/deserialize 
seamlessly across all GLVs without driver-side configuration. Replaces TP3 
custom type mechanism.
+* Added Primitive Provider Defined Types (PrimitivePDT) — a single opaque 
stringified value variant of PDT for types with no native TinkerPop 
representation (e.g. unsigned integers). Supported across all GLVs via adapter 
registration.
 * Added Gremlator, a single page web application, that translates Gremlin into 
various programming languages like Javascript and Python.
 * Added explicit transaction support to all non-Java GLVs (gremlin-python, 
gremlin-go, gremlin-javascript, gremlin-dotnet).
 * Changed default transaction close behavior from commit to rollback across 
all GLVs to align with embedded graph defaults.
diff --git a/docs/src/dev/provider/index.asciidoc 
b/docs/src/dev/provider/index.asciidoc
index 45c4cd8a91..6ce6e0bc45 100644
--- a/docs/src/dev/provider/index.asciidoc
+++ b/docs/src/dev/provider/index.asciidoc
@@ -1577,6 +1577,117 @@ serialization and the registry handles inbound 
reconstruction.
 For driver users consuming PDTs, see the <<gremlin-variants,Gremlin Variants>> 
reference documentation for
 each language driver.
 
+[[primitive-provider-defined-types]]
+==== Primitive Provider Defined Types
+
+When a custom type is best represented as a single opaque stringified value 
rather than a map of fields — for example,
+an unsigned 32-bit integer, a WKT geometry string, or a provider-specific 
identifier — use a *Primitive PDT* instead of
+a Composite PDT. A Primitive PDT carries only a type name and a string value; 
TinkerPop never parses or interprets the
+value.
+
+On the wire, a Primitive PDT is serialized as GraphBinary type `0xf1` (two 
fully-qualified Strings: type and value) or
+GraphSON type `g:PrimitivePdt` (with an untyped JSON string value). In 
gremlin-lang, the literal form is
+`PDT("name","value")` — an overload of the composite `PDT("name",[map])` 
literal where the second argument is a string
+instead of a map.
+
+A type may be registered as composite *or* primitive, not both — attempting to 
register a type for both forms throws an
+error.
+
+===== Adapter Precedence
+
+A registered adapter always takes precedence over annotation/attribute-based 
handling on dehydration. This is consistent
+across all GLVs: if an adapter is registered for a type, it controls 
serialization regardless of whether the class is
+also annotated.
+
+===== Java
+
+Implement `PrimitivePDTAdapter<T>`:
+
+[source,java]
+----
+public class Uint32Adapter implements PrimitivePDTAdapter<Uint32> {
+    @Override public String typeName() { return "mygraph:Uint32"; }
+    @Override public Class<Uint32> targetClass() { return Uint32.class; }
+    @Override public String toValue(Uint32 obj) { return 
Long.toUnsignedString(obj.getValue()); }
+    @Override public Uint32 fromValue(String value) { return new 
Uint32(Integer.parseUnsignedInt(value)); }
+}
+----
+
+Register via ServiceLoader in the same way as composite adapters — add the 
fully qualified class name to
+`META-INF/services/org.apache.tinkerpop.gremlin.structure.io.pdt.PrimitivePDTAdapter`.
+
+===== Python
+
+Use `register_primitive` on the registry:
+
+[source,python]
+----
+from gremlin_python.structure.graph import ProviderDefinedTypeRegistry
+
+registry = ProviderDefinedTypeRegistry()
+registry.register_primitive('mygraph:Uint32',
+    from_value=lambda s: Uint32(int(s)),
+    to_value=lambda obj: str(obj.value),
+    target_class=Uint32)
+----
+
+===== JavaScript
+
+Use `registerPrimitive` with a `PrimitivePdtAdapter`:
+
+[source,javascript]
+----
+const { ProviderDefinedTypeRegistry, PrimitivePdtAdapter } = 
require('gremlin');
+
+const registry = new ProviderDefinedTypeRegistry();
+registry.registerPrimitive('mygraph:Uint32', new PrimitivePdtAdapter(
+    (str) => new Uint32(parseInt(str)),   // fromValue
+    (obj) => obj.value.toString()          // toValue
+), Uint32);
+----
+
+===== Go
+
+Use `RegisterPrimitiveFuncs` or `RegisterPrimitiveFuncsWithType`:
+
+[source,go]
+----
+registry := gremlingo.NewPDTRegistry()
+registry.RegisterPrimitiveFuncsWithType("mygraph:Uint32", 
reflect.TypeOf(Uint32{}),
+    // hydrate: string -> Go type
+    func(value string) (interface{}, error) {
+        v, err := strconv.ParseUint(value, 10, 32)
+        return Uint32{Value: uint32(v)}, err
+    },
+    // dehydrate: Go type -> string
+    func(obj interface{}) (string, error) {
+        return strconv.FormatUint(uint64(obj.(Uint32).Value), 10), nil
+    },
+)
+----
+
+===== .NET
+
+Implement `IPrimitivePdtAdapter<T>`:
+
+[source,csharp]
+----
+public class Uint32Adapter : IPrimitivePdtAdapter<Uint32>
+{
+    public string TypeName => "mygraph:Uint32";
+    public Uint32 FromString(string value) => new Uint32(uint.Parse(value));
+    public string ToString(Uint32 obj) => obj.Value.ToString();
+}
+----
+
+Register on the `ProviderDefinedTypeRegistry` in the same way as composite 
adapters.
+
+===== Value Type
+
+Across all GLVs, unhydrated primitive PDT values are represented as 
`PrimitiveProviderDefinedType` objects containing a
+`name` (or `Name`) and a string `value` (or `Value`). When no adapter is 
registered for a given type name, the driver
+returns this generic value object.
+
 [[gremlin-plugins]]
 == Gremlin Plugins
 
diff --git a/docs/src/reference/gremlin-variants.asciidoc 
b/docs/src/reference/gremlin-variants.asciidoc
index 7a8405b292..4e01d73113 100644
--- a/docs/src/reference/gremlin-variants.asciidoc
+++ b/docs/src/reference/gremlin-variants.asciidoc
@@ -116,6 +116,27 @@ string is valid within the ANTLR grammar:
 
 For example, a string value `say "hello"` would be serialized as `"say 
\"hello\""` in the canonical Gremlin string.
 
+==== PDT Literals
+
+The gremlin-lang grammar supports Provider Defined Type literals in two forms:
+
+* Composite: `PDT("typeName",[key:"value",...])`  — creates a 
`ProviderDefinedType` with a map of fields.
+* Primitive: `PDT("typeName","value")` — creates a 
`PrimitiveProviderDefinedType` with an opaque string value.
+
+Both forms share the `PDT(` prefix. The second argument determines the 
variant: a map literal produces a composite PDT,
+a string literal produces a primitive PDT.
+
+Examples:
+
+[source,groovy]
+----
+// Composite PDT — a Point with x and y fields
+g.inject(PDT("mygraph:Point",["x":1.0,"y":2.0]))
+
+// Primitive PDT — an unsigned 32-bit integer as a stringified value
+g.inject(PDT("mygraph:Uint32","4294967295"))
+----
+
 The following sections describe each language variant and driver that is 
officially TinkerPop a part of the project,
 providing more detailed information about usage, configuration and known 
limitations.
 
diff --git a/docs/src/upgrade/release-4.x.x.asciidoc 
b/docs/src/upgrade/release-4.x.x.asciidoc
index ac8debb0a9..88fe8d51a9 100644
--- a/docs/src/upgrade/release-4.x.x.asciidoc
+++ b/docs/src/upgrade/release-4.x.x.asciidoc
@@ -545,6 +545,10 @@ effort to the old custom serializer approach but is 
entirely optional for basic
 * <<gremlin-dotnet-pdt,Gremlin.Net>>
 * <<gremlin-go-pdt,Gremlin-Go>>
 
+PDTs come in two flavors: *Composite* (a type name plus a map of fields, for 
structured types) and *Primitive* (a type
+name plus a single opaque string value, for types expressible as a single 
stringified value). The gremlin-lang grammar
+supports both forms via the `PDT("name",[map])` and `PDT("name","value")` 
literals respectively.
+
 
 === Upgrading for Providers
 
@@ -565,6 +569,16 @@ benefiting all driver users transparently.
 See <<provider-defined-types>> for full details on annotation usage, field 
filtering, nested types, and ServiceLoader
 registration.
 
+===== Primitive Provider Defined Types
+
+In addition to composite PDTs (which carry a map of fields), providers can now 
expose *Primitive PDTs* — types
+represented as a single opaque stringified value (GraphBinary type `0xf1`, 
GraphSON type `g:PrimitivePdt`). This is
+ideal for types with no native TinkerPop representation that can be expressed 
as a single string, such as unsigned
+integers or WKT geometry strings. Each GLV provides an adapter interface for 
primitive PDTs
+(`PrimitivePDTAdapter` in Java, `register_primitive` in Python, 
`registerPrimitive` in JavaScript,
+`RegisterPrimitiveFuncs` in Go, `IPrimitivePdtAdapter<T>` in .NET). A type may 
be registered as composite or
+primitive, not both. See <<primitive-provider-defined-types>> for details.
+
 ==== Graph Driver Providers
 
 == TinkerPop 4.0.0-beta.2

Reply via email to