or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdclient-sessions.mddsl.mdindex.mdtransports.mdutilities.md

dsl.mddocs/

0

# DSL Query Builder

1

2

Domain-specific language for programmatic GraphQL query construction without string templates. Provides type-safe query building with schema introspection, variable handling, fragment support, and automatic field name conversion.

3

4

## Capabilities

5

6

### Core DSL Functions

7

8

Primary functions for creating and converting DSL operations into executable GraphQL requests.

9

10

```python { .api }

11

def dsl_gql(*operations, **operations_with_name) -> GraphQLRequest:

12

"""

13

Convert DSL operations into executable GraphQL requests.

14

15

Args:

16

*operations: DSLExecutable instances (DSLQuery, DSLMutation, DSLSubscription, DSLFragment)

17

**operations_with_name: Same as above but with operation names as keys

18

19

Returns:

20

GraphQLRequest that can be executed by gql clients

21

22

Example:

23

dsl_gql(query) or dsl_gql(GetUser=query, CreateUser=mutation)

24

"""

25

```

26

27

### Schema Integration

28

29

Classes for integrating with GraphQL schemas to provide type-safe query building.

30

31

```python { .api }

32

class DSLSchema:

33

def __init__(self, schema: GraphQLSchema):

34

"""

35

Root class for DSL operations providing access to schema types.

36

37

Args:

38

schema: GraphQL schema object for type introspection

39

40

Usage:

41

ds = DSLSchema(client.schema)

42

ds.Query.user # Returns DSLType for User queries

43

ds.User.name # Returns DSLField for User.name field

44

"""

45

46

# Dynamic attributes: Any schema type name becomes a DSLType instance

47

48

class DSLType:

49

"""

50

Represents GraphQL object/interface types in DSL.

51

52

Accessed via DSLSchema attributes (ds.Query, ds.User, etc.)

53

Dynamic attributes: Field names become DSLField instances

54

Supports snake_case to camelCase conversion for field names

55

"""

56

57

# Dynamic attributes: Field names become DSLField instances

58

59

class DSLField:

60

"""

61

Represents GraphQL fields with arguments and sub-selections.

62

63

Accessed via DSLType attributes or method calls.

64

"""

65

66

def args(self, **kwargs) -> DSLField:

67

"""

68

Set field arguments.

69

70

Args:

71

**kwargs: Field arguments as keyword arguments

72

73

Returns:

74

DSLField with arguments set

75

76

Example:

77

ds.Query.user.args(id="123")

78

"""

79

80

def select(self, *fields, **fields_with_alias) -> DSLField:

81

"""

82

Select sub-fields for this field.

83

84

Args:

85

*fields: DSLField instances to select

86

**fields_with_alias: DSLField instances with custom aliases

87

88

Returns:

89

DSLField with sub-field selections

90

91

Example:

92

ds.Query.user.select(ds.User.name, ds.User.email)

93

ds.Query.user.select(user_name=ds.User.name)

94

"""

95

96

def alias(self, alias: str) -> DSLField:

97

"""

98

Set field alias.

99

100

Args:

101

alias: Custom alias for this field

102

103

Returns:

104

DSLField with alias set

105

106

Example:

107

ds.User.name.alias("userName")

108

"""

109

110

def __call__(self, **kwargs) -> DSLField:

111

"""

112

Shorthand for args() method.

113

114

Args:

115

**kwargs: Field arguments

116

117

Returns:

118

DSLField with arguments set

119

120

Example:

121

ds.Query.user(id="123") # Same as ds.Query.user.args(id="123")

122

"""

123

124

class DSLMetaField:

125

def __init__(self, name: str):

126

"""

127

Represents GraphQL meta-fields.

128

129

Args:

130

name: Meta-field name ("__typename", "__schema", "__type")

131

132

Example:

133

DSLMetaField("__typename")

134

"""

135

```

136

137

### Operation Classes

138

139

Classes for building different types of GraphQL operations.

140

141

```python { .api }

142

class DSLQuery:

143

def __init__(self, *fields, **fields_with_alias):

144

"""

145

Represents GraphQL Query operations.

146

147

Args:

148

*fields: DSLField instances to include in query

149

**fields_with_alias: DSLField instances with custom aliases

150

151

Example:

152

DSLQuery(ds.Query.user.select(ds.User.name, ds.User.email))

153

"""

154

155

class DSLMutation:

156

def __init__(self, *fields, **fields_with_alias):

157

"""

158

Represents GraphQL Mutation operations.

159

160

Args:

161

*fields: DSLField instances to include in mutation

162

**fields_with_alias: DSLField instances with custom aliases

163

164

Example:

165

DSLMutation(ds.Mutation.createUser.args(input=user_input).select(ds.User.id))

166

"""

167

168

class DSLSubscription:

169

def __init__(self, *fields, **fields_with_alias):

170

"""

171

Represents GraphQL Subscription operations.

172

173

Args:

174

*fields: DSLField instances to include in subscription

175

**fields_with_alias: DSLField instances with custom aliases

176

177

Example:

178

DSLSubscription(ds.Subscription.messageAdded.select(ds.Message.content))

179

"""

180

```

