Collections - Kotlin SDK Documentation

Overview

Collections represent your application data. Under the hood they are backed by plain SQLite tables that are generated automatically with the collection name and fields (columns).

A single entry of a collection is called a record (a single row in the SQL table).

📖 Reference: For detailed collection concepts, see the JavaScript SDK Collections documentation.

Collection Types

Base Collection

Default collection type for storing any application data.

import com.bosbase.sdk.BosBase

val pb = BosBase("http://localhost:8090")
// Authenticate as admin
pb.admins.authWithPassword("admin@example.com", "password")

val collection = pb.collections.createBase(
    name = "articles",
    overrides = mapOf(
        "fields" to listOf(
            mapOf("name" to "title", "type" to "text", "required" to true),
            mapOf("name" to "description", "type" to "text")
        )
    )
)

View Collection

Read-only collection populated from a SQL SELECT statement.

val view = pb.collections.createView(
    name = "post_stats",
    viewQuery = """
        SELECT posts.id, posts.name, count(comments.id) as totalComments 
        FROM posts LEFT JOIN comments on comments.postId = posts.id 
        GROUP BY posts.id
    """.trimIndent()
)

Auth Collection

Base collection with authentication fields (email, password, etc.).

val users = pb.collections.createAuth(
    name = "users",
    overrides = mapOf(
        "fields" to listOf(
            mapOf("name" to "name", "type" to "text", "required" to true)
        )
    )
)

Collections API

List Collections

// Paginated list
val result = pb.collections.getList(page = 1, perPage = 50)

// Get all collections
val all = pb.collections.getFullList()

Get Collection

val collection = pb.collections.getOne("articles")

Create Collection

// Using scaffolds
val base = pb.collections.createBase("articles")
val auth = pb.collections.createAuth("users")
val view = pb.collections.createView("stats", "SELECT * FROM posts")

// Manual creation
val collection = pb.collections.create(
    body = mapOf(
        "type" to "base",
        "name" to "articles",
        "fields" to listOf(
            mapOf("name" to "title", "type" to "text", "required" to true),
            mapOf(
                "name" to "created",
                "type" to "autodate",
                "required" to false,
                "onCreate" to true,
                "onUpdate" to false
            ),
            mapOf(
                "name" to "updated",
                "type" to "autodate",
                "required" to false,
                "onCreate" to true,
                "onUpdate" to true
            )
        )
    )
)

Update Collection

val updated = pb.collections.update(
    idOrName = "articles",
    body = mapOf(
        "name" to "blog_articles",
        "fields" to listOf(
            // Updated fields
        )
    )
)

Delete Collection

pb.collections.delete("articles")

Truncate Collection

Delete all records in a collection without deleting the collection itself:

pb.collections.truncate("articles")

Field Management

Add Field

val newField = mapOf(
    "name" to "description",
    "type" to "text",
    "required" to false
)

pb.collections.addField(
    collectionIdOrName = "articles",
    field = newField
)

Update Field

pb.collections.updateField(
    collectionIdOrName = "articles",
    fieldName = "description",
    updates = mapOf(
        "required" to true,
        "max" to 500
    )
)

Remove Field

pb.collections.removeField(
    collectionIdOrName = "articles",
    fieldName = "description"
)

Get Field

val field = pb.collections.getField(
    collectionIdOrName = "articles",
    fieldName = "title"
)

Index Management

Indexes are managed by updating the collection’s indexes field:

// Get current collection
val collection = pb.collections.getOne("articles")
val currentIndexes = (collection["indexes"] as? JsonArray)?.mapNotNull { it.jsonPrimitive.contentOrNull }?.toMutableList() ?: mutableListOf()

// Add single column index
currentIndexes.add("CREATE INDEX idx_title ON articles(title)")

// Add multi-column index
currentIndexes.add("CREATE INDEX idx_title_created ON articles(title, created)")

// Add unique index
currentIndexes.add("CREATE UNIQUE INDEX idx_slug ON articles(slug)")

// Update collection with new indexes
pb.collections.update("articles", body = mapOf(
    "indexes" to currentIndexes
))

// Get current indexes
val indexes = (collection["indexes"] as? JsonArray)?.mapNotNull { it.jsonPrimitive.contentOrNull } ?: emptyList()

Remove Index

val collection = pb.collections.getOne("articles")
val indexes = (collection["indexes"] as? JsonArray)?.mapNotNull { it.jsonPrimitive.contentOrNull }?.toMutableList() ?: mutableListOf()

// Remove specific index
indexes.removeAll { it.contains("idx_title") }

pb.collections.update("articles", body = mapOf(
    "indexes" to indexes
))

API Rules Management

API rules are managed by updating the collection’s rule fields:

// Get current collection
val collection = pb.collections.getOne("articles")

