Schema Definition Language Support - #154

Merged
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities
Oct 28, 2024
Merged

Schema Definition Language Support#154
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities

Conversation

@NeedleInAJayStack

@NeedleInAJayStackNeedleInAJayStack commented Oct 21, 2024

Copy link
Copy Markdown
Member

This adds full Schema Definition Language (SDL) support to this package, including:

  • Printing SDLs for existing schemas
  • Building new schemas directly from SDLs
  • Using SDL to extend already-defined schemas
  • Validating SDL schemas

It does so primarily by porting graphql-js.

Unfortunately, this is a breaking change, even though I worked hard to keep the breakages to a minimum. Notably:

  • TypeReference was deprecated. Almost all existing usage is back-supported, but recursively defined types can be problematic. Most of users won't be impacted after we update Graphiti.
  • Some public Definition type properties have changed slightly (become optional or were converted to closures). I back-supported in most cases, but it wasn't possible everywhere.

Since this is a breaking change, I'd be interested in opinions on whether we should just drop TypeReference support instead of keeping it around as deprecated. And while we're at it, should we make any other public interface changes?

Fixes#55

@NeedleInAJayStackNeedleInAJayStack self-assigned this Oct 21, 2024
@NeedleInAJayStack
NeedleInAJayStackforce-pushed the experiment/SDL-utilities branch 2 times, most recently from e4f2317 to 560ac6fCompareOctober 21, 2024 06:00
@paulofaria

paulofaria commented Oct 24, 2024

Copy link
Copy Markdown
Member

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from. When you say TypeReference was deprecated, what exactly do you mean. Maybe I'm misremembering stuff, though?

@NeedleInAJayStack

NeedleInAJayStack commented Oct 25, 2024

Copy link
Copy Markdown
MemberAuthor

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from.

Oh thanks, that's very good background! In this PR I was able to get all existing GraphQL and Graphiti tests running without TypeReferences after changing the GraphQLObject field property to a closure-based API. A pretty good example of the change can be seen in this comment diff: https://github.com/GraphQLSwift/GraphQL/pull/154/files#diff-a5342873cae3c47e54aedd945d19280fa6c7d03f66ad1f7ab13b16ec79c9acf1L288-L299 I'd be interested in your thoughts and if you see any gaps with that approach!

When you say TypeReference was deprecated, what exactly do you mean.

I marked it with @available(*, deprecated, ...)here. By doing so, it will give compiler warnings to anyone that is using it, but will still compile. I did this back when I thought I would be able to make this PR a minor version bump, but if it requires a major it seems like we maybe ought to just delete it.

Also, sorry - I know this is a humongous pull request. Unfortunately all these features use each other in their tests so it was hard to decouple them into separate pull requests.

@paulofaria

Copy link
Copy Markdown
Member

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

About the PR size, no worries, I am famous for such PRs myself. 😂

@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

Sure, here's an example of a recursive type with TypeReference removed. This works out-of-the-box because CharacterInterface is a global variable.

For non-globals, you can do hit the issue of referencing a variable in a closure before it is created. This is solved by just creating the GraphQL type with empty fields, and then setting the fields closure in a subsequent line. This function contains a test schema that uses this approach on a recursive type. Note that this has the added benefit of allowing the user to avoid the memory cycle caused by recursive types.

Downstream in Graphiti, this then works exactly as you'd expect, where type references are no longer necessary to handle creation ordering/etc

@paulofaria

Copy link
Copy Markdown
Member

Oh, that's great news. I'm not sure if SSWG has any guidelines regarding deprecation. I imagine that as long as we follow SEMVER we're fine. So, if we're going to bump to a major version anyway, I'd say let's remove it altogether. Maybe just add some documentation somewhere explaining how to deal with its absence like you just explained.

paulofaria
paulofaria previously approved these changes Oct 27, 2024
@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

I'm not sure if SSWG has any guidelines regarding deprecation.

I looked through the docs here, but it doesn't appear they have any deprecation requirements, so it seems like we're just okay bumping major.

just add some documentation somewhere explaining how to deal with its absence like you just explained.

Great point. I've added a MIGRATION.md file and linked it from the README, and I've removed GraphQLTypeReference and all usage.

You mind giving it one more quick look? Thanks for the review!

@paulofaria

Copy link
Copy Markdown
Member

Perfect! Awesome work, man! 😄

@NeedleInAJayStack
NeedleInAJayStack merged commit 5e098b3 into GraphQLSwift:mainOct 28, 2024
Sign up for freeto 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.

SDL support

2 participants

@NeedleInAJayStack@paulofaria
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Schema Definition Language Support - #154

Merged
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities
Oct 28, 2024
Merged

