or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

active-record.mdcondition-builders.mdindex.mdkotlin-extensions.mdpagination.mdplugin-system.mdservice-layer.mdstatic-utilities.md

kotlin-extensions.mddocs/

0

# Kotlin Extensions

1

2

MyBatis-Plus Extension provides comprehensive Kotlin support through specialized wrapper classes that leverage Kotlin's language features for type-safe database operations. These extensions offer property-based query building using Kotlin's reflection capabilities and provide a more idiomatic Kotlin development experience.

3

4

## Core Components

5

6

### KtQueryWrapper

7

8

Type-safe query wrapper for Kotlin with property-based field references.

9

10

```kotlin { .api }

11

class KtQueryWrapper<T>(entity: T? = null) : AbstractKtWrapper<T, KtQueryWrapper<T>>() {

12

constructor(entityClass: Class<T>) : this(null)

13

14

// Select operations

15

fun select(vararg columns: KProperty<*>): KtQueryWrapper<T>

16

fun getSqlSelect(): String

17

18

// Factory methods

19

fun instance(): KtQueryWrapper<T>

20

fun clear(): KtQueryWrapper<T>

21

22

// Inherited condition methods from AbstractKtWrapper

23

// eq, ne, gt, ge, lt, le, like, notLike, in, notIn, etc.

24

}

25

```

26

27

### KtUpdateWrapper

28

29

Type-safe update wrapper for Kotlin operations.

30

31

```kotlin { .api }

32

class KtUpdateWrapper<T>(entity: T? = null) : AbstractKtWrapper<T, KtUpdateWrapper<T>>() {

33

constructor(entityClass: Class<T>) : this(null)

34

35

// Set operations using Kotlin properties

36

fun set(column: KProperty<*>, value: Any?): KtUpdateWrapper<T>

37

fun setSql(sql: String): KtUpdateWrapper<T>

38

39

// Factory methods

40

fun instance(): KtUpdateWrapper<T>

41

fun clear(): KtUpdateWrapper<T>

42

}

43

```

44

45

### KtQueryChainWrapper

46

47

Kotlin chain wrapper for fluent query operations.

48

49

```kotlin { .api }

50

class KtQueryChainWrapper<T> : AbstractChainWrapper<T, KProperty<*>, KtQueryChainWrapper<T>, KtQueryWrapper<T>>(),

51

ChainQuery<T> {

52

53

constructor(baseMapper: BaseMapper<T>)

54

constructor(entityClass: Class<T>)

55

56

// Terminal operations

57

override fun list(): List<T>

58

override fun one(): T

59

override fun oneOpt(): Optional<T>

60

override fun count(): Long

61

override fun exists(): Boolean

62

override fun <E : IPage<T>> page(page: E): E

63

64

// Select operations

65

fun select(vararg columns: KProperty<*>): KtQueryChainWrapper<T>

66

}

67

```

68

69

### KtUpdateChainWrapper

70

71

Kotlin chain wrapper for fluent update operations.

72

73

```kotlin { .api }

74

class KtUpdateChainWrapper<T> : AbstractChainWrapper<T, KProperty<*>, KtUpdateChainWrapper<T>, KtUpdateWrapper<T>>(),

75

ChainUpdate<T> {

76

77

constructor(baseMapper: BaseMapper<T>)

78

constructor(entityClass: Class<T>)

79

80

// Terminal operations

81

override fun update(): Boolean

82

override fun update(entity: T): Boolean

83

override fun remove(): Boolean

84

85

// Set operations

86

fun set(column: KProperty<*>, value: Any?): KtUpdateChainWrapper<T>

87

fun setSql(sql: String): KtUpdateChainWrapper<T>

88

}

89

```

90

91

### AbstractKtWrapper

92

93

Base class for Kotlin wrappers providing type-safe condition methods.

94

95