// Update rules via collection update
pb.collections.update("articles", body = mapOf(
    "listRule" to "@request.auth.id != ''",      // List rule
    "viewRule" to "@request.auth.id != ''",      // View rule
    "createRule" to "@request.auth.id != ''",    // Create rule
    "updateRule" to "@request.auth.id = author.id",  // Update rule
    "deleteRule" to "@request.auth.id = author.id || @request.auth.isSuperuser = true"  // Delete rule
))

// Get current rules
val listRule = collection["listRule"]?.jsonPrimitive?.contentOrNull
val viewRule = collection["viewRule"]?.jsonPrimitive?.contentOrNull
val createRule = collection["createRule"]?.jsonPrimitive?.contentOrNull
val updateRule = collection["updateRule"]?.jsonPrimitive?.contentOrNull
val deleteRule = collection["deleteRule"]?.jsonPrimitive?.contentOrNull

println("List rule: $listRule")
println("View rule: $viewRule")

Setting Individual Rules

// Set only list rule
pb.collections.update("articles", body = mapOf(
    "listRule" to "status = 'published' || @request.auth.id != ''"
))

// Set only view rule
pb.collections.update("articles", body = mapOf(
    "viewRule" to "@request.auth.id != ''"
))

// Clear a rule (allow anyone)
pb.collections.update("articles", body = mapOf(
    "listRule" to ""
))

Auth Collection Rules

For auth collections, you can also set manage and auth rules:

pb.collections.update("users", body = mapOf(
    "manageRule" to "@request.auth.id = id || @request.auth.isSuperuser = true",
    "authRule" to "verified = true"
))

Collection Import

Import multiple collections at once:

val collections = listOf(
    mapOf(
        "type" to "base",
        "name" to "articles",
        "fields" to listOf(/* ... */)
    ),
    mapOf(
        "type" to "auth",
        "name" to "users",
        "fields" to listOf(/* ... */)
    )
)

pb.collections.import(
    collections = collections,
    deleteMissing = false  // Set to true to delete collections not in import
)

Collection Scaffolds

Get scaffolded collection models:

val scaffolds = pb.collections.getScaffolds()

// Access scaffold types
val baseScaffold = scaffolds["base"]
val authScaffold = scaffolds["auth"]
val viewScaffold = scaffolds["view"]

Examples

Complete Collection Setup

import com.bosbase.sdk.BosBase

fun setupBlogCollections(pb: BosBase) {
    // Authenticate as admin
    pb.admins.authWithPassword("admin@example.com", "password")
    
    // Create articles collection
    val articles = pb.collections.createBase(
        name = "articles",
        overrides = mapOf(
            "fields" to listOf(
                mapOf("name" to "title", "type" to "text", "required" to true),
                mapOf("name" to "content", "type" to "editor", "required" to true),
                mapOf("name" to "status", "type" to "select", "options" to mapOf(
                    "values" to listOf("draft", "published", "archived")
                )),
                mapOf("name" to "author", "type" to "relation", "options" to mapOf(
                    "collectionId" to "users",
                    "maxSelect" to 1
                ))
            )
        )
    )
    
    // Set API rules
    pb.collections.update("articles", body = mapOf(
        "listRule" to "status = 'published' || @request.auth.id != ''",
        "viewRule" to "status = 'published' || @request.auth.id = author.id",
        "createRule" to "@request.auth.id != ''",
        "updateRule" to "@request.auth.id = author.id",
        "deleteRule" to "@request.auth.id = author.id || @request.auth.isSuperuser = true"
    ))
    
    // Add index for performance
    val collection = pb.collections.getOne("articles")
    val indexes = ((collection["indexes"] as? JsonArray)?.mapNotNull { it.jsonPrimitive.contentOrNull }?.toMutableList() ?: mutableListOf()).apply {
        add("CREATE INDEX idx_status_created ON articles(status, created)")
    }
    pb.collections.update("articles", body = mapOf(
        "indexes" to indexes
    ))
    
    println("Blog collections setup complete!")
}

Dynamic Field Addition

fun addTagFieldToArticles(pb: BosBase) {
    pb.collections.addField(
        collectionIdOrName = "articles",
        field = mapOf(
            "name" to "tags",
            "type" to "select",
            "options" to mapOf(
                "maxSelect" to 5,
                "values" to listOf("kotlin", "android", "backend", "frontend")
            )
        )
    )
}

Collection Migration

fun migrateCollection(pb: BosBase, oldName: String, newName: String) {
    // Get existing collection
    val collection = pb.collections.getOne(oldName)
    
    // Create new collection with updated name
    val newCollection = pb.collections.create(
        body = (collection.jsonObject.toMutableMap() + ("name" to newName)).toMap()
    )
    
    // Copy data (if needed)
    // ... data migration logic ...
    
    // Delete old collection
    pb.collections.delete(oldName)
}