Schema Definition Language Support#154
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities

Conversation

@NeedleInAJayStack

@NeedleInAJayStackNeedleInAJayStack commented Oct 21, 2024

Copy link
Copy Markdown
Member

This adds full Schema Definition Language (SDL) support to this package, including:

  • Printing SDLs for existing schemas
  • Building new schemas directly from SDLs
  • Using SDL to extend already-defined schemas
  • Validating SDL schemas

It does so primarily by porting graphql-js.

Unfortunately, this is a breaking change, even though I worked hard to keep the breakages to a minimum. Notably:

  • TypeReference was deprecated. Almost all existing usage is back-supported, but recursively defined types can be problematic. Most of users won't be impacted after we update Graphiti.
  • Some public Definition type properties have changed slightly (become optional or were converted to closures). I back-supported in most cases, but it wasn't possible everywhere.

Since this is a breaking change, I'd be interested in opinions on whether we should just drop TypeReference support instead of keeping it around as deprecated. And while we're at it, should we make any other public interface changes?

Fixes#55

@NeedleInAJayStackNeedleInAJayStack self-assigned this Oct 21, 2024
@NeedleInAJayStack
NeedleInAJayStackforce-pushed the experiment/SDL-utilities branch 2 times, most recently from e4f2317 to 560ac6fCompareOctober 21, 2024 06:00
@paulofaria

paulofaria commented Oct 24, 2024

Copy link
Copy Markdown
Member

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from. When you say TypeReference was deprecated, what exactly do you mean. Maybe I'm misremembering stuff, though?

@NeedleInAJayStack

NeedleInAJayStack commented Oct 25, 2024

Copy link
Copy Markdown
MemberAuthor

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from.

Oh thanks, that's very good background! In this PR I was able to get all existing GraphQL and Graphiti tests running without TypeReferences after changing the GraphQLObject field property to a closure-based API. A pretty good example of the change can be seen in this comment diff: https://github.com/GraphQLSwift/GraphQL/pull/154/files#diff-a5342873cae3c47e54aedd945d19280fa6c7d03f66ad1f7ab13b16ec79c9acf1L288-L299 I'd be interested in your thoughts and if you see any gaps with that approach!

When you say TypeReference was deprecated, what exactly do you mean.

I marked it with @available(*, deprecated, ...)here. By doing so, it will give compiler warnings to anyone that is using it, but will still compile. I did this back when I thought I would be able to make this PR a minor version bump, but if it requires a major it seems like we maybe ought to just delete it.

Also, sorry - I know this is a humongous pull request. Unfortunately all these features use each other in their tests so it was hard to decouple them into separate pull requests.

@paulofaria

Copy link
Copy Markdown
Member

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

About the PR size, no worries, I am famous for such PRs myself. 😂

@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

Sure, here's an example of a recursive type with TypeReference removed. This works out-of-the-box because CharacterInterface is a global variable.

For non-globals, you can do hit the issue of referencing a variable in a closure before it is created. This is solved by just creating the GraphQL type with empty fields, and then setting the fields closure in a subsequent line. This function contains a test schema that uses this approach on a recursive type. Note that this has the added benefit of allowing the user to avoid the memory cycle caused by recursive types.

Downstream in Graphiti, this then works exactly as you'd expect, where type references are no longer necessary to handle creation ordering/etc

@paulofaria

Copy link
Copy Markdown
Member

Oh, that's great news. I'm not sure if SSWG has any guidelines regarding deprecation. I imagine that as long as we follow SEMVER we're fine. So, if we're going to bump to a major version anyway, I'd say let's remove it altogether. Maybe just add some documentation somewhere explaining how to deal with its absence like you just explained.

paulofaria
paulofaria previously approved these changes Oct 27, 2024
@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

I'm not sure if SSWG has any guidelines regarding deprecation.

I looked through the docs here, but it doesn't appear they have any deprecation requirements, so it seems like we're just okay bumping major.

just add some documentation somewhere explaining how to deal with its absence like you just explained.

Great point. I've added a MIGRATION.md file and linked it from the README, and I've removed GraphQLTypeReference and all usage.

You mind giving it one more quick look? Thanks for the review!

@paulofaria

Copy link
Copy Markdown
Member

Perfect! Awesome work, man! 😄

@NeedleInAJayStack
NeedleInAJayStack merged commit 5e098b3 into GraphQLSwift:mainOct 28, 2024
Sign up for freeto 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.

SDL support

2 participants

@NeedleInAJayStack@paulofaria
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Schema Definition Language Support - #154

Merged
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities
Oct 28, 2024
Merged

Schema Definition Language Support#154
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities

Conversation

@NeedleInAJayStack

@NeedleInAJayStackNeedleInAJayStack commented Oct 21, 2024

Copy link
Copy Markdown
Member

This adds full Schema Definition Language (SDL) support to this package, including:

  • Printing SDLs for existing schemas
  • Building new schemas directly from SDLs
  • Using SDL to extend already-defined schemas
  • Validating SDL schemas

It does so primarily by porting graphql-js.

Unfortunately, this is a breaking change, even though I worked hard to keep the breakages to a minimum. Notably:

  • TypeReference was deprecated. Almost all existing usage is back-supported, but recursively defined types can be problematic. Most of users won't be impacted after we update Graphiti.
  • Some public Definition type properties have changed slightly (become optional or were converted to closures). I back-supported in most cases, but it wasn't possible everywhere.

Since this is a breaking change, I'd be interested in opinions on whether we should just drop TypeReference support instead of keeping it around as deprecated. And while we're at it, should we make any other public interface changes?

Fixes#55

@NeedleInAJayStackNeedleInAJayStack self-assigned this Oct 21, 2024
@NeedleInAJayStack
NeedleInAJayStackforce-pushed the experiment/SDL-utilities branch 2 times, most recently from e4f2317 to 560ac6fCompareOctober 21, 2024 06:00
@paulofaria

paulofaria commented Oct 24, 2024

Copy link
Copy Markdown
Member

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from. When you say TypeReference was deprecated, what exactly do you mean. Maybe I'm misremembering stuff, though?

@NeedleInAJayStack

NeedleInAJayStack commented Oct 25, 2024

Copy link
Copy Markdown
MemberAuthor

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from.

Oh thanks, that's very good background! In this PR I was able to get all existing GraphQL and Graphiti tests running without TypeReferences after changing the GraphQLObject field property to a closure-based API. A pretty good example of the change can be seen in this comment diff: https://github.com/GraphQLSwift/GraphQL/pull/154/files#diff-a5342873cae3c47e54aedd945d19280fa6c7d03f66ad1f7ab13b16ec79c9acf1L288-L299 I'd be interested in your thoughts and if you see any gaps with that approach!

When you say TypeReference was deprecated, what exactly do you mean.

I marked it with @available(*, deprecated, ...)here. By doing so, it will give compiler warnings to anyone that is using it, but will still compile. I did this back when I thought I would be able to make this PR a minor version bump, but if it requires a major it seems like we maybe ought to just delete it.

Also, sorry - I know this is a humongous pull request. Unfortunately all these features use each other in their tests so it was hard to decouple them into separate pull requests.

@paulofaria

Copy link
Copy Markdown
Member

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

About the PR size, no worries, I am famous for such PRs myself. 😂

@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

Sure, here's an example of a recursive type with TypeReference removed. This works out-of-the-box because CharacterInterface is a global variable.

For non-globals, you can do hit the issue of referencing a variable in a closure before it is created. This is solved by just creating the GraphQL type with empty fields, and then setting the fields closure in a subsequent line. This function contains a test schema that uses this approach on a recursive type. Note that this has the added benefit of allowing the user to avoid the memory cycle caused by recursive types.

Downstream in Graphiti, this then works exactly as you'd expect, where type references are no longer necessary to handle creation ordering/etc

@paulofaria

Copy link
Copy Markdown
Member

Oh, that's great news. I'm not sure if SSWG has any guidelines regarding deprecation. I imagine that as long as we follow SEMVER we're fine. So, if we're going to bump to a major version anyway, I'd say let's remove it altogether. Maybe just add some documentation somewhere explaining how to deal with its absence like you just explained.

paulofaria
paulofaria previously approved these changes Oct 27, 2024
@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

I'm not sure if SSWG has any guidelines regarding deprecation.

I looked through the docs here, but it doesn't appear they have any deprecation requirements, so it seems like we're just okay bumping major.

just add some documentation somewhere explaining how to deal with its absence like you just explained.

Great point. I've added a MIGRATION.md file and linked it from the README, and I've removed GraphQLTypeReference and all usage.

You mind giving it one more quick look? Thanks for the review!

@paulofaria

Copy link
Copy Markdown
Member

Perfect! Awesome work, man! 😄

@NeedleInAJayStack
NeedleInAJayStack merged commit 5e098b3 into GraphQLSwift:mainOct 28, 2024
Sign up for freeto 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.

SDL support

2 participants

@NeedleInAJayStack@paulofaria
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Schema Definition Language Support - #154

Merged
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities
Oct 28, 2024
Merged

Schema Definition Language Support#154
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities

Conversation

@NeedleInAJayStack

@NeedleInAJayStackNeedleInAJayStack commented Oct 21, 2024

Copy link
Copy Markdown
Member

This adds full Schema Definition Language (SDL) support to this package, including:

  • Printing SDLs for existing schemas
  • Building new schemas directly from SDLs
  • Using SDL to extend already-defined schemas
  • Validating SDL schemas

It does so primarily by porting graphql-js.

Unfortunately, this is a breaking change, even though I worked hard to keep the breakages to a minimum. Notably:

  • TypeReference was deprecated. Almost all existing usage is back-supported, but recursively defined types can be problematic. Most of users won't be impacted after we update Graphiti.
  • Some public Definition type properties have changed slightly (become optional or were converted to closures). I back-supported in most cases, but it wasn't possible everywhere.

Since this is a breaking change, I'd be interested in opinions on whether we should just drop TypeReference support instead of keeping it around as deprecated. And while we're at it, should we make any other public interface changes?

Fixes#55

@NeedleInAJayStackNeedleInAJayStack self-assigned this Oct 21, 2024
@NeedleInAJayStack
NeedleInAJayStackforce-pushed the experiment/SDL-utilities branch 2 times, most recently from e4f2317 to 560ac6fCompareOctober 21, 2024 06:00
@paulofaria

paulofaria commented Oct 24, 2024

Copy link
Copy Markdown
Member

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from. When you say TypeReference was deprecated, what exactly do you mean. Maybe I'm misremembering stuff, though?

@NeedleInAJayStack

NeedleInAJayStack commented Oct 25, 2024

Copy link
Copy Markdown
MemberAuthor

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from.

Oh thanks, that's very good background! In this PR I was able to get all existing GraphQL and Graphiti tests running without TypeReferences after changing the GraphQLObject field property to a closure-based API. A pretty good example of the change can be seen in this comment diff: https://github.com/GraphQLSwift/GraphQL/pull/154/files#diff-a5342873cae3c47e54aedd945d19280fa6c7d03f66ad1f7ab13b16ec79c9acf1L288-L299 I'd be interested in your thoughts and if you see any gaps with that approach!

When you say TypeReference was deprecated, what exactly do you mean.

I marked it with @available(*, deprecated, ...)here. By doing so, it will give compiler warnings to anyone that is using it, but will still compile. I did this back when I thought I would be able to make this PR a minor version bump, but if it requires a major it seems like we maybe ought to just delete it.

Also, sorry - I know this is a humongous pull request. Unfortunately all these features use each other in their tests so it was hard to decouple them into separate pull requests.

@paulofaria

Copy link
Copy Markdown
Member

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

About the PR size, no worries, I am famous for such PRs myself. 😂

@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

Sure, here's an example of a recursive type with TypeReference removed. This works out-of-the-box because CharacterInterface is a global variable.

For non-globals, you can do hit the issue of referencing a variable in a closure before it is created. This is solved by just creating the GraphQL type with empty fields, and then setting the fields closure in a subsequent line. This function contains a test schema that uses this approach on a recursive type. Note that this has the added benefit of allowing the user to avoid the memory cycle caused by recursive types.

Downstream in Graphiti, this then works exactly as you'd expect, where type references are no longer necessary to handle creation ordering/etc

@paulofaria

Copy link
Copy Markdown
Member

Oh, that's great news. I'm not sure if SSWG has any guidelines regarding deprecation. I imagine that as long as we follow SEMVER we're fine. So, if we're going to bump to a major version anyway, I'd say let's remove it altogether. Maybe just add some documentation somewhere explaining how to deal with its absence like you just explained.

paulofaria
paulofaria previously approved these changes Oct 27, 2024
@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

I'm not sure if SSWG has any guidelines regarding deprecation.

I looked through the docs here, but it doesn't appear they have any deprecation requirements, so it seems like we're just okay bumping major.

just add some documentation somewhere explaining how to deal with its absence like you just explained.

Great point. I've added a MIGRATION.md file and linked it from the README, and I've removed GraphQLTypeReference and all usage.

You mind giving it one more quick look? Thanks for the review!

@paulofaria

Copy link
Copy Markdown
Member

Perfect! Awesome work, man! 😄

@NeedleInAJayStack
NeedleInAJayStack merged commit 5e098b3 into GraphQLSwift:mainOct 28, 2024
Sign up for freeto 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.

SDL support

2 participants

@NeedleInAJayStack@paulofaria
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Schema Definition Language Support - #154

Merged
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities
Oct 28, 2024
Merged

Schema Definition Language Support#154
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities

Conversation

@NeedleInAJayStack

@NeedleInAJayStackNeedleInAJayStack commented Oct 21, 2024

