nerdsupremacist / graphaello Goto Github PK
View Code? Open in Web Editor NEWA Tool for Writing Declarative, Type-Safe and Data-Driven Applications in SwiftUI using GraphQL
Home Page: https://graphaello.dev
License: MIT License
A Tool for Writing Declarative, Type-Safe and Data-Driven Applications in SwiftUI using GraphQL
Home Page: https://graphaello.dev
License: MIT License
On larger projects, Code Generation takes a very long time.
Evaluate caching:
I'm wondering how production ready this library is? And if not, what other features would be required to be added in until it becomes production ready? Also is there a specific timeframe for this?
Hi! Thank you for creating this great library.
As I saw int the documentation, with this code there should be autogenerated initializer similar to this CourseCell(course: PandaEntry.Course)
, but the initializer is missing. Can you please help me to understand what is the problem?
struct CourseCell: View {
@GraphQL(PandaEntry.Course.title)
var title: String?
var body: some View {
Text(title ?? "unknown")
}
}
make a nice promotional website for Graphaello...
Include some nice examples (with animations) and documentation on how it all can be used
SwiftSyntax parser library isn't compatible
Command PhaseScriptExecution failed with a nonzero exit code
☕️ Extracting APIs + Structs:
❗️ Error Occurred:
SwiftSyntax parser library isn't compatible
Error: Formulae found in multiple taps:
* nerdsupremacist/tap/graphaello
* nerdsupremacist/graphaello/graphaello
In beta 3 there is a mistake in the #if-macro-statement. The name looks like GRAPHAELLO_SWIFT_GRAPH_QL__TARGET
. There is on _
too much.
I was looking at this, and was wondering if there currently is a way to poll a query every N seconds? (E.g. if I display a set of comments, I might want to refresh the view every few seconds such that people are always up-to-date.)
Maybe use the Environment
this is same as #37
Use memoization to make sure that we have loaded everything for the current parameters
Something like this:
@dynamicMemberLookup
protocol Type: Target { }
extension Type {
// make member key paths static for the type
static subscript<T>(dynamicMember keyPath: KeyPath<GraphQLFragmentPath<Self, Self>, GraphQLFragmentPath<Self, T>>) -> GraphQLFragmentPath<Self, T> {
return .init()
}
static subscript<T>(dynamicMember keyPath: KeyPath<GraphQLFragmentPath<Self, Self>, GraphQLPath<Self, T>>) -> GraphQLPath<Self, T> {
return .init()
}
}
@dynamicMemberLookup
struct GraphQLFragmentPath<TargetType: Target, UnderlyingType> {
fileprivate init() {}
// nested values inside arrays
subscript<Value, Output>(dynamicMember _: KeyPath<GraphQLFragmentPath<TargetType, Value>, GraphQLPath<TargetType, Output>>) -> GraphQLPath<TargetType, [Output]> where UnderlyingType == [Value] {
return .init()
}
subscript<Value, Output>(dynamicMember _: KeyPath<GraphQLFragmentPath<TargetType, Value>, GraphQLPath<TargetType, Output>>) -> GraphQLPath<TargetType, [Output]?> where UnderlyingType == [Value]? {
return .init()
}
subscript<Value, Output>(dynamicMember _: KeyPath<GraphQLFragmentPath<TargetType, Value>, GraphQLFragmentPath<TargetType, Output>>) -> GraphQLPath<TargetType, [Output]> where UnderlyingType == [Value] {
return .init()
}
subscript<Value, Output>(dynamicMember _: KeyPath<GraphQLFragmentPath<TargetType, Value>, GraphQLFragmentPath<TargetType, Output>>) -> GraphQLPath<TargetType, [Output]?> where UnderlyingType == [Value]? {
return .init()
}
}
and similar strategies for dealing with optionals...
The main reason this is not being used right now is the fact that autocomplete is broken. We should evaluate if there's a way to have autocomplete working and still bringing the amount of code waaaay down
This example should be valid:
struct CountryMapPin {
@GraphQL(Covid.Country.cases)
var cases: Int
@GraphQL(Covid.Country.info.latitude)
var latitude: Double?
@GraphQL(Covid.Country.info.longitude)
var longitude: Double?
}
struct ContentView: View {
@GraphQL(Covid.countries)
var pins: [CountryMapPin]
var body: some View {
MapView(pins: pins).frame(height: 400)
}
}
We solve this by adding the following extension to every struct that has a single fragmentl:
extension CountryMapPin: Fragment {
typealias UnderlyingType = Country.UnderlyingType
}
extension CountryMapPin.Country {
func countryMapPin() -> CountryMapPin {
return CountryMapPin(country: self)
}
}
In code generation add an extra operation to implicitly convert. Create it during resolution.
To enable App Extensions, multi target support might be very useful
Currently you can change values of the GraphQL property wrapper after a mutation.
However, when the mutated value is in a Fragment, the change isn't propagated to the original dictionary from where the query originated from.
This is an issue in the following scenarios:
This will most likely require a rewrite of a lot of the GraphQL Property Wrapper and the generated initializer code
My GraphQL API has an enum which is used as a default value in a field, and when my Grapheaello.swift
is generated it does not camelize the enum (API.Lang.enUs
) when building out the query renderer function parameters:
extension API {
// lang should be:
// lang: API.Lang? = API.Lang.enUs
func contentView<Loading: View>(lang: API.Lang? = API.Lang.en_us,
@ViewBuilder loading: () -> Loading) -> some View {
return QueryRenderer(client: client,
query: ApolloAPIContentViewQuery(lang: lang),
loading: loading(),
error: { BasicErrorView(error: $0) }) { (data: ApolloAPI.ContentViewQuery.Data) -> ContentView in
ContentView(data: data)
}
}
}
For my code to compile I have to modify the Swift to be:
extension API {
func contentView<Loading: View>(lang: API.Lang? = API.Lang.enUs,
@ViewBuilder loading: () -> Loading) -> some View {
return QueryRenderer(client: client,
query: ApolloAPIContentViewQuery(lang: lang),
loading: loading(),
error: { BasicErrorView(error: $0) }) { (data: ApolloAPI.ContentViewQuery.Data) -> ContentView in
ContentView(data: data)
}
}
}
Here is the enum that is generated from the GraphQL schema:
# Lang
enum Lang {
# en-GB
EN_GB
# en-US
EN_US
}
public enum ApolloAPI {
/// Lang
public enum Lang: RawRepresentable, Equatable, Hashable, CaseIterable, Apollo.JSONDecodable, Apollo.JSONEncodable {
public typealias RawValue = String
/// en-US
case enUs
/// en-GB
case enGb
/// Auto generated constant for unknown enum values
case __unknown(RawValue)
public init?(rawValue: RawValue) {
switch rawValue {
case "EN_US": self = .enUs
case "EN_GB": self = .enGb
default: self = .__unknown(rawValue)
}
}
public var rawValue: RawValue {
switch self {
case .enUs: return "EN_US"
case .enGb: return "EN_GB"
case .__unknown(let value): return value
}
}
public static func == (lhs: Lang, rhs: Lang) -> Bool {
switch (lhs, rhs) {
case (.enUs, .enUs): return true
case (.enGb, .enGb): return true
case (.__unknown(let lhsValue), .__unknown(let rhsValue)): return lhsValue == rhsValue
default: return false
}
}
public static var allCases: [Lang] {
return [
.enUs,
.enGb,
]
}
}
}
I did some debugging and found that the expression passed to QueryRendererArgument
isn't camelizing the enum properly when rendering the Struct.swift.stencil:
Graphaello.QueryRendererArgument(name: "lang", type: "API.Lang?", expression: Optional(SwiftSyntax.ExprSyntax))
I'm not exactly sure how to change what is returned from SwiftSyntax.ExprSyntax
otherwise I'd submit a PR. Any help is appreciated!
Is it possible to use custom scalars for Graphql?
Is it activated in the project
getting M1 Mac "graphaello is not installed on your machine" even if it is
$ type "graphaello"
graphaello is /opt/homebrew/bin/graphaello
adding PATH=/opt/homebrew/bin:$PATH
to run phase works so I assume it's bash/zsh difference - clean install of Mac I'm sure more people will hit this
while working on creating a sample application, using the apollographl tutorial endpoint, https://apollo-fullstack-tutorial.herokuapp.com/
I am getting errors and warnings.
Showing Recent Issues
no rule to process file '/Users/stunjiturner/Downloads/CodeReviewRepos/OutOfThisWorld-Graphaello/ApolloFullstackTutorialHerokuappCom.graphql.json' of type 'text.json' for architecture 'x86_64'
Showing Recent Issues
/Users/stunjiturner/Downloads/CodeReviewRepos/OutOfThisWorld-Graphaello/Graphaello.swift:564:23: 'ApolloFullstackTutorialHerokuappCom' is ambiguous for type lookup in this context
The API I'm using has "repeat" as a field, which is a swift reserved keyword.
Graphaello.swift:
...
case repeat = "REPEAT" // ".../AL/Graphaello.swift:4222:18: Keyword 'repeat' cannot be used as an identifier here"
...
Theres will always be a swift compiler error on Buildtime using that API.
A fix would be to use backticks to escape the keyword.
On Apple Silicon brew installs to /opt/homebrew/bin/brew by default. This causes fetchInstalledVersion() to fail.
Since our generated code accesses Apollo API it is important that before we generate the code, we make sure that the correct version of Apollo is installed.
We could either:
I think that 1 would lead to less frustration, but 2 is more "correct" I guess?
Shouldn't the value for false
be this way?
RegexTokenGenerator(word: "false").map(to: .value(.bool(true))),
should be:
RegexTokenGenerator(word: "false").map(to: .value(.bool(false))),
???
Example CLI command.
graphaello add https://apollo-fullstack-tutorial.herokuapp.com/ creates a camel case of the URL, I would like to use the API Name argument for CLI, but the documentation is not clear, how to use
Resolved issue after realizing issue with assertions and non-optional types
Integrate with SwiftWeb
This depends on: Apodini/SwiftWeb#1
Apollo can only run the query with their types.
Despite the fact that our types are identical to theirs, we still need to convert.
Problematic areas:
We can't just run .init()
as in the case with enums right now, because the Apollo type is only generated when it's being used by a query. So we can't always ship the init code
Possible Ideas:
unsafeBitCast
would do the job ¯\_(ツ)_/¯Relevant areas:
@Binding var someBool: Bool
is generated as someBool: Bool
instead of someBool: Binding<Bool>>
It would be awesome to auto complete commands in shells that support it.
Resources:
https://iridakos.com/programming/2018/03/01/bash-programmable-completion-tutorial
The Generated Client API is remains largely undocumented...
It would also be awesome if we could include the documentation of the API in the Generated DSL
/Users/stunjiturner/Downloads/CodeReviewRepos/CRY/Graphaello.swift:895:14: Invalid redeclaration of 'Service'
static var Service: FragmentPath<Crystallize.Service> { .init() }
https://api.crystallize.com/sightuary/catalogue, public graphql endpoint
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.