181

182

### Fragment Support

183

184

Classes for creating reusable GraphQL fragments.

185

186

```python { .api }

187

class DSLFragment:

188

def __init__(self, name: str):

189

"""

190

Represents named GraphQL fragments.

191

192

Args:

193

name: Fragment name

194

195

Example:

196

user_info = DSLFragment("UserInfo")

197

"""

198

199

def on(self, type_condition: DSLType) -> DSLFragment:

200

"""

201

Set fragment type condition.

202

203

Args:

204

type_condition: DSLType representing the fragment type

205

206

Returns:

207

DSLFragment with type condition set

208

209

Example:

210

user_info.on(ds.User)

211

"""

212

213

def select(self, *fields, **fields_with_alias) -> DSLFragment:

214

"""

215

Select fields for this fragment.

216

217

Args:

218

*fields: DSLField instances to include

219

**fields_with_alias: DSLField instances with aliases

220

221

Returns:

222

DSLFragment with field selections

223

224

Example:

225

user_info.select(ds.User.name, ds.User.email)

226

"""

227

228

class DSLInlineFragment:

229

def __init__(self, *fields, **fields_with_alias):

230

"""

231

Represents inline GraphQL fragments.

232

233

Args:

234

*fields: DSLField instances to include

235

**fields_with_alias: DSLField instances with aliases

236

237

Example:

238

DSLInlineFragment(ds.User.name).on(ds.User)

239

"""

240

241

def on(self, type_condition: DSLType) -> DSLInlineFragment:

242

"""

243

Set type condition for inline fragment.

244

245

Args:

246

type_condition: DSLType for fragment condition

247

248

Returns:

249

DSLInlineFragment with type condition

250

251

Example:

252

DSLInlineFragment(ds.User.name).on(ds.User)

253

"""

254

255

def select(self, *fields, **fields_with_alias) -> DSLInlineFragment:

256

"""

257

Select additional fields for inline fragment.

258

259

Args:

260

*fields: DSLField instances to add

261

**fields_with_alias: DSLField instances with aliases

262

263

Returns:

264

DSLInlineFragment with additional selections

265

"""

266

```

267

268

### Variable System

269

270

Classes for handling GraphQL variables in DSL operations.

271

272

```python { .api }

273

class DSLVariableDefinitions:

274

def __init__(self):

275

"""

276

Container for operation variables.

277

278

Dynamic attributes: Variable names become DSLVariable instances

279

280

Example:

281

vars = DSLVariableDefinitions()

282

vars.user_id # Returns DSLVariable("user_id")

283

"""

284

285

# Dynamic attributes: Variable names become DSLVariable instances

286

287

class DSLVariable:

288

"""

289

Represents GraphQL variables in operations.

290

291

Accessed via DSLVariableDefinitions attributes.

292

"""

293

294

def set_type(self, type_: GraphQLInputType) -> DSLVariable:

295

"""

296

Set variable type.

297

298

Args:

299

type_: GraphQL input type for this variable

300

301

Returns:

302

DSLVariable with type set

303

304

Example:

305

vars.user_id.set_type(GraphQLNonNull(GraphQLID))

306

"""

307

308

def default(self, default_value: Any) -> DSLVariable:

309

"""

310

Set default value for variable.

311

312

Args:

313

default_value: Default value if not provided

314

315

Returns:

316

DSLVariable with default value set

317

318

Example:

319

vars.limit.default(10)

320

"""

321

```

322

323

## Usage Examples

324

325

### Basic DSL Query Building

326

327

```python

328

from gql import Client

329

from gql.dsl import DSLSchema, DSLQuery, dsl_gql

330

from gql.transport.requests import RequestsHTTPTransport

331

332

# Setup client and DSL schema

333

transport = RequestsHTTPTransport(url="https://api.example.com/graphql")

334

client = Client(transport=transport, fetch_schema_from_transport=True)

335

336

# Create DSL schema from client schema

337

ds = DSLSchema(client.schema)

338

339

# Build query using DSL

340

query = DSLQuery(

341

ds.Query.user(id="123").select(

342

ds.User.name,

343

ds.User.email,

344

ds.User.posts.select(

345

ds.Post.title,

346

ds.Post.content,

347

ds.Post.publishedAt

348

)

349

)

350

)

351

352

# Convert to executable request and execute

353

request = dsl_gql(query)

354

result = client.execute(request)

355

356

print(result["user"]["name"])

357

```