Copy link
Copy Markdown
Member

This adds full Schema Definition Language (SDL) support to this package, including:

  • Printing SDLs for existing schemas
  • Building new schemas directly from SDLs
  • Using SDL to extend already-defined schemas
  • Validating SDL schemas

It does so primarily by porting graphql-js.

Unfortunately, this is a breaking change, even though I worked hard to keep the breakages to a minimum. Notably:

  • TypeReference was deprecated. Almost all existing usage is back-supported, but recursively defined types can be problematic. Most of users won't be impacted after we update Graphiti.
  • Some public Definition type properties have changed slightly (become optional or were converted to closures). I back-supported in most cases, but it wasn't possible everywhere.

Since this is a breaking change, I'd be interested in opinions on whether we should just drop TypeReference support instead of keeping it around as deprecated. And while we're at it, should we make any other public interface changes?

Fixes#55

@NeedleInAJayStackNeedleInAJayStack self-assigned this Oct 21, 2024
@NeedleInAJayStack
NeedleInAJayStackforce-pushed the experiment/SDL-utilities branch 2 times, most recently from e4f2317 to 560ac6fCompareOctober 21, 2024 06:00
@paulofaria

paulofaria commented Oct 24, 2024

Copy link
Copy Markdown
Member

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from. When you say TypeReference was deprecated, what exactly do you mean. Maybe I'm misremembering stuff, though?

@NeedleInAJayStack

NeedleInAJayStack commented Oct 25, 2024

Copy link
Copy Markdown
MemberAuthor

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from.

Oh thanks, that's very good background! In this PR I was able to get all existing GraphQL and Graphiti tests running without TypeReferences after changing the GraphQLObject field property to a closure-based API. A pretty good example of the change can be seen in this comment diff: https://github.com/GraphQLSwift/GraphQL/pull/154/files#diff-a5342873cae3c47e54aedd945d19280fa6c7d03f66ad1f7ab13b16ec79c9acf1L288-L299 I'd be interested in your thoughts and if you see any gaps with that approach!

When you say TypeReference was deprecated, what exactly do you mean.

I marked it with @available(*, deprecated, ...)here. By doing so, it will give compiler warnings to anyone that is using it, but will still compile. I did this back when I thought I would be able to make this PR a minor version bump, but if it requires a major it seems like we maybe ought to just delete it.

Also, sorry - I know this is a humongous pull request. Unfortunately all these features use each other in their tests so it was hard to decouple them into separate pull requests.

@paulofaria

Copy link
Copy Markdown
Member

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

About the PR size, no worries, I am famous for such PRs myself. 😂

@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

Sure, here's an example of a recursive type with TypeReference removed. This works out-of-the-box because CharacterInterface is a global variable.

For non-globals, you can do hit the issue of referencing a variable in a closure before it is created. This is solved by just creating the GraphQL type with empty fields, and then setting the fields closure in a subsequent line. This function contains a test schema that uses this approach on a recursive type. Note that this has the added benefit of allowing the user to avoid the memory cycle caused by recursive types.

Downstream in Graphiti, this then works exactly as you'd expect, where type references are no longer necessary to handle creation ordering/etc

@paulofaria

Copy link
Copy Markdown
Member

Oh, that's great news. I'm not sure if SSWG has any guidelines regarding deprecation. I imagine that as long as we follow SEMVER we're fine. So, if we're going to bump to a major version anyway, I'd say let's remove it altogether. Maybe just add some documentation somewhere explaining how to deal with its absence like you just explained.

paulofaria
paulofaria previously approved these changes Oct 27, 2024
@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

I'm not sure if SSWG has any guidelines regarding deprecation.

I looked through the docs here, but it doesn't appear they have any deprecation requirements, so it seems like we're just okay bumping major.

just add some documentation somewhere explaining how to deal with its absence like you just explained.

Great point. I've added a MIGRATION.md file and linked it from the README, and I've removed GraphQLTypeReference and all usage.

You mind giving it one more quick look? Thanks for the review!

@paulofaria

Copy link
Copy Markdown
Member

Perfect! Awesome work, man! 😄

@NeedleInAJayStack
NeedleInAJayStack merged commit 5e098b3 into GraphQLSwift:mainOct 28, 2024
Sign up for freeto 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.

SDL support

2 participants

@NeedleInAJayStack@paulofaria
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Schema Definition Language Support - #154

Merged
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities
Oct 28, 2024
Merged

Schema Definition Language Support#154
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities

Conversation

@NeedleInAJayStack

@NeedleInAJayStackNeedleInAJayStack commented Oct 21, 2024

Copy link
Copy Markdown
Member

This adds full Schema Definition Language (SDL) support to this package, including:

  • Printing SDLs for existing schemas
  • Building new schemas directly from SDLs
  • Using SDL to extend already-defined schemas
  • Validating SDL schemas

It does so primarily by porting graphql-js.

Unfortunately, this is a breaking change, even though I worked hard to keep the breakages to a minimum. Notably:

  • TypeReference was deprecated. Almost all existing usage is back-supported, but recursively defined types can be problematic. Most of users won't be impacted after we update Graphiti.
  • Some public Definition type properties have changed slightly (become optional or were converted to closures). I back-supported in most cases, but it wasn't possible everywhere.

Since this is a breaking change, I'd be interested in opinions on whether we should just drop TypeReference support instead of keeping it around as deprecated. And while we're at it, should we make any other public interface changes?

Fixes#55

@NeedleInAJayStackNeedleInAJayStack self-assigned this Oct 21, 2024
@NeedleInAJayStack
NeedleInAJayStackforce-pushed the experiment/SDL-utilities branch 2 times, most recently from e4f2317 to 560ac6fCompareOctober 21, 2024 06:00
@paulofaria

paulofaria commented Oct 24, 2024

Copy link
Copy Markdown
Member

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from. When you say TypeReference was deprecated, what exactly do you mean. Maybe I'm misremembering stuff, though?

@NeedleInAJayStack

NeedleInAJayStack commented Oct 25, 2024

Copy link
Copy Markdown
MemberAuthor

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from.

Oh thanks, that's very good background! In this PR I was able to get all existing GraphQL and Graphiti tests running without TypeReferences after changing the GraphQLObject field property to a closure-based API. A pretty good example of the change can be seen in this comment diff: https://github.com/GraphQLSwift/GraphQL/pull/154/files#diff-a5342873cae3c47e54aedd945d19280fa6c7d03f66ad1f7ab13b16ec79c9acf1L288-L299 I'd be interested in your thoughts and if you see any gaps with that approach!

When you say TypeReference was deprecated, what exactly do you mean.

I marked it with @available(*, deprecated, ...)here. By doing so, it will give compiler warnings to anyone that is using it, but will still compile. I did this back when I thought I would be able to make this PR a minor version bump, but if it requires a major it seems like we maybe ought to just delete it.

Also, sorry - I know this is a humongous pull request. Unfortunately all these features use each other in their tests so it was hard to decouple them into separate pull requests.

@paulofaria

Copy link
Copy Markdown
Member

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

About the PR size, no worries, I am famous for such PRs myself. 😂

@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

Sure, here's an example of a recursive type with TypeReference removed. This works out-of-the-box because CharacterInterface is a global variable.

For non-globals, you can do hit the issue of referencing a variable in a closure before it is created. This is solved by just creating the GraphQL type with empty fields, and then setting the fields closure in a subsequent line. This function contains a test schema that uses this approach on a recursive type. Note that this has the added benefit of allowing the user to avoid the memory cycle caused by recursive types.

Downstream in Graphiti, this then works exactly as you'd expect, where type references are no longer necessary to handle creation ordering/etc

@paulofaria

Copy link
Copy Markdown
Member

Oh, that's great news. I'm not sure if SSWG has any guidelines regarding deprecation. I imagine that as long as we follow SEMVER we're fine. So, if we're going to bump to a major version anyway, I'd say let's remove it altogether. Maybe just add some documentation somewhere explaining how to deal with its absence like you just explained.

paulofaria
paulofaria previously approved these changes Oct 27, 2024
@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

I'm not sure if SSWG has any guidelines regarding deprecation.

I looked through the docs here, but it doesn't appear they have any deprecation requirements, so it seems like we're just okay bumping major.

just add some documentation somewhere explaining how to deal with its absence like you just explained.

Great point. I've added a MIGRATION.md file and linked it from the README, and I've removed GraphQLTypeReference and all usage.

You mind giving it one more quick look? Thanks for the review!

@paulofaria

Copy link
Copy Markdown
Member

Perfect! Awesome work, man! 😄

@NeedleInAJayStack
NeedleInAJayStack merged commit 5e098b3 into GraphQLSwift:mainOct 28, 2024
Sign up for freeto 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.

SDL support

2 participants

@NeedleInAJayStack@paulofaria
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Schema Definition Language Support - #154

Merged
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities
Oct 28, 2024
Merged

Schema Definition Language Support#154
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities

Conversation

@NeedleInAJayStack

@NeedleInAJayStackNeedleInAJayStack commented Oct 21, 2024

Copy link
Copy Markdown
Member