```kotlin { .api }

96

abstract class AbstractKtWrapper<T, Children : AbstractKtWrapper<T, Children>> {

97

98

// Comparison conditions

99

fun eq(column: KProperty<*>, value: Any?): Children

100

fun ne(column: KProperty<*>, value: Any?): Children

101

fun gt(column: KProperty<*>, value: Any?): Children

102

fun ge(column: KProperty<*>, value: Any?): Children

103

fun lt(column: KProperty<*>, value: Any?): Children

104

fun le(column: KProperty<*>, value: Any?): Children

105

106

// String conditions

107

fun like(column: KProperty<*>, value: Any?): Children

108

fun notLike(column: KProperty<*>, value: Any?): Children

109

fun likeLeft(column: KProperty<*>, value: Any?): Children

110

fun likeRight(column: KProperty<*>, value: Any?): Children

111

112

// Null conditions

113

fun isNull(column: KProperty<*>): Children

114

fun isNotNull(column: KProperty<*>): Children

115

116

// Collection conditions

117

fun `in`(column: KProperty<*>, values: Collection<*>): Children

118

fun notIn(column: KProperty<*>, values: Collection<*>): Children

119

fun `in`(column: KProperty<*>, vararg values: Any?): Children

120

fun notIn(column: KProperty<*>, vararg values: Any?): Children

121

122

// Range conditions

123

fun between(column: KProperty<*>, val1: Any?, val2: Any?): Children

124

fun notBetween(column: KProperty<*>, val1: Any?, val2: Any?): Children

125

126

// Logical operators

127

fun and(): Children

128

fun or(): Children

129

fun and(consumer: (Children) -> Unit): Children

130

fun or(consumer: (Children) -> Unit): Children

131

132

// Ordering (for query wrappers)

133

fun orderByAsc(column: KProperty<*>): Children

134

fun orderByDesc(column: KProperty<*>): Children

135

fun orderByAsc(vararg columns: KProperty<*>): Children

136

fun orderByDesc(vararg columns: KProperty<*>): Children

137

138

// Grouping and Having

139

fun groupBy(column: KProperty<*>): Children

140

fun groupBy(vararg columns: KProperty<*>): Children

141

fun having(sqlHaving: String, vararg params: Any?): Children

142

143

// Utility methods

144

abstract fun instance(): Children

145

abstract fun clear(): Children

146

}

147

```

148

149

## Usage Examples

150

151

### Entity Definition

152

153

```kotlin

154

@TableName("user")

155

data class User(

156

@TableId(type = IdType.AUTO)

157

var id: Long? = null,

158

159

var name: String? = null,

160

var email: String? = null,

161

var age: Int? = null,

162

var active: Boolean? = null,

163

var department: String? = null,

164

var salary: BigDecimal? = null,

165

var createdTime: LocalDateTime? = null,

166

var updatedTime: LocalDateTime? = null

167

) : Model<User>() {

168

169

override fun pkVal(): Serializable? = id

170

}

171

```

172

173

### Basic Query Operations

174

175

```kotlin

176

// Using KtQueryWrapper directly

177

val wrapper = KtQueryWrapper<User>()

178

.eq(User::active, true)

179

.gt(User::age, 18)

180

.like(User::name, "John")

181

.orderByDesc(User::createdTime)

182

183

val users = userService.list(wrapper)

184

185

// Using entity instance for initialization

186

val user = User()

187

val wrapper2 = KtQueryWrapper(user)

188

.ne(User::id, user.id)

189

.eq(User::department, "IT")

190

191

// Type-safe property references

192

val activeUsers = userService.list(

193

KtQueryWrapper<User>()

194

.eq(User::active, true)

195

.isNotNull(User::email)

196

.orderByAsc(User::name)

197

)

198

```

199

200

### Service Integration

201

202

```kotlin

203

@Service

204

class UserService : ServiceImpl<UserMapper, User>() {

205

206

// Kotlin-specific query methods

207

fun findActiveUsersByDepartment(department: String): List<User> {

208

return this.ktQuery()

209

.eq(User::active, true)

210

.eq(User::department, department)

211

.orderByAsc(User::name)

212

.list()

213

}

214

215

fun findUsersByAgeRange(minAge: Int, maxAge: Int): List<User> {

216

return this.list(

217

KtQueryWrapper<User>()

218

.between(User::age, minAge, maxAge)

219

.eq(User::active, true)

220

)

221

}

222

223

fun updateUserSalary(userId: Long, newSalary: BigDecimal): Boolean {

224

return this.ktUpdate()

225

.set(User::salary, newSalary)

226

.set(User::updatedTime, LocalDateTime.now())

227

.eq(User::id, userId)

228

.update()

229

}

230

231

fun deactivateInactiveUsers(days: Int): Boolean {

232

val cutoffDate = LocalDateTime.now().minusDays(days.toLong())

233

return this.ktUpdate()

234

.set(User::active, false)

235

.set(User::updatedTime, LocalDateTime.now())

236

.lt(User::createdTime, cutoffDate)

237

.update()

238

}

239

}

240

```

241

242

### Chain Operations

243

244

```kotlin

245

// Query chains with Kotlin extensions

246

val activeUsers = userService.ktQuery()

247

.eq(User::active, true)

248

.ge(User::age, 21)

249

.isNotNull(User::email)

250

.orderByDesc(User::createdTime)

251

.list()

252

253

// Single result query

254

val user = userService.ktQuery()

255

.eq(User::email, "john@example.com")

256

.eq(User::active, true)

257

.one()

258

259

// Optional result

260

val optionalUser = userService.ktQuery()

261

.eq(User::name, "John Doe")

262

.oneOpt()

263

264

if (optionalUser.isPresent) {

265

val user = optionalUser.get()

266

println("Found user: ${user.name}")

267

}

268

269

// Count operations

270

val activeCount = userService.ktQuery()

271

.eq(User::active, true)

272

.count()

273

274

// Existence check

275

val hasAdmins = userService.ktQuery()

276

.eq(User::department, "ADMIN")

277

.eq(User::active, true)

278

.exists()

279

```

280

281

### Update Operations

282

283

```kotlin

284

// Update with conditions

285

val updated = userService.ktUpdate()

286

.set(User::department, "Engineering")

287

.set(User::updatedTime, LocalDateTime.now())

288

.eq(User::department, "IT")

289

.update()

290

291

// Complex update conditions

292

val updated = userService.ktUpdate()

293

.set(User::active, false)

294

.set(User::updatedTime, LocalDateTime.now())

295

.and { wrapper ->

296

wrapper.lt(User::age, 18)

297

.or()

298

.gt(User::age, 65)

299

}

300

.update()

301

302

// Remove operations

303

val removed = userService.ktUpdate()

304

.eq(User::active, false)

305

.isNull(User::email)

306

.remove()

307

```

308

309

### Complex Conditions

310

311

```kotlin

312

// Nested conditions with lambdas

313

val users = userService.ktQuery()

314

.eq(User::active, true)

315

.and { wrapper ->

316

wrapper.eq(User::department, "IT")

317

.or()

318

.eq(User::department, "Engineering")

319

}

320

.or { wrapper ->

321

wrapper.ge(User::salary, BigDecimal("100000"))

322

.eq(User::active, true)

323

}

324

.orderByDesc(User::salary)

325

.list()

326

327

// Range and collection conditions

328

val users = userService.list(

329

KtQueryWrapper<User>()

330

.`in`(User::department, listOf("IT", "HR", "Finance"))

331

.between(User::age, 25, 45)

332

.notIn(User::id, listOf(1L, 2L, 3L))

333

.isNotNull(User::email)

334

)

335

336

// String matching conditions

337

val users = userService.list(

338

KtQueryWrapper<User>()

339

.like(User::name, "John")

340

.likeRight(User::email, "@company.com")

341

.notLike(User::department, "temp")

342

)

343

```

344

345

### Select Specific Fields

346

347

```kotlin

348

// Select specific columns using property references

349

val wrapper = KtQueryWrapper<User>()

350

.select(User::id, User::name, User::email)

351

.eq(User::active, true)

352

.orderByAsc(User::name)

353

354

val users = userService.list(wrapper)

355

356

// Chain wrapper with select

357

val users = userService.ktQuery()

358

.select(User::name, User::department, User::salary)

359

.eq(User::active, true)

360

.gt(User::salary, BigDecimal("50000"))

361

.list()

362

```

363

364

### Pagination with Kotlin

365

366

```kotlin

367

// Paginated query with Kotlin wrapper

368

val page = Page<User>(1, 10)

369

val result = userService.ktQuery()

370

.eq(User::active, true)

371

.ge(User::age, 18)

372

.orderByDesc(User::createdTime)

373

.page(page)

374

375

val users = result.records

376

val total = result.total

377

378

// Pagination with complex conditions

379

val searchPage = userService.page(

380

Page<User>(1, 20),

381

KtQueryWrapper<User>()

382

.and { wrapper ->

383

wrapper.like(User::name, "John")

384

.or()

385

.like(User::email, "john")

386

}

387

.eq(User::active, true)

388

.orderByDesc(User::updatedTime)

389

)

390

```

391

392

### Static Utility Usage

393

394

```kotlin

395

// Using Db utility with Kotlin wrappers

396

val users = Db.ktQuery(User::class.java)

397

.eq(User::active, true)

398

.list()

399

400

val updated = Db.ktUpdate(User::class.java)

401

.set(User::updatedTime, LocalDateTime.now())

402

.eq(User::id, 1L)

403

.update()

404

405

// ChainWrappers with Kotlin

406

val users = ChainWrappers.ktQueryChain(User::class.java)

407

.eq(User::department, "Engineering")

408

.orderByAsc(User::name)

409

.list()

410

411

val updated = ChainWrappers.ktUpdateChain(userMapper)

412

.set(User::active, false)

413

.lt(User::createdTime, LocalDateTime.now().minusYears(1))

414

.update()

415

```

416

417

### Advanced Kotlin Features

418

419

```kotlin

420

// Extension functions for User entity

421

fun User.isAdult(): Boolean = this.age?.let { it >= 18 } ?: false

422

423

fun User.updateActivity(active: Boolean): Boolean {

424

return Db.ktUpdate(User::class.java)

425

.set(User::active, active)

426

.set(User::updatedTime, LocalDateTime.now())

427

.eq(User::id, this.id)

428

.update()

429

}

430

431

fun User.findSimilarUsers(): List<User> {

432

return Db.ktQuery(User::class.java)

433

.eq(User::department, this.department)

434

.eq(User::active, true)

435

.ne(User::id, this.id)

436

.list()

437

}

438

439

// Usage of extension functions

440

val user = userService.getById(1L)

441

if (user.isAdult()) {

442

user.updateActivity(true)

443

val similarUsers = user.findSimilarUsers()

444

}

445

```

446

447

### Data Class Integration

448

449

```kotlin

450

// Leveraging data class features

451

data class UserSearchCriteria(

452

val name: String? = null,

453

val department: String? = null,

454

val minAge: Int? = null,

455

val maxAge: Int? = null,

456

val active: Boolean? = null

457

)

458

459

class UserService : ServiceImpl<UserMapper, User>() {

460

461

fun searchUsers(criteria: UserSearchCriteria): List<User> {

462

val wrapper = KtQueryWrapper<User>()

463

464

criteria.name?.let { wrapper.like(User::name, it) }

465

criteria.department?.let { wrapper.eq(User::department, it) }

466

criteria.minAge?.let { wrapper.ge(User::age, it) }

467

criteria.maxAge?.let { wrapper.le(User::age, it) }

468

criteria.active?.let { wrapper.eq(User::active, it) }

469

470

return this.list(wrapper.orderByDesc(User::createdTime))

471

}

472

473

fun updateUserFields(id: Long, updates: UserUpdateData): Boolean {

474

val wrapper = KtUpdateWrapper<User>()

475

476

updates.name?.let { wrapper.set(User::name, it) }

477

updates.email?.let { wrapper.set(User::email, it) }

478

updates.department?.let { wrapper.set(User::department, it) }

479

updates.salary?.let { wrapper.set(User::salary, it) }

480

481

wrapper.set(User::updatedTime, LocalDateTime.now())

482

.eq(User::id, id)

483

484

return this.update(wrapper)

485

}

486

}

487

488

data class UserUpdateData(

489

val name: String? = null,

490

val email: String? = null,

491

val department: String? = null,

492

val salary: BigDecimal? = null

493

)

494

```

495

496

### Repository Pattern with Kotlin

497

498

