Skip to content

feat: recognize generated schema types (SchemaTypeName + UnwrapSchema)#20

Open
mlwelles wants to merge 1 commit into
matthewmcneely:mainfrom
mlwelles:feature/schema-routing
Open

feat: recognize generated schema types (SchemaTypeName + UnwrapSchema)#20
mlwelles wants to merge 1 commit into
matthewmcneely:mainfrom
mlwelles:feature/schema-routing

Conversation

@mlwelles

@mlwelles mlwelles commented Jun 4, 2026

Copy link
Copy Markdown

Adds a small mechanism so the client recognizes generated schema/wrapper types:

  • record.go: the Schema interface (SchemaTypeName() string), the UnwrapSchema reflection helper, and the DgraphMapper interface.
  • The 7 client mutation/query methods unwrap their argument via UnwrapSchema, so a generated wrapper type routes to its backing schema struct. Plain user structs don't implement Schema and are unaffected (UnwrapSchema is identity for them).

Self-contained and additive: builds and tests green. This is the integration point that lets code generators (e.g. modusgraph-gen) emit wrapper types the client understands.

Part of a series upstreaming work from a downstream fork; opened for review/discussion.


Summary by cubic

Teach the modusgraph client to recognize generated schema wrapper types and route them to their underlying schema structs. This enables modusgraph-gen wrappers to work transparently; plain user structs are unchanged.

  • New Features
    • Added Schema interface (SchemaTypeName() string) to tag generated schema records.
    • Added UnwrapSchema to return the inner record when a wrapper exposes Unwrap(); ignores errors.Unwrap.
    • Applied UnwrapSchema in Insert, InsertRaw, Upsert, Update, Get, Query, and UpdateSchema (per-arg).
    • Backward compatible: non-Schema structs pass through unchanged.

Written for commit b74cec7. Summary will update on new commits.

Review in cubic

Add the Schema interface (SchemaTypeName), the UnwrapSchema reflection
helper, and the DgraphMapper interface (record.go). The client unwraps
schema-defining values at the mutation and query boundary so generated
wrapper types route to their backing schema struct. Plain structs do not
implement Schema and are unaffected — UnwrapSchema is identity for them.
@mlwelles mlwelles requested a review from matthewmcneely as a code owner June 4, 2026 17:48

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 3 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="record.go">

<violation number="1" location="record.go:45">
P2: UnwrapSchema misses pointer-receiver Unwrap() methods when wrapper is passed by value</violation>

<violation number="2" location="record.go:53">
P1: Potential panic when invoking reflected Unwrap() on typed nil pointer wrappers</violation>
</file>

<file name="record_test.go">

<violation number="1" location="record_test.go:73">
P2: Tests use a local `recordingClient` mock to simulate unwrapping instead of exercising real client methods, so regressions in the actual integration points (7 client mutation/query methods) may go undetected.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread record.go
Comment on lines +53 to +54
inner := m.Call(nil)[0].Interface()
if _, ok := inner.(Schema); ok {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Potential panic when invoking reflected Unwrap() on typed nil pointer wrappers

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At record.go, line 53:

<comment>Potential panic when invoking reflected Unwrap() on typed nil pointer wrappers</comment>

<file context>
@@ -0,0 +1,58 @@
+	if mt.NumIn() != 0 || mt.NumOut() != 1 {
+		return obj
+	}
+	inner := m.Call(nil)[0].Interface()
+	if _, ok := inner.(Schema); ok {
+		return inner
</file context>
Suggested change
inner := m.Call(nil)[0].Interface()
if _, ok := inner.(Schema); ok {
// Guard against typed-nil pointer wrappers
if v.Kind() == reflect.Ptr && v.IsNil() {
return obj
}
m := v.MethodByName("Unwrap")
if !m.IsValid() {
return obj
}

Comment thread record.go
if !v.IsValid() {
return obj
}
m := v.MethodByName("Unwrap")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: UnwrapSchema misses pointer-receiver Unwrap() methods when wrapper is passed by value

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At record.go, line 45:

<comment>UnwrapSchema misses pointer-receiver Unwrap() methods when wrapper is passed by value</comment>

<file context>
@@ -0,0 +1,58 @@
+	if !v.IsValid() {
+		return obj
+	}
+	m := v.MethodByName("Unwrap")
+	if !m.IsValid() {
+		return obj
</file context>
Suggested change
m := v.MethodByName("Unwrap")
m := v.MethodByName("Unwrap")
if !m.IsValid() && v.Kind() != reflect.Ptr && v.CanAddr() {
m = v.Addr().MethodByName("Unwrap")
}
if !m.IsValid() {
return obj
}

Comment thread record_test.go
seen []any
}

func (c *recordingClient) capture(obj any) any {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Tests use a local recordingClient mock to simulate unwrapping instead of exercising real client methods, so regressions in the actual integration points (7 client mutation/query methods) may go undetected.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At record_test.go, line 73:

<comment>Tests use a local `recordingClient` mock to simulate unwrapping instead of exercising real client methods, so regressions in the actual integration points (7 client mutation/query methods) may go undetected.</comment>

<file context>
@@ -0,0 +1,117 @@
+	seen []any
+}
+
+func (c *recordingClient) capture(obj any) any {
+	obj = UnwrapSchema(obj)
+	c.seen = append(c.seen, obj)
</file context>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant