11import vscode , { Disposable , TelemetryLogger } from "vscode" ;
22import {
33 DocumentNode ,
4- GraphQLInputObjectType ,
5- GraphQLScalarType ,
4+ GraphQLInputField ,
65 Kind ,
6+ ObjectFieldNode ,
77 ObjectTypeDefinitionNode ,
8+ OperationDefinitionNode ,
9+ OperationTypeNode ,
10+ ValueNode ,
811 buildClientSchema ,
9- buildSchema ,
12+ getNamedType ,
13+ isInputObjectType ,
14+ print ,
1015} from "graphql" ;
1116import { checkIfFileExists , upsertFile } from "./file-utils" ;
1217import { DataConnectService } from "./service" ;
@@ -135,9 +140,18 @@ query {
135140 // generate content for the file
136141 const preamble =
137142 "# This is a file for you to write an un-named mutation. \n# Only one un-named mutation is allowed per file." ;
138- const adhocMutation = await generateMutation ( ast ) ;
139- const content = [ preamble , adhocMutation ] . join ( "\n" ) ;
143+ const introspect = ( await dataConnectService . introspect ( ) ) ?. data ;
144+ const schema = buildClientSchema ( introspect ! ) ;
145+ const dataType = schema . getType ( `${ ast . name . value } _Data` ) ;
146+ if ( ! isInputObjectType ( dataType ) ) return ;
140147
148+ const adhocMutation = print (
149+ await makeAdHocMutation (
150+ Object . values ( dataType . getFields ( ) ) ,
151+ ast . name . value ,
152+ ) ,
153+ ) ;
154+ const content = [ preamble , adhocMutation ] . join ( "\n" ) ;
141155 const basePath = vscode . workspace . rootPath + "/dataconnect/" ;
142156 const filePath = vscode . Uri . file ( `${ basePath } ${ ast . name . value } _insert.gql` ) ;
143157 const doesFileExist = await checkIfFileExists ( filePath ) ;
@@ -162,46 +176,78 @@ query {
162176 }
163177 }
164178
165- async function generateMutation (
166- ast : ObjectTypeDefinitionNode ,
167- ) : Promise < string > {
168- const introspect = ( await dataConnectService . introspect ( ) ) ?. data ;
169- const schema = buildClientSchema ( introspect ! ) ;
179+ function makeAdHocMutation (
180+ fields : GraphQLInputField [ ] ,
181+ singularName : string ,
182+ ) : OperationDefinitionNode {
183+ const argumentFields : ObjectFieldNode [ ] = [ ] ;
170184
171- const name = ast . name . value ;
172- const lowerCaseName =
173- ast . name . value . charAt ( 0 ) . toLowerCase ( ) + ast . name . value . slice ( 1 ) ;
174- const dataName = `${ name } _Data` ;
175- const mutationDataType : GraphQLInputObjectType = schema . getTypeMap ( ) [
176- dataName
177- ] as GraphQLInputObjectType ;
178-
179- // build mutation as string
180- const functionSpacing = "\t" ;
181- const fieldSpacing = "\t\t" ;
182- const mutation = [ ] ;
183- mutation . push ( "mutation {" ) ; // mutation header
184- mutation . push ( `${ functionSpacing } ${ lowerCaseName } _insert(data: {` ) ;
185- for ( const [ fieldName , field ] of Object . entries (
186- mutationDataType . getFields ( ) ,
187- ) ) {
188- // necessary to avoid type error
189- const fieldtype : any = field . type ;
190- // use all argument types that are of scalar, except x_expr
191- if (
192- isDataConnectScalarType ( fieldtype . name ) &&
193- ! field . name . includes ( "_expr" )
194- ) {
195- const defaultValue = ( defaultScalarValues as any ) [ fieldtype . name ] || "" ;
196- mutation . push (
197- `${ fieldSpacing } ${ fieldName } : ${ defaultValue } # ${ fieldtype . name } ` ,
198- ) ; // field name + temp value + comment
199- }
185+ for ( const field of fields ) {
186+ const type = getNamedType ( field . type ) ;
187+ const defaultValue = getDefaultScalarValue ( type . name ) ;
188+ if ( ! defaultValue ) continue ;
189+
190+ argumentFields . push ( {
191+ kind : Kind . OBJECT_FIELD ,
192+ name : { kind : Kind . NAME , value : field . name } ,
193+ value : defaultValue ,
194+ } ) ;
200195 }
201- mutation . push ( `${ functionSpacing } })` , "}" ) ; // closing braces/paren
202- return mutation . join ( "\n" ) ;
196+
197+ return {
198+ kind : Kind . OPERATION_DEFINITION ,
199+ operation : OperationTypeNode . MUTATION ,
200+ selectionSet : {
201+ kind : Kind . SELECTION_SET ,
202+ selections : [
203+ {
204+ kind : Kind . FIELD ,
205+ name : { kind : Kind . NAME , value : `${ singularName . charAt ( 0 ) . toLowerCase ( ) } ${ singularName . slice ( 1 ) } _insert` } ,
206+ arguments : [
207+ {
208+ kind : Kind . ARGUMENT ,
209+ name : { kind : Kind . NAME , value : "data" } ,
210+ value : {
211+ kind : Kind . OBJECT ,
212+ fields : argumentFields ,
213+ } ,
214+ } ,
215+ ] ,
216+ } ,
217+ ] ,
218+ } ,
219+ } ;
203220 }
204221
222+ function getDefaultScalarValue ( type : string ) : ValueNode | undefined {
223+ switch ( type ) {
224+ case "Any" :
225+ return { kind : Kind . OBJECT , fields : [ ] } ;
226+ case "Boolean" :
227+ return { kind : Kind . BOOLEAN , value : false } ;
228+ case "Date" :
229+ return {
230+ kind : Kind . STRING ,
231+ value : new Date ( ) . toISOString ( ) . substring ( 0 , 10 ) ,
232+ } ;
233+ case "Float" :
234+ return { kind : Kind . FLOAT , value : "0" } ;
235+ case "Int" :
236+ return { kind : Kind . INT , value : "0" } ;
237+ case "Int64" :
238+ return { kind : Kind . INT , value : "0" } ;
239+ case "String" :
240+ return { kind : Kind . STRING , value : "" } ;
241+ case "Timestamp" :
242+ return { kind : Kind . STRING , value : new Date ( ) . toISOString ( ) } ;
243+ case "UUID" :
244+ return { kind : Kind . STRING , value : "11111111222233334444555555555555" } ;
245+ case "Vector" :
246+ return { kind : Kind . LIST , values : [ ] } ;
247+ default :
248+ return undefined ;
249+ }
250+ }
205251 return Disposable . from (
206252 vscode . commands . registerCommand (
207253 "firebase.dataConnect.schemaAddData" ,
0 commit comments