358

359

### Field Arguments and Aliases

360

361

```python

362

from gql.dsl import DSLSchema, DSLQuery, dsl_gql

363

364

# Build query with arguments and aliases

365

query = DSLQuery(

366

# Field with arguments

367

ds.Query.users(

368

limit=10,

369

offset=0,

370

orderBy="CREATED_AT"

371

).select(

372

ds.User.id,

373

ds.User.name,

374

# Field with alias

375

user_email=ds.User.email,

376

# Nested field with arguments

377

ds.User.posts(published=True).select(

378

ds.Post.title,

379

published_date=ds.Post.publishedAt

380

)

381

)

382

)

383

384

request = dsl_gql(query)

385

result = client.execute(request)

386

387

# Access aliased fields

388

for user in result["users"]:

389

print(f"{user['name']} - {user['user_email']}")

390

```

391

392

### Variables and Dynamic Queries

393

394

```python

395

from gql.dsl import DSLSchema, DSLQuery, DSLVariableDefinitions, dsl_gql

396

397

# Setup variables

398

vars = DSLVariableDefinitions()

399

400

# Build query with variables

401

query = DSLQuery(

402

ds.Query.user(id=vars.user_id).select(

403

ds.User.name,

404

ds.User.email,

405

ds.User.posts(limit=vars.post_limit).select(

406

ds.Post.title,

407

ds.Post.content

408

)

409

)

410

)

411

412

# Execute with different variable values

413

request = dsl_gql(query)

414

415

result1 = client.execute(request, variable_values={

416

"user_id": "123",

417

"post_limit": 5

418

})

419

420

result2 = client.execute(request, variable_values={

421

"user_id": "456",

422

"post_limit": 10

423

})

424

```

425

426

### Fragment Usage

427

428

```python

429

from gql.dsl import DSLSchema, DSLQuery, DSLFragment, dsl_gql

430

431

# Define reusable fragment

432

user_info = DSLFragment("UserInfo").on(ds.User).select(

433

ds.User.id,

434

ds.User.name,

435

ds.User.email,

436

ds.User.createdAt

437

)

438

439

# Use fragment in multiple places

440

query = DSLQuery(

441

# Use fragment in different contexts

442

current_user=ds.Query.currentUser.select(user_info),

443

user_by_id=ds.Query.user(id="123").select(user_info),

444

445

# Use fragment in nested selections

446

ds.Query.posts.select(

447

ds.Post.title,

448

ds.Post.author.select(user_info)

449

)

450

)

451

452

# Include fragment in request

453

request = dsl_gql(query, user_info)

454

result = client.execute(request)

455

```

456

457

### Inline Fragments for Union Types

458

459

```python

460

from gql.dsl import DSLSchema, DSLQuery, DSLInlineFragment, dsl_gql

461

462

# Handle union types with inline fragments

463

query = DSLQuery(

464

ds.Query.search(query="python").select(

465

# Common fields available on all union members

466

ds.SearchResult.id,

467

468

# Type-specific fields using inline fragments

469

DSLInlineFragment().on(ds.User).select(

470

ds.User.name,

471

ds.User.email

472

),

473

474

DSLInlineFragment().on(ds.Post).select(

475

ds.Post.title,

476

ds.Post.content

477

),

478

479

DSLInlineFragment().on(ds.Repository).select(

480

ds.Repository.name,

481

ds.Repository.description,

482

ds.Repository.starCount

483

)

484

)

485

)

486

487

request = dsl_gql(query)

488

result = client.execute(request)

489

490

# Results will include type-specific fields based on actual types

491

for item in result["search"]:

492

if "name" in item and "email" in item:

493

print(f"User: {item['name']} ({item['email']})")

494

elif "title" in item:

495

print(f"Post: {item['title']}")

496

elif "starCount" in item:

497

print(f"Repository: {item['name']} ({item['starCount']} stars)")

498

```

499

500

### Mutations with Input Objects

501

502

```python

503

from gql.dsl import DSLSchema, DSLMutation, dsl_gql

504

505

# Build mutation with input object

506

user_input = {

507

"name": "John Doe",

508

"email": "john@example.com",

509

"age": 30

510

}

511

512

mutation = DSLMutation(

513

ds.Mutation.createUser(input=user_input).select(

514

ds.User.id,

515

ds.User.name,

516

ds.User.email,

517

ds.User.createdAt

518

)

519

)

520

521

request = dsl_gql(mutation)

522

result = client.execute(request)

523

524

created_user = result["createUser"]

525

print(f"Created user {created_user['name']} with ID {created_user['id']}")

526

```

