Interface PluginDatabaseManager


public interface PluginDatabaseManager
Database manager for plugin data persistence.

Each plugin gets its own isolated database schema for data isolation. Plugins interact with the database through a JPA-like repository pattern - no raw SQL is allowed.

Example usage:

@Plugin(name = "MyPlugin", version = "1.0.0", author = "Author")
public class MyPlugin {
    private PluginRepository<MyEntity> repository;

    @OnEnable
    public void onEnable(PluginContext context) {
        PluginDatabaseManager db = context.getDatabaseManager();

        // Option 1: Automatic migration from entity classes (recommended)
        db.autoMigrate(UserSetting.class, GuildConfig.class);

        // Option 2: Create/update individual tables
        db.createOrUpdateTable(UserSetting.class);

        // Option 3: Manual schema definition (legacy)
        TableSchema schema = TableSchema.builder("my_data")
            .column("name", ColumnType.STRING, 255, false)
            .column("count", ColumnType.INTEGER, false)
            .column("active", ColumnType.BOOLEAN, false)
            .column("data", ColumnType.TEXT, true)
            .build();
        db.createTable(schema);

        // Get a repository for CRUD operations.
        // Prefer the single-arg form when MyEntity is annotated with @Entity
        // (with or without an explicit tableName) — the table name is then
        // derived from the annotation, so there is no risk of the table name
        // drifting between the entity definition and the getRepository call.
        repository = db.getRepository(MyEntity.class);
        // For legacy/ad-hoc tables without an @Entity class, fall back to the
        // explicit (String, Class) overload.
        // repository = db.getRepository("my_data", MyEntity.class);
    }
}

  • Method Details

    • getSchemaName

      String getSchemaName()
      Get the database schema name assigned to this plugin.

      All tables created by this plugin will be created in this schema. Format: "plugin_{pluginId}" (e.g., "plugin_abcd1234")

      Returns:
      the plugin's database schema name
    • getPluginId

      String getPluginId()
      Get the plugin ID this manager belongs to.
      Returns:
      the plugin ID
    • createTable

      boolean createTable(TableSchema schema)
      Create a table for this plugin.

      The table name will be automatically prefixed with the plugin's prefix. This operation is idempotent - calling it multiple times is safe.

      Parameters:
      schema - the table schema definition
      Returns:
      true if created, false if already exists
    • tableExists

      boolean tableExists(String tableName)
      Check if a table exists.
      Parameters:
      tableName - the table name (without prefix)
      Returns:
      true if exists
    • dropTable

      boolean dropTable(String tableName)
      Drop a table.

      Warning: This permanently deletes all data in the table.

      Parameters:
      tableName - the table name (without prefix)
      Returns:
      true if dropped, false if didn't exist
    • getRepository

      <T> PluginRepository<T> getRepository(String tableName, Class<T> entityClass)
      Get a repository for CRUD operations on a table.

      Prefer getRepository(Class) when the entity class is annotated with @Entity — it derives the table name from @Entity(tableName = "...") (or the class name) so the caller does not have to keep two copies of the table name in sync. Use this (String, Class) overload only when the entity is NOT annotated with @Entity (e.g. legacy code, ad-hoc POJOs, or tables whose name cannot be expressed via the annotation).

      Type Parameters:
      T - the entity type
      Parameters:
      tableName - the table name (without prefix)
      entityClass - the entity class for mapping
      Returns:
      a repository instance
    • getRepository

      <T> PluginRepository<T> getRepository(Class<T> entityClass)
      Get a repository for CRUD operations on a table, deriving the table name from the entity's @Entity annotation.

      The table name is resolved in this order:

      1. An explicit @Entity(tableName = "...") attribute on the class.
      2. Otherwise the class name converted from PascalCase to snake_case (with a trailing Entity suffix stripped).
      This is the same resolution order used by autoMigrate(Class[]) and createOrUpdateTable(Class), so an entity mapped via @Entity(tableName = "user_settings") and a manual migration script that creates user_settings all line up to the same physical table.

      Example:

      
      @Entity(tableName = "user_settings")
      public class UserSettingEntity { ... }
      
      // No need to repeat the table name here — it's read from the annotation.
      PluginRepository<UserSettingEntity> repo = db.getRepository(UserSettingEntity.class);
      
      
      Type Parameters:
      T - the entity type
      Parameters:
      entityClass - the entity class annotated with @Entity
      Returns:
      a repository instance for the resolved table
      Throws:
      IllegalArgumentException - if entityClass is not annotated with @Entity, or if @Entity(tableName = "...") is set but violates the table-name naming rules
    • getKeyValueStore

      PluginKeyValueStore getKeyValueStore()
      Get a simple key-value store for this plugin.

      Useful for storing configuration or simple data without defining schemas.

      Returns:
      the key-value store
    • listTables

      List<String> listTables()
      List all tables owned by this plugin.
      Returns:
      list of table names (without prefix)
    • getSchemaVersion

      int getSchemaVersion()
      Get the current schema version for this plugin.

      Used for migration management.

      Returns:
      current schema version, or 0 if not set
    • setSchemaVersion

      void setSchemaVersion(int version)
      Set the schema version for this plugin.

      Call this after successfully applying migrations.

      Parameters:
      version - the new schema version
    • migrate

      boolean migrate(int targetVersion, PluginMigration migration)
      Execute a migration if needed.

      The migration will only run if the current schema version is less than the target version. After successful migration, the schema version is updated.

      Parameters:
      targetVersion - the version this migration upgrades to
      migration - the migration to execute
      Returns:
      true if migration was executed, false if already at or past target version
    • getStats

      Get database statistics for this plugin.
      Returns:
      database stats
    • autoMigrate

      boolean autoMigrate(Class<?>... entityClasses)
      Automatically migrate tables to match the given entity classes.

      This method compares the current database schema with the schema derived from the entity classes and applies necessary changes (add columns, create indexes, etc.). It does not drop columns or tables - only additive changes for safety.

      The target table name for each entity is resolved in this order:

      1. An explicit @Entity(tableName = "...") attribute on the class.
      2. Otherwise the class name converted from PascalCase to snake_case (with a trailing Entity suffix stripped).
      Use the explicit form whenever the table is also managed by a manual migration script so the auto-migrator and the manual script target the same physical table.

      Example:

      
      dbManager.autoMigrate(UserSetting.class, GuildConfig.class);
      
      
      Parameters:
      entityClasses - the entity classes to migrate to
      Returns:
      true if any migrations were applied, false if already up to date
    • createOrUpdateTable

      <T> boolean createOrUpdateTable(String tableName, Class<T> entityClass)
      Create or update a table from an entity class, using an explicit table name.

      This is the legacy-smooth-migration overload: callers who used to do db.createTable(TableSchema.builder("user_settings")...) can swap to db.createOrUpdateTable("user_settings", UserSettingEntity.class) without first having to annotate their POJO with @Entity(tableName = "user_settings"). Once the migration is complete, they can drop the explicit name and switch to the single-arg createOrUpdateTable(Class) form.

      The explicit tableName overrides any @Entity(tableName = "...") attribute on the class — the value here is what the table will be named in the database, and the annotation is ignored for this call. The name is validated against the same naming rules as TableSchema.Builder (lowercase, starts with a letter, max 50 chars), so a bad value fails fast with a clear message at the call site rather than producing a confusing SQL syntax error later.

      Example migration path:

      
      // Before — manual schema definition:
      TableSchema schema = TableSchema.builder("user_settings")
          .column("user_id", ColumnType.BIGINT, false)
          .build();
      db.createTable(schema);
      
      // After — entity-driven, but still naming the table explicitly so a manual
      // migration script and the auto-migrator agree on the target table:
      db.createOrUpdateTable("user_settings", UserSettingEntity.class);
      
      // Later — once UserSettingEntity carries @Entity(tableName = "user_settings"),
      // drop the explicit name and use the single-arg form:
      // db.createOrUpdateTable(UserSettingEntity.class);
      
      
      Type Parameters:
      T - the entity type
      Parameters:
      tableName - the explicit database table name to use (overrides @Entity(tableName = "...") for this call)
      entityClass - the entity class annotated with @Entity
      Returns:
      true if the table was created or modified
      Throws:
      IllegalArgumentException - if entityClass is not annotated with @Entity, or if tableName violates the table-name naming rules
    • createOrUpdateTable

      <T> boolean createOrUpdateTable(Class<T> entityClass)
      Create or update a table from an entity class.

      This is a convenience method that creates the table if it doesn't exist, or adds missing columns/indexes if it does exist.

      The table name is resolved from @Entity(tableName = "...") when present, otherwise from the class name (PascalCase → snake_case).

      If you have an entity class that is not yet annotated with @Entity(tableName = "...") and you want to start using the entity-driven migration path without changing the POJO first, use the (String, Class) overload — it takes the table name explicitly and overrides whatever the annotation says for that call. Once the POJO carries the annotation, you can drop the explicit name and switch to this single-arg form.

      Parameters:
      entityClass - the entity class annotated with @Entity
      Returns:
      true if table was created or modified, false if already up to date
    • getTableSchema

      TableSchema getTableSchema(String tableName)
      Get the current table schema for a table (for comparison/debugging).
      Parameters:
      tableName - the table name (without prefix)
      Returns:
      current table schema, or null if table doesn't exist