Authentication-Results: mail-b.sr.ht; dkim=pass header.d=emersion.fr header.i=@emersion.fr Received: from mail-4323.proton.ch (mail-4323.proton.ch [185.70.43.23]) by mail-b.sr.ht (Postfix) with ESMTPS id 56E0411EF83 for <~emersion/hut-dev@lists.sr.ht>; Tue, 1 Feb 2022 10:05:46 +0000 (UTC) Date: Tue, 01 Feb 2022 10:05:43 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=emersion.fr; s=protonmail2; t=1643709944; bh=6gMCFqsM1hGIMdcdVo2jqWlxhqAdwY9PQto6NY2oxiQ=; h=Date:To:From:Cc:Reply-To:Subject:Message-ID:In-Reply-To: References:From:To:Cc; b=ESa6RMwZzNh7bV7UkbB3uLxmUY4Sbfu5olnXG2QDNnCdp04vGDyqD8RqhJMVn2uul TSoA2I93cWPGlI1AoKflzClYFlB6npgEDG/Q/QqlBgvDvkXGMGJq/L/UJDBGRvTsvk q06MaMvqo9hBeYUZS8oE03EJ6hF59Y0VZa/zWO02l/bBQ11XqoY+TptRAMYuckhaBU 2c4b5WZroJS5dYE+k0k6/X0z2aUwM5eEZfE6zfTaOk4mg8BC8ImTWtFA6l70aFPenc lk6BW1zi/QyjAnayuGfx7p00zZwnysW7AkDpoJbYCOhqeuceRJdGMLM4PxieVvgawg IQ8RBN4oQGjRw== To: Renato Torres From: Simon Ser Cc: ~emersion/hut-dev@lists.sr.ht Reply-To: Simon Ser Subject: Re: [PATCH v1 0/1] git: show license spike Message-ID: In-Reply-To: References: <20220122233022.1256016-1-renato.torres@protonmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-1.2 required=10.0 tests=ALL_TRUSTED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,T_SCC_BODY_TEXT_LINE shortcircuit=no autolearn=disabled version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on mailout.protonmail.ch On Sunday, January 23rd, 2022 at 19:29, Renato Torres wrote: > I was exploring your comments a bit further (and learned a lot about > GraphQL...). > > If I understood correctly we cannot use "raw" as a generic solution > because that's a specific field from the git.sr.ht GraphQL API. We should be able to accommodate for name collisions. If we had an unexport= ed "raw" field in the struct then it'll get ignored by encoding/json and an exported "Raw" field can co-exist. > I've hacked gqlclient to explore a solution for this. > > Consider the following schema ("stolen" from 99designs/gqlgen): > > ```graphql > interface Character { > # ... > } > type Human implements Character { > # ... > } > type Droid implements Character { > # ... > } > ``` > > Instead of generating: > > ```go > type Character struct { > // ... > } > type Human struct { > // ... > } > type Droid struct { > // ... > } > ``` > > We would generate: > > ```go > type Character interface{} Not a fan of this, because: - Character is an empty interface, so all types will satisfy it. - You can't do anything useful with just a Character, since it has no metho= ds? - gqlclient would need to always know the concrete type of the Character to make it so users can type-switch. But below it seems like methods are added to Character, so not sure how thi= s all ties together. > type CharacterFields struct { > // ... > } > type Human struct { > // ... > } > type Droid struct { > // ... > } > ``` > > And the following methods: > > ```go > func (i *Character) AsCharacterFields() *CharacterFields { > bytes, _ :=3D json.Marshal(i) > charFields =3D new(CharacterFields) > json.Unmarshal(bytes, &charFields) > return charFields > } > func (i *Character) AsHuman() *Human { > bytes, _ :=3D json.Marshal(i) > obj =3D new(Human) > json.Unmarshal(bytes, &obj) > return obj > } > > // Etc.... > ``` It's not possible to define methods on an interface type. And generating th= ese requires knowing about all possible Character implementations? > The operations remain unchanged: > > ```go > func Characters(client *gqlclient.Client, > ctx context.Context) (characters []Character, err error) { > > op :=3D gqlclient.NewOperation("query characters ... ") > var respData struct { > Characters []Character > } > err =3D client.Execute(ctx, op, &respData) > return respData.Characters, err > } > > ``` encoding/json is not able to unmarshal interface{} types. > I don't like very much the "Fields" suffix, eventually we would need > to find a better naming schema. > > Additionally this has the drawback of having to use "AsCharacterFields" > to access the fields declared in the GraphQL interface, something that > we don't need with the current approach. > > > It would seem like this is a promise we can make for simple > > cases, but not sure about federated GraphQL schemas and schemas split > > into multiple files. Would need to do more research. > > I think with this approach we wouldn't have problems with other cases, > because it does not require us to know about all implementations of a > GraphQL interface at generation time (but I haven't done a proper > research on this...). > > Example in cmd/gqlclientgen/main.go: > > ```go > // ... > func genDef(schema *ast.Schema, def *ast.Definition) *jen.Statement { > switch def.Kind { > // ... > case ast.Object: > var stmts []jen.Code > var fields []jen.Code > for _, field :=3D range def.Fields { > //... > } > for _, i :=3D range def.Interfaces { > interfaceName :=3D i > stmts =3D append(stmts, jen.Line()) > stmts =3D append(stmts, > jen.Func().Params(jen.Id("i").Op("*").Id(interfaceName)). > Id("As"+def.Name).Params().Params(jen.Op("*"). > Id(def.Name)).Block( > jen.Id("bytes, _").Op(":=3D"). > Qual("encoding/json", "Marshal").Call(jen.Id("i")), > jen.Id("obj").Op("=3D").New(jen.Id(def.Name)), > jen.Qual("encoding/json", > "Unmarshal").Call(jen.Id("bytes"), jen.Id("&obj")), > jen.Return(jen.Id("obj")))) > } > // ... > } > ``` > > What do you think? I can send a gqlclient patch if you want to take > a look at the code I used to generate this. I think I'm not fully understanding your proposal yet. Please enlighten me.= :)