This adds full Schema Definition Language (SDL) support to this package, including:

  • Printing SDLs for existing schemas
  • Building new schemas directly from SDLs
  • Using SDL to extend already-defined schemas
  • Validating SDL schemas

It does so primarily by porting graphql-js.

Unfortunately, this is a breaking change, even though I worked hard to keep the breakages to a minimum. Notably:

  • TypeReference was deprecated. Almost all existing usage is back-supported, but recursively defined types can be problematic. Most of users won't be impacted after we update Graphiti.
  • Some public Definition type properties have changed slightly (become optional or were converted to closures). I back-supported in most cases, but it wasn't possible everywhere.

Since this is a breaking change, I'd be interested in opinions on whether we should just drop TypeReference support instead of keeping it around as deprecated. And while we're at it, should we make any other public interface changes?

Fixes#55

@NeedleInAJayStackNeedleInAJayStack self-assigned this Oct 21, 2024
@NeedleInAJayStack
NeedleInAJayStackforce-pushed the experiment/SDL-utilities branch 2 times, most recently from e4f2317 to 560ac6fCompareOctober 21, 2024 06:00
@paulofaria

paulofaria commented Oct 24, 2024

Copy link
Copy Markdown
Member

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from. When you say TypeReference was deprecated, what exactly do you mean. Maybe I'm misremembering stuff, though?

@NeedleInAJayStack

NeedleInAJayStack commented Oct 25, 2024

Copy link
Copy Markdown
MemberAuthor

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from.

Oh thanks, that's very good background! In this PR I was able to get all existing GraphQL and Graphiti tests running without TypeReferences after changing the GraphQLObject field property to a closure-based API. A pretty good example of the change can be seen in this comment diff: https://github.com/GraphQLSwift/GraphQL/pull/154/files#diff-a5342873cae3c47e54aedd945d19280fa6c7d03f66ad1f7ab13b16ec79c9acf1L288-L299 I'd be interested in your thoughts and if you see any gaps with that approach!

When you say TypeReference was deprecated, what exactly do you mean.

I marked it with @available(*, deprecated, ...)here. By doing so, it will give compiler warnings to anyone that is using it, but will still compile. I did this back when I thought I would be able to make this PR a minor version bump, but if it requires a major it seems like we maybe ought to just delete it.

Also, sorry - I know this is a humongous pull request. Unfortunately all these features use each other in their tests so it was hard to decouple them into separate pull requests.

@paulofaria

Copy link
Copy Markdown
Member

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

About the PR size, no worries, I am famous for such PRs myself. 😂

@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

Sure, here's an example of a recursive type with TypeReference removed. This works out-of-the-box because CharacterInterface is a global variable.

For non-globals, you can do hit the issue of referencing a variable in a closure before it is created. This is solved by just creating the GraphQL type with empty fields, and then setting the fields closure in a subsequent line. This function contains a test schema that uses this approach on a recursive type. Note that this has the added benefit of allowing the user to avoid the memory cycle caused by recursive types.

Downstream in Graphiti, this then works exactly as you'd expect, where type references are no longer necessary to handle creation ordering/etc

@paulofaria

Copy link
Copy Markdown
Member

Oh, that's great news. I'm not sure if SSWG has any guidelines regarding deprecation. I imagine that as long as we follow SEMVER we're fine. So, if we're going to bump to a major version anyway, I'd say let's remove it altogether. Maybe just add some documentation somewhere explaining how to deal with its absence like you just explained.

paulofaria
paulofaria previously approved these changes Oct 27, 2024
@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

I'm not sure if SSWG has any guidelines regarding deprecation.

I looked through the docs here, but it doesn't appear they have any deprecation requirements, so it seems like we're just okay bumping major.

just add some documentation somewhere explaining how to deal with its absence like you just explained.

Great point. I've added a MIGRATION.md file and linked it from the README, and I've removed GraphQLTypeReference and all usage.

You mind giving it one more quick look? Thanks for the review!

@paulofaria

Copy link
Copy Markdown
Member

Perfect! Awesome work, man! 😄

@NeedleInAJayStack
NeedleInAJayStack merged commit 5e098b3 into GraphQLSwift:mainOct 28, 2024
Sign up for freeto 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.

SDL support

2 participants

@NeedleInAJayStack@paulofaria
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Schema Definition Language Support - #154

Merged
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities
Oct 28, 2024
Merged

Schema Definition Language Support#154
NeedleInAJayStack merged 48 commits into
GraphQLSwift:mainfrom
NeedleInAJayStack:experiment/SDL-utilities

Conversation

@NeedleInAJayStack

@NeedleInAJayStackNeedleInAJayStack commented Oct 21, 2024

Copy link
Copy Markdown
Member