```kotlin

499

@Repository

500

class UserRepository {

501

502

fun findActiveUsersByDepartments(departments: List<String>): List<User> {

503

return Db.ktQuery(User::class.java)

504

.eq(User::active, true)

505

.`in`(User::department, departments)

506

.orderByAsc(User::name)

507

.list()

508

}

509

510

fun findHighEarners(threshold: BigDecimal): List<User> {

511

return Db.list(

512

User::class.java,

513

KtQueryWrapper<User>()

514

.ge(User::salary, threshold)

515

.eq(User::active, true)

516

.orderByDesc(User::salary)

517

)

518

}

519

520

fun updateSalariesByDepartment(department: String, multiplier: Double): Boolean {

521

return Db.ktUpdate(User::class.java)

522

.setSql("salary = salary * $multiplier")

523

.set(User::updatedTime, LocalDateTime.now())

524

.eq(User::department, department)

525

.eq(User::active, true)

526

.update()

527

}

528

529

fun deactivateUsersOlderThan(age: Int): Boolean {

530

return Db.ktUpdate(User::class.java)

531

.set(User::active, false)

532

.set(User::updatedTime, LocalDateTime.now())

533

.gt(User::age, age)

534

.update()

535

}

536

537

fun countUsersByDepartment(): Map<String, Long> {

538

val users = Db.list(

539

User::class.java,

540

KtQueryWrapper<User>()

541

.select(User::department)

542

.eq(User::active, true)

543

)

544

545

return users.groupBy { it.department ?: "Unknown" }

546

.mapValues { it.value.size.toLong() }

547

}

548

}

549

```

550

551

### Error Handling in Kotlin

552

553

```kotlin

554

class KotlinUserService : ServiceImpl<UserMapper, User>() {

555

556

fun safeGetUser(id: Long): User? {

557

return try {

558

this.ktQuery()

559

.eq(User::id, id)

560

.eq(User::active, true)

561

.one()

562

} catch (e: Exception) {

563

println("Error fetching user $id: ${e.message}")

564

null

565

}

566

}

567

568

fun findUserOrDefault(email: String, defaultUser: User): User {

569

return try {

570

this.ktQuery()

571

.eq(User::email, email)

572

.eq(User::active, true)

573

.oneOpt()

574

.orElse(defaultUser)

575

} catch (e: Exception) {

576

println("Error finding user by email $email: ${e.message}")

577

defaultUser

578

}

579

}

580

581

fun batchUpdateWithValidation(updates: List<Pair<Long, String>>): Result<Int> {

582

return try {

583

var successCount = 0

584

585

updates.forEach { (id, newName) ->

586

val updated = this.ktUpdate()

587

.set(User::name, newName)

588

.set(User::updatedTime, LocalDateTime.now())

589

.eq(User::id, id)

590

.eq(User::active, true)

591

.update()

592

593

if (updated) successCount++

594

}

595

596

Result.success(successCount)

597

} catch (e: Exception) {

598

Result.failure(e)

599

}

600

}

601

}

602

```

603

604

## Performance and Best Practices

605

606

### 1. Property Reference Caching

607

608

```kotlin

609

// Kotlin property references are cached automatically

610

// But you can store them for repeated use

611

object UserProperties {

612

val ID = User::id

613

val NAME = User::name

614

val EMAIL = User::email

615

val ACTIVE = User::active

616

val CREATED_TIME = User::createdTime

617

}

618

619

// Usage

620

val users = Db.ktQuery(User::class.java)

621

.eq(UserProperties.ACTIVE, true)

622

.orderByDesc(UserProperties.CREATED_TIME)

623

.list()

624

```

625

626

### 2. Type Safety Benefits

627

628

```kotlin

629

// Compile-time safety - these won't compile if properties don't exist

630

val users = userService.ktQuery()

631

.eq(User::active, true) // ✓ Correct

632

.eq(User::name, "John") // ✓ Correct

633

// .eq(User::invalidField, "x") // ✗ Compilation error

634

.list()

635

```

636

637

### 3. Null Safety Integration

638

639

```kotlin

640

// Kotlin's null safety works with the wrappers

641

fun findUsersByOptionalCriteria(

642

name: String?,

643

department: String?,

644

minAge: Int?

645

): List<User> {

646

val wrapper = KtQueryWrapper<User>()

647

.eq(User::active, true)

648

649

// Safe navigation and let

650

name?.let { wrapper.like(User::name, it) }

651

department?.let { wrapper.eq(User::department, it) }

652

minAge?.let { wrapper.ge(User::age, it) }

653

654

return userService.list(wrapper)

655

}

656

```

657

658

The Kotlin extensions provide a more idiomatic and type-safe way to work with MyBatis-Plus in Kotlin applications, leveraging Kotlin's language features for better developer experience and compile-time safety.