527

528

### Subscriptions with DSL

529

530

```python

531

import asyncio

532

from gql.dsl import DSLSchema, DSLSubscription, dsl_gql

533

534

async def handle_subscription():

535

# Build subscription

536

subscription = DSLSubscription(

537

ds.Subscription.messageAdded(channelId="general").select(

538

ds.Message.id,

539

ds.Message.content,

540

ds.Message.user.select(

541

ds.User.name,

542

ds.User.avatar

543

),

544

ds.Message.timestamp

545

)

546

)

547

548

request = dsl_gql(subscription)

549

550

async with client.connect_async() as session:

551

async for result in session.subscribe(request):

552

message = result["messageAdded"]

553

user = message["user"]

554

print(f"[{message['timestamp']}] {user['name']}: {message['content']}")

555

556

asyncio.run(handle_subscription())

557

```

558

559

### Meta-fields and Introspection

560

561

```python

562

from gql.dsl import DSLSchema, DSLQuery, DSLMetaField, dsl_gql

563

564

# Query with typename meta-field

565

query = DSLQuery(

566

ds.Query.search(query="graphql").select(

567

DSLMetaField("__typename"), # Include __typename for each result

568

ds.SearchResult.id,

569

570

# Conditional selection based on type

571

DSLInlineFragment().on(ds.User).select(

572

ds.User.name

573

),

574

575

DSLInlineFragment().on(ds.Post).select(

576

ds.Post.title

577

)

578

)

579

)

580

581

request = dsl_gql(query)

582

result = client.execute(request)

583

584

# Use __typename to handle different types

585

for item in result["search"]:

586

if item["__typename"] == "User":

587

print(f"User: {item['name']}")

588

elif item["__typename"] == "Post":

589

print(f"Post: {item['title']}")

590

```

591

592

### Complex Nested Queries

593

594

```python

595

from gql.dsl import DSLSchema, DSLQuery, DSLFragment, dsl_gql

596

597

# Define fragments for reusability

598

post_summary = DSLFragment("PostSummary").on(ds.Post).select(

599

ds.Post.id,

600

ds.Post.title,

601

ds.Post.publishedAt,

602

ds.Post.commentCount,

603

ds.Post.likeCount

604

)

605

606

user_profile = DSLFragment("UserProfile").on(ds.User).select(

607

ds.User.id,

608

ds.User.name,

609

ds.User.email,

610

ds.User.bio,

611

ds.User.followersCount,

612

ds.User.followingCount

613

)

614

615

# Build complex nested query

616

query = DSLQuery(

617

# Current user with profile info

618

ds.Query.currentUser.select(

619

user_profile,

620

621

# Recent posts with summary

622

ds.User.posts(limit=5, orderBy="PUBLISHED_AT_DESC").select(

623

post_summary,

624

625

# Comments on each post

626

ds.Post.comments(limit=3).select(

627

ds.Comment.id,

628

ds.Comment.content,

629

ds.Comment.author.select(user_profile)

630

)

631

),

632

633

# Following users

634

ds.User.following(limit=10).select(user_profile)

635

)

636

)

637

638

request = dsl_gql(query, post_summary, user_profile)

639

result = client.execute(request)

640

641

# Access nested data

642

current_user = result["currentUser"]

643

print(f"User: {current_user['name']}")

644

print(f"Recent posts: {len(current_user['posts'])}")

645

646

for post in current_user["posts"]:

647

print(f" - {post['title']} ({post['commentCount']} comments)")

648

for comment in post["comments"]:

649

print(f" * {comment['author']['name']}: {comment['content']}")

650

```

651

652

### Snake Case to Camel Case Conversion

653

654

```python

655

from gql.dsl import DSLSchema, DSLQuery, dsl_gql

656

657

# DSL automatically converts snake_case to camelCase

658

query = DSLQuery(

659

ds.Query.current_user.select( # Becomes currentUser

660

ds.User.first_name, # Becomes firstName

661

ds.User.last_name, # Becomes lastName

662

ds.User.created_at, # Becomes createdAt

663

ds.User.updated_at # Becomes updatedAt

664

)

665

)

666

667

# Generated GraphQL uses camelCase field names

668

request = dsl_gql(query)

669

print(request.payload["query"])

670

# Output includes: currentUser { firstName lastName createdAt updatedAt }

671

672

result = client.execute(request)

673

user = result["currentUser"]

674

print(f"{user['firstName']} {user['lastName']}")

675

```