This adds full Schema Definition Language (SDL) support to this package, including:

  • Printing SDLs for existing schemas
  • Building new schemas directly from SDLs
  • Using SDL to extend already-defined schemas
  • Validating SDL schemas

It does so primarily by porting graphql-js.

Unfortunately, this is a breaking change, even though I worked hard to keep the breakages to a minimum. Notably:

  • TypeReference was deprecated. Almost all existing usage is back-supported, but recursively defined types can be problematic. Most of users won't be impacted after we update Graphiti.
  • Some public Definition type properties have changed slightly (become optional or were converted to closures). I back-supported in most cases, but it wasn't possible everywhere.

Since this is a breaking change, I'd be interested in opinions on whether we should just drop TypeReference support instead of keeping it around as deprecated. And while we're at it, should we make any other public interface changes?

Fixes#55

@NeedleInAJayStackNeedleInAJayStack self-assigned this Oct 21, 2024
@NeedleInAJayStack
NeedleInAJayStackforce-pushed the experiment/SDL-utilities branch 2 times, most recently from e4f2317 to 560ac6fCompareOctober 21, 2024 06:00
@paulofaria

paulofaria commented Oct 24, 2024

Copy link
Copy Markdown
Member

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from. When you say TypeReference was deprecated, what exactly do you mean. Maybe I'm misremembering stuff, though?

@NeedleInAJayStack

NeedleInAJayStack commented Oct 25, 2024

Copy link
Copy Markdown
MemberAuthor

The main difference between the canonical implementation and ours is the need for type references. If I recall correctly, it was because JS used thunks because it allows a symbol to be used inside a closure before its value is bound. I looked for other implementations for inspiration, like Java. I think that's where I got TypeReference from.

Oh thanks, that's very good background! In this PR I was able to get all existing GraphQL and Graphiti tests running without TypeReferences after changing the GraphQLObject field property to a closure-based API. A pretty good example of the change can be seen in this comment diff: https://github.com/GraphQLSwift/GraphQL/pull/154/files#diff-a5342873cae3c47e54aedd945d19280fa6c7d03f66ad1f7ab13b16ec79c9acf1L288-L299 I'd be interested in your thoughts and if you see any gaps with that approach!

When you say TypeReference was deprecated, what exactly do you mean.

I marked it with @available(*, deprecated, ...)here. By doing so, it will give compiler warnings to anyone that is using it, but will still compile. I did this back when I thought I would be able to make this PR a minor version bump, but if it requires a major it seems like we maybe ought to just delete it.

Also, sorry - I know this is a humongous pull request. Unfortunately all these features use each other in their tests so it was hard to decouple them into separate pull requests.

@paulofaria

Copy link
Copy Markdown
Member

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

About the PR size, no worries, I am famous for such PRs myself. 😂

@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

How would cyclical or recursive references be defined without TypeReference? Can you point me to examples?

Sure, here's an example of a recursive type with TypeReference removed. This works out-of-the-box because CharacterInterface is a global variable.

For non-globals, you can do hit the issue of referencing a variable in a closure before it is created. This is solved by just creating the GraphQL type with empty fields, and then setting the fields closure in a subsequent line. This function contains a test schema that uses this approach on a recursive type. Note that this has the added benefit of allowing the user to avoid the memory cycle caused by recursive types.

Downstream in Graphiti, this then works exactly as you'd expect, where type references are no longer necessary to handle creation ordering/etc

@paulofaria

Copy link
Copy Markdown
Member

Oh, that's great news. I'm not sure if SSWG has any guidelines regarding deprecation. I imagine that as long as we follow SEMVER we're fine. So, if we're going to bump to a major version anyway, I'd say let's remove it altogether. Maybe just add some documentation somewhere explaining how to deal with its absence like you just explained.

paulofaria
paulofaria previously approved these changes Oct 27, 2024
@NeedleInAJayStack

Copy link
Copy Markdown
MemberAuthor

I'm not sure if SSWG has any guidelines regarding deprecation.

I looked through the docs here, but it doesn't appear they have any deprecation requirements, so it seems like we're just okay bumping major.

just add some documentation somewhere explaining how to deal with its absence like you just explained.

Great point. I've added a MIGRATION.md file and linked it from the README, and I've removed GraphQLTypeReference and all usage.

You mind giving it one more quick look? Thanks for the review!

@paulofaria

Copy link
Copy Markdown
Member

Perfect! Awesome work, man! 😄

@NeedleInAJayStack
NeedleInAJayStack merged commit 5e098b3 into GraphQLSwift:mainOct 28, 2024
Sign up for freeto 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.

SDL support

2 participants

@NeedleInAJayStack@paulofaria