realm_flutter_vector_db 1.0.13 copy "realm_flutter_vector_db: ^1.0.13" to clipboard
realm_flutter_vector_db: ^1.0.13 copied to clipboard

Realm Dart SDK with built-in HNSW vector search - a mobile database with AI/ML vector similarity search capabilities for semantic search.

example/lib/main.dart

// Copyright 2021 MongoDB, Inc.
// SPDX-License-Identifier: Apache-2.0

// ignore_for_file: avoid_print

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:realm_flutter_vector_db/realm_vector_db.dart';

part 'main.realm.dart';

@RealmModel()
class _Car {
  late String make;
  String? model;
  int? kilometers = 500;
  _Person? owner;
}

@RealmModel()
class _Person {
  late String name;
  int age = 1;
}

@RealmModel()
class _Document {
  @PrimaryKey()
  late String id;

  late String title;
  late String content;
  late List<double> embedding;
}

void main() {
  print("Current PID $pid");
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late Realm realm;
  String outputText = 'Initializing...';

  _MyAppState() {
    final config = Configuration.local(
      [Car.schema, Person.schema, Document.schema],
      schemaVersion: 2, // Increment version to trigger delete on mismatch
      shouldDeleteIfMigrationNeeded: true,
    );
    realm = Realm(config);
  }

  int get carsCount => realm.all<Car>().length;
  int get docsCount => realm.all<Document>().length;

  @override
  void initState() {
    super.initState();
    _runExamples();
  }

  void _runExamples() async {
    final buffer = StringBuffer();

    // First, clean up any existing vector index and documents to start fresh
    try {
      realm.write(() {
        if (realm.hasVectorIndex<Document>('embedding')) {
          buffer.writeln('Found existing vector index, removing for clean test...');
          realm.removeVectorIndex<Document>('embedding');
          buffer.writeln('✓ Vector index removed\n');
        }
        realm.deleteAll<Document>();
      });
    } catch (e) {
      // If there's an error, just log it and continue
      buffer.writeln('Note: Error during cleanup: $e\n');
    }

    // Original Car example
    buffer.writeln('=== Basic Car Example ===');
    var myCar = Car("Tesla", model: "Model Y", kilometers: 1);
    realm.write(() {
      buffer.writeln('Adding a Car to Realm.');
      var car = realm.add(Car("Tesla", owner: Person("John")));
      buffer.writeln("Updating the car's model and kilometers");
      car.model = "Model 3";
      car.kilometers = 5000;

      buffer.writeln('Adding another Car to Realm.');
      realm.add(myCar);

      buffer.writeln("Changing the owner of the car.");
      myCar.owner = Person("me", age: 18);
      buffer.writeln("The car has a new owner ${car.owner!.name}");
    });

    buffer.writeln("Getting all cars from the Realm.");
    var cars = realm.all<Car>();
    buffer.writeln("There are ${cars.length} cars in the Realm.");

    var indexedCar = cars[0];
    buffer.writeln('The first car is ${indexedCar.make} ${indexedCar.model}');

    buffer.writeln("Getting all Tesla cars from the Realm.");
    var filteredCars = realm.query<Car>("make == 'Tesla'");
    buffer.writeln('Found ${filteredCars.length} Tesla cars\n');

    // Vector Search Comprehensive Tests
    buffer.writeln('╔════════════════════════════════════════════════════════╗');
    buffer.writeln('║  HNSW VECTOR SEARCH - COMPREHENSIVE TEST SUITE        ║');
    buffer.writeln('╚════════════════════════════════════════════════════════╝\n');

    try {
      // TEST 1: Index Creation with Different Metrics
      buffer.writeln('━━━ TEST 1: Index Creation ━━━');
      realm.write(() {
        buffer.writeln('Creating vector index with Cosine metric...');
        buffer.writeln('Parameters: M=16, M0=32, efConstruction=200, efSearch=100');
        realm.createVectorIndex<Document>(
          'embedding',
          metric: VectorDistanceMetric.cosine,
          m: 16,
          efConstruction: 200,
        );
        buffer.writeln('✓ Vector index created successfully!\n');
      });

      // TEST 2: Adding Diverse Documents
      buffer.writeln('━━━ TEST 2: Document Insertion (20 documents) ━━━');
      realm.write(() {
        buffer.writeln('Adding documents across multiple categories:\n');

        // Technology cluster (5 docs)
        buffer.writeln('Technology Cluster:');
        realm.add(Document('tech1', 'AI Fundamentals', 'Introduction to artificial intelligence', embedding: [0.95, 0.85, 0.05, 0.10, 0.02, 0.08]));
        buffer.writeln('  + AI Fundamentals');

        realm.add(Document('tech2', 'Machine Learning', 'Deep learning and neural networks', embedding: [0.90, 0.82, 0.08, 0.12, 0.03, 0.10]));
        buffer.writeln('  + Machine Learning');

        realm.add(Document('tech3', 'Computer Vision', 'Image recognition and object detection', embedding: [0.88, 0.80, 0.10, 0.15, 0.05, 0.12]));
        buffer.writeln('  + Computer Vision');

        realm.add(Document('tech4', 'NLP Systems', 'Natural language processing and chatbots', embedding: [0.92, 0.83, 0.07, 0.11, 0.04, 0.09]));
        buffer.writeln('  + NLP Systems');

        realm.add(Document('tech5', 'Robotics', 'Autonomous robots and automation', embedding: [0.85, 0.78, 0.12, 0.18, 0.06, 0.14]));
        buffer.writeln('  + Robotics\n');

        // Nature cluster (5 docs)
        buffer.writeln('Nature Cluster:');
        realm.add(Document('nature1', 'Forest Ecosystems', 'Trees, plants and woodland creatures', embedding: [0.08, 0.12, 0.95, 0.88, 0.02, 0.05]));
        buffer.writeln('  + Forest Ecosystems');

        realm.add(Document('nature2', 'Ocean Life', 'Marine animals and coral reefs', embedding: [0.10, 0.15, 0.92, 0.85, 0.03, 0.08]));
        buffer.writeln('  + Ocean Life');

        realm.add(Document('nature3', 'Mountain Wildlife', 'Alpine animals and high-altitude plants', embedding: [0.12, 0.18, 0.90, 0.82, 0.05, 0.10]));
        buffer.writeln('  + Mountain Wildlife');

        realm.add(Document('nature4', 'Desert Biomes', 'Arid ecosystems and adapted species', embedding: [0.15, 0.20, 0.88, 0.80, 0.07, 0.12]));
        buffer.writeln('  + Desert Biomes');

        realm.add(Document('nature5', 'Rainforest Canopy', 'Tropical biodiversity and climate', embedding: [0.05, 0.10, 0.98, 0.92, 0.01, 0.03]));
        buffer.writeln('  + Rainforest Canopy\n');

        // Sports cluster (5 docs)
        buffer.writeln('Sports Cluster:');
        realm.add(Document('sport1', 'Football Tactics', 'Strategy and team formations', embedding: [0.10, 0.15, 0.05, 0.08, 0.95, 0.88]));
        buffer.writeln('  + Football Tactics');

        realm.add(Document('sport2', 'Basketball Skills', 'Shooting, passing and defense techniques', embedding: [0.12, 0.18, 0.08, 0.12, 0.92, 0.85]));
        buffer.writeln('  + Basketball Skills');

        realm.add(Document('sport3', 'Tennis Training', 'Serve, volley and court positioning', embedding: [0.15, 0.20, 0.10, 0.15, 0.90, 0.82]));
        buffer.writeln('  + Tennis Training');

        realm.add(Document('sport4', 'Swimming Techniques', 'Strokes, breathing and endurance', embedding: [0.08, 0.12, 0.12, 0.18, 0.88, 0.80]));
        buffer.writeln('  + Swimming Techniques');

        realm.add(Document('sport5', 'Marathon Running', 'Distance training and nutrition', embedding: [0.18, 0.22, 0.15, 0.20, 0.85, 0.78]));
        buffer.writeln('  + Marathon Running\n');

        // Cross-domain documents (5 docs)
        buffer.writeln('Cross-Domain Documents:');
        realm.add(Document('cross1', 'Bio Technology', 'Using AI for biology research', embedding: [0.55, 0.50, 0.45, 0.40, 0.10, 0.15]));
        buffer.writeln('  + Bio Technology (Tech + Nature)');

        realm.add(Document('cross2', 'Sports Analytics', 'Machine learning for athlete performance', embedding: [0.60, 0.55, 0.08, 0.12, 0.65, 0.60]));
        buffer.writeln('  + Sports Analytics (Tech + Sports)');

        realm.add(Document('cross3', 'Wildlife Photography', 'Camera tech for nature documentation', embedding: [0.45, 0.40, 0.55, 0.50, 0.12, 0.18]));
        buffer.writeln('  + Wildlife Photography (Tech + Nature)');

        realm.add(Document('cross4', 'Outdoor Adventure', 'Hiking, climbing and nature sports', embedding: [0.15, 0.20, 0.50, 0.45, 0.60, 0.55]));
        buffer.writeln('  + Outdoor Adventure (Nature + Sports)');

        realm.add(Document('cross5', 'Balanced Living', 'Health, nature and physical activity', embedding: [0.30, 0.35, 0.35, 0.30, 0.40, 0.35]));
        buffer.writeln('  + Balanced Living (All Domains)\n');
      });

      // TEST 3: Index Statistics
      buffer.writeln('━━━ TEST 3: Index Statistics ━━━');
      final stats = realm.getVectorIndexStats<Document>('embedding');
      if (stats != null) {
        buffer.writeln('✓ Index Stats Retrieved:');
        buffer.writeln('  • Total vectors indexed: ${stats.numVectors}');
        buffer.writeln('  • Maximum layer depth: ${stats.maxLayer}');
        buffer.writeln('  • Expected: 20 vectors, multi-layer structure\n');
      } else {
        buffer.writeln('✗ Failed to retrieve index stats\n');
      }

      // TEST 4: KNN Search - Technology Query
      buffer.writeln('━━━ TEST 4: KNN Search - Technology Query ━━━');
      buffer.writeln('Query: Pure AI/ML content [0.95, 0.85, 0.05, 0.10, 0.02, 0.08]');
      buffer.writeln('K=5, Expected: Top 5 technology documents\n');

      final techQuery = [0.95, 0.85, 0.05, 0.10, 0.02, 0.08];
      final techResults = realm.vectorSearchKnn<Document>(
        'embedding',
        queryVector: techQuery,
        k: 5,
      );

      buffer.writeln('Results (sorted by similarity):');
      for (var i = 0; i < techResults.length; i++) {
        final result = techResults[i];
        final similarity = (1 - result.distance) * 100;
        buffer.writeln('  ${i + 1}. "${result.object.title}"');
        buffer.writeln('     ID: ${result.object.id} | Distance: ${result.distance.toStringAsFixed(4)} | Similarity: ${similarity.toStringAsFixed(1)}%');
      }
      buffer.writeln('');

      // TEST 5: KNN Search - Nature Query
      buffer.writeln('━━━ TEST 5: KNN Search - Nature Query ━━━');
      buffer.writeln('Query: Pure nature content [0.05, 0.10, 0.98, 0.92, 0.01, 0.03]');
      buffer.writeln('K=5, Expected: Top 5 nature documents\n');

      final natureQuery = [0.05, 0.10, 0.98, 0.92, 0.01, 0.03];
      final natureResults = realm.vectorSearchKnn<Document>(
        'embedding',
        queryVector: natureQuery,
        k: 5,
      );

      buffer.writeln('Results (sorted by similarity):');
      for (var i = 0; i < natureResults.length; i++) {
        final result = natureResults[i];
        final similarity = (1 - result.distance) * 100;
        buffer.writeln('  ${i + 1}. "${result.object.title}"');
        buffer.writeln('     ID: ${result.object.id} | Distance: ${result.distance.toStringAsFixed(4)} | Similarity: ${similarity.toStringAsFixed(1)}%');
      }
      buffer.writeln('');

      // TEST 6: KNN Search - Sports Query
      buffer.writeln('━━━ TEST 6: KNN Search - Sports Query ━━━');
      buffer.writeln('Query: Pure sports content [0.10, 0.15, 0.05, 0.08, 0.95, 0.88]');
      buffer.writeln('K=5, Expected: Top 5 sports documents\n');

      final sportsQuery = [0.10, 0.15, 0.05, 0.08, 0.95, 0.88];
      final sportsResults = realm.vectorSearchKnn<Document>(
        'embedding',
        queryVector: sportsQuery,
        k: 5,
      );

      buffer.writeln('Results (sorted by similarity):');
      for (var i = 0; i < sportsResults.length; i++) {
        final result = sportsResults[i];
        final similarity = (1 - result.distance) * 100;
        buffer.writeln('  ${i + 1}. "${result.object.title}"');
        buffer.writeln('     ID: ${result.object.id} | Distance: ${result.distance.toStringAsFixed(4)} | Similarity: ${similarity.toStringAsFixed(1)}%');
      }
      buffer.writeln('');

      // TEST 7: KNN Search - Cross-Domain Query
      buffer.writeln('━━━ TEST 7: KNN Search - Cross-Domain Query ━━━');
      buffer.writeln('Query: Tech + Nature hybrid [0.60, 0.55, 0.50, 0.45, 0.15, 0.20]');
      buffer.writeln('K=5, Expected: Cross-domain documents (Bio Tech, Wildlife Photo, etc.)\n');

      final crossQuery = [0.60, 0.55, 0.50, 0.45, 0.15, 0.20];
      final crossResults = realm.vectorSearchKnn<Document>(
        'embedding',
        queryVector: crossQuery,
        k: 5,
      );

      buffer.writeln('Results (sorted by similarity):');
      for (var i = 0; i < crossResults.length; i++) {
        final result = crossResults[i];
        final similarity = (1 - result.distance) * 100;
        buffer.writeln('  ${i + 1}. "${result.object.title}"');
        buffer.writeln('     ID: ${result.object.id} | Distance: ${result.distance.toStringAsFixed(4)} | Similarity: ${similarity.toStringAsFixed(1)}%');
      }
      buffer.writeln('');

      // TEST 8: Radius Search - Tight Radius
      buffer.writeln('━━━ TEST 8: Radius Search - Tight Radius ━━━');
      buffer.writeln('Query: AI Fundamentals vector [0.95, 0.85, 0.05, 0.10, 0.02, 0.08]');
      buffer.writeln('Max Distance: 0.15 (very tight - only very similar docs)\n');

      final radiusTightResults = realm.vectorSearchRadius<Document>(
        'embedding',
        queryVector: [0.95, 0.85, 0.05, 0.10, 0.02, 0.08],
        maxDistance: 0.15,
      );

      buffer.writeln('Found ${radiusTightResults.length} documents within tight radius:');
      for (var result in radiusTightResults) {
        buffer.writeln('  • "${result.object.title}" (dist: ${result.distance.toStringAsFixed(4)})');
      }
      buffer.writeln('');

      // TEST 9: Radius Search - Medium Radius
      buffer.writeln('━━━ TEST 9: Radius Search - Medium Radius ━━━');
      buffer.writeln('Query: Balanced Living vector [0.30, 0.35, 0.35, 0.30, 0.40, 0.35]');
      buffer.writeln('Max Distance: 0.5 (medium - should find related cross-domain docs)\n');

      final radiusMediumResults = realm.vectorSearchRadius<Document>(
        'embedding',
        queryVector: [0.30, 0.35, 0.35, 0.30, 0.40, 0.35],
        maxDistance: 0.5,
      );

      buffer.writeln('Found ${radiusMediumResults.length} documents within medium radius:');
      final sortedMedium = radiusMediumResults.toList()..sort((a, b) => a.distance.compareTo(b.distance));
      for (var result in sortedMedium.take(10)) {
        buffer.writeln('  • "${result.object.title}" (dist: ${result.distance.toStringAsFixed(4)})');
      }
      if (radiusMediumResults.length > 10) {
        buffer.writeln('  ... and ${radiusMediumResults.length - 10} more');
      }
      buffer.writeln('');

      // TEST 10: Radius Search - Wide Radius
      buffer.writeln('━━━ TEST 10: Radius Search - Wide Radius ━━━');
      buffer.writeln('Query: Zero vector [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]');
      buffer.writeln('Max Distance: 1.5 (wide - should find many/all documents)\n');

      final radiusWideResults = realm.vectorSearchRadius<Document>(
        'embedding',
        queryVector: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
        maxDistance: 1.5,
      );

      buffer.writeln('Found ${radiusWideResults.length} documents within wide radius');
      buffer.writeln('(Expected: all 20 documents)\n');

      // TEST 11: Edge Case - K larger than dataset
      buffer.writeln('━━━ TEST 11: Edge Case - K > Dataset Size ━━━');
      buffer.writeln('Query: Tech query, K=50 (dataset has only 20 docs)\n');

      final largeKResults = realm.vectorSearchKnn<Document>(
        'embedding',
        queryVector: techQuery,
        k: 50,
      );

      buffer.writeln('✓ Returned ${largeKResults.length} results (max available)');
      buffer.writeln('Expected: 20 results (entire dataset)\n');

      // TEST 12: Edge Case - K = 1
      buffer.writeln('━━━ TEST 12: Edge Case - K = 1 (Single Nearest) ━━━');
      buffer.writeln('Query: Pure sports [0.10, 0.15, 0.05, 0.08, 0.95, 0.88], K=1\n');

      final singleResult = realm.vectorSearchKnn<Document>(
        'embedding',
        queryVector: sportsQuery,
        k: 1,
      );

      if (singleResult.isNotEmpty) {
        final result = singleResult.first;
        buffer.writeln('✓ Single nearest neighbor:');
        buffer.writeln('  "${result.object.title}" (dist: ${result.distance.toStringAsFixed(4)})\n');
      }

      // TEST 13: Verification - Check Index Presence
      buffer.writeln('━━━ TEST 13: Index Verification ━━━');
      final hasIndex = realm.hasVectorIndex<Document>('embedding');
      buffer.writeln('✓ Vector index exists: $hasIndex');
      buffer.writeln('Expected: true\n');

      // TEST 14: Performance Test - Multiple Sequential Searches
      buffer.writeln('━━━ TEST 14: Performance - Sequential Searches ━━━');
      final perfStopwatch = Stopwatch()..start();

      for (var i = 0; i < 10; i++) {
        realm.vectorSearchKnn<Document>(
          'embedding',
          queryVector: [0.5 + i * 0.05, 0.5 - i * 0.05, 0.5, 0.5, 0.3, 0.3],
          k: 5,
        );
      }

      perfStopwatch.stop();
      buffer.writeln('✓ Completed 10 sequential KNN searches (K=5)');
      buffer.writeln('Total time: ${perfStopwatch.elapsedMilliseconds}ms');
      buffer.writeln('Avg time per search: ${(perfStopwatch.elapsedMilliseconds / 10).toStringAsFixed(2)}ms\n');

      // TEST 15: Filtering - By ID Pattern
      buffer.writeln('━━━ TEST 15: Filtering - By ID Pattern ━━━');
      buffer.writeln('Query: Tech content, filtered to show only "tech" prefix IDs\n');

      final techResultsFiltered = realm
          .vectorSearchKnn<Document>(
            'embedding',
            queryVector: techQuery,
            k: 10,
          )
          .where((result) => result.object.id.startsWith('tech'));

      buffer.writeln('Results (top 5 tech IDs):');
      for (var i = 0; i < techResultsFiltered.take(5).length; i++) {
        final result = techResultsFiltered.elementAt(i);
        buffer.writeln('  ${i + 1}. "${result.object.title}" (ID: ${result.object.id}, dist: ${result.distance.toStringAsFixed(4)})');
      }
      buffer.writeln('');

      // TEST 16: Filtering - By Title Pattern
      buffer.writeln('━━━ TEST 16: Filtering - By Title Contains ━━━');
      buffer.writeln('Query: All documents, filter titles containing "Life" or "Living"\n');

      final allResults = realm.vectorSearchKnn<Document>(
        'embedding',
        queryVector: [0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
        k: 20,
      );

      final lifeResults = allResults.where((result) => result.object.title.contains('Life') || result.object.title.contains('Living'));

      buffer.writeln('Found ${lifeResults.length} documents:');
      for (var result in lifeResults) {
        buffer.writeln('  • "${result.object.title}" (dist: ${result.distance.toStringAsFixed(4)})');
      }
      buffer.writeln('');

      // TEST 17: Filtering - By Content Keywords
      buffer.writeln('━━━ TEST 17: Filtering - By Content Keywords ━━━');
      buffer.writeln('Query: Nature content, filter by "animals" keyword in content\n');

      final natureResultsWithAnimals = realm
          .vectorSearchKnn<Document>(
            'embedding',
            queryVector: natureQuery,
            k: 10,
          )
          .where((result) => result.object.content.toLowerCase().contains('animals'));

      buffer.writeln('Results with "animals" keyword:');
      for (var i = 0; i < natureResultsWithAnimals.length; i++) {
        final result = natureResultsWithAnimals.elementAt(i);
        buffer.writeln('  ${i + 1}. "${result.object.title}"');
        buffer.writeln('     Content: "${result.object.content}" (dist: ${result.distance.toStringAsFixed(4)})');
      }
      buffer.writeln('');

      // TEST 18: Filtering - Distance Threshold
      buffer.writeln('━━━ TEST 18: Filtering - Custom Distance Threshold ━━━');
      buffer.writeln('Query: Sports content, manually filter distance < 0.3\n');

      final sportsResultsFiltered = realm
          .vectorSearchKnn<Document>(
            'embedding',
            queryVector: sportsQuery,
            k: 10,
          )
          .where((result) => result.distance < 0.3);

      buffer.writeln('Found ${sportsResultsFiltered.length} high-confidence results:');
      for (var result in sportsResultsFiltered) {
        buffer.writeln('  • "${result.object.title}" (dist: ${result.distance.toStringAsFixed(4)})');
      }
      buffer.writeln('');

      // TEST 19: Filtering - Combined Criteria
      buffer.writeln('━━━ TEST 19: Filtering - Multiple Combined Criteria ━━━');
      buffer.writeln('Query: All docs, filter for cross-domain (ID starts with "cross") AND distance < 0.6\n');

      final neutralQuery = [0.4, 0.4, 0.4, 0.4, 0.4, 0.4];
      final combinedFiltered = realm
          .vectorSearchKnn<Document>(
            'embedding',
            queryVector: neutralQuery,
            k: 20,
          )
          .where((result) => result.object.id.startsWith('cross') && result.distance < 0.6);

      buffer.writeln('Found ${combinedFiltered.length} cross-domain docs within threshold:');
      for (var result in combinedFiltered) {
        buffer.writeln('  • "${result.object.title}" (ID: ${result.object.id}, dist: ${result.distance.toStringAsFixed(4)})');
      }
      buffer.writeln('');

      // TEST 20: Filtering - Realm Query on Vector Results
      buffer.writeln('━━━ TEST 20: Filtering - Using Realm Query After Vector Search ━━━');
      buffer.writeln('Query: Get vector search results, then filter with Realm query\n');

      // Get top 10 tech results
      final topTechResults = realm.vectorSearchKnn<Document>(
        'embedding',
        queryVector: techQuery,
        k: 10,
      );

      // Extract IDs from vector results
      final topTechIds = topTechResults.map((r) => r.object.id).toList();
      buffer.writeln('Top 10 vector search IDs: ${topTechIds.join(", ")}\n');

      // Now use Realm query to filter further by title pattern
      final queryString = topTechIds.map((id) => "id == '$id'").join(' OR ');
      final realmFiltered = realm.all<Document>().query(queryString).query("title CONTAINS[c] 'learning' OR title CONTAINS[c] 'intelligence'");

      buffer.writeln('After Realm query filter (title contains "learning" or "intelligence"):');
      buffer.writeln('Found ${realmFiltered.length} documents:');
      for (var doc in realmFiltered) {
        buffer.writeln('  • "${doc.title}" (ID: ${doc.id})');
      }
      buffer.writeln('');

      // TEST 21: Filtering - Exclude Categories
      buffer.writeln('━━━ TEST 21: Filtering - Exclude Specific Categories ━━━');
      buffer.writeln('Query: Balanced query, exclude all sports-related docs\n');

      final nonSportsResults = realm
          .vectorSearchKnn<Document>(
            'embedding',
            queryVector: [0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
            k: 20,
          )
          .where((result) => !result.object.id.startsWith('sport'));

      buffer.writeln('Found ${nonSportsResults.length} non-sports documents:');
      for (var i = 0; i < nonSportsResults.take(8).length; i++) {
        final result = nonSportsResults.elementAt(i);
        buffer.writeln('  ${i + 1}. "${result.object.title}" (ID: ${result.object.id})');
      }
      if (nonSportsResults.length > 8) {
        buffer.writeln('  ... and ${nonSportsResults.length - 8} more');
      }
      buffer.writeln('');

      // TEST 22: Filtering - Top-K Per Category
      buffer.writeln('━━━ TEST 22: Filtering - Top-K Results Per Category ━━━');
      buffer.writeln('Query: Neutral query, get top 2 from each category\n');

      final neutralResults = realm.vectorSearchKnn<Document>(
        'embedding',
        queryVector: neutralQuery,
        k: 20,
      );

      final topTechPerCategory = neutralResults.where((r) => r.object.id.startsWith('tech')).take(2);
      final topNaturePerCategory = neutralResults.where((r) => r.object.id.startsWith('nature')).take(2);
      final topSportsPerCategory = neutralResults.where((r) => r.object.id.startsWith('sport')).take(2);
      final topCrossPerCategory = neutralResults.where((r) => r.object.id.startsWith('cross')).take(2);

      buffer.writeln('Top 2 Tech:');
      for (var result in topTechPerCategory) {
        buffer.writeln('  • "${result.object.title}" (dist: ${result.distance.toStringAsFixed(4)})');
      }

      buffer.writeln('Top 2 Nature:');
      for (var result in topNaturePerCategory) {
        buffer.writeln('  • "${result.object.title}" (dist: ${result.distance.toStringAsFixed(4)})');
      }

      buffer.writeln('Top 2 Sports:');
      for (var result in topSportsPerCategory) {
        buffer.writeln('  • "${result.object.title}" (dist: ${result.distance.toStringAsFixed(4)})');
      }

      buffer.writeln('Top 2 Cross-Domain:');
      for (var result in topCrossPerCategory) {
        buffer.writeln('  • "${result.object.title}" (dist: ${result.distance.toStringAsFixed(4)})');
      }
      buffer.writeln('');

      // TEST 23: Filtering - Similarity Score Range
      buffer.writeln('━━━ TEST 23: Filtering - By Similarity Score Range ━━━');
      buffer.writeln('Query: Tech content, filter for 70%-90% similarity range\n');

      final similarityRangeResults = realm
          .vectorSearchKnn<Document>(
        'embedding',
        queryVector: techQuery,
        k: 15,
      )
          .where((result) {
        final similarity = (1 - result.distance) * 100;
        return similarity >= 70 && similarity <= 90;
      });

      buffer.writeln('Results in 70%-90% similarity range:');
      for (var result in similarityRangeResults) {
        final similarity = (1 - result.distance) * 100;
        buffer.writeln('  • "${result.object.title}" (${similarity.toStringAsFixed(1)}% similar)');
      }
      buffer.writeln('');

      // TEST 24: Edge Case - Duplicate Index Creation
      buffer.writeln('━━━ TEST 24: Edge Case - Duplicate Index Creation ━━━');
      buffer.writeln('Test: Attempt to create vector index on same property multiple times\n');

      // Check index status before attempting duplicate creation
      print('🔍 [TEST 24] Checking if index exists before duplicate attempt...');
      final hasIndexBefore = realm.hasVectorIndex<Document>('embedding');
      print('🔍 [TEST 24] Index exists before duplicate attempt: $hasIndexBefore');
      buffer.writeln('Initial state: hasVectorIndex = $hasIndexBefore');

      if (hasIndexBefore) {
        final statsBefore = realm.getVectorIndexStats<Document>('embedding');
        print('🔍 [TEST 24] Index stats before: numVectors=${statsBefore?.numVectors}, maxLayer=${statsBefore?.maxLayer}');
        buffer.writeln('Index stats: ${statsBefore?.numVectors} vectors, ${statsBefore?.maxLayer} layers\n');
      }

      try {
        print('🔍 [TEST 24] Entering write transaction for duplicate index creation...');
        realm.write(() {
          print('🔍 [TEST 24] Inside write transaction, calling createVectorIndex with different params...');
          print('🔍 [TEST 24] Params: metric=Euclidean, M=8, efConstruction=100');
          buffer.writeln('Attempting to create index again on "embedding" property...');
          buffer.writeln('Parameters: Euclidean metric, M=8, efConstruction=100');

          realm.createVectorIndex<Document>(
            'embedding',
            metric: VectorDistanceMetric.euclidean, // Different metric
            m: 8, // Different parameters
            efConstruction: 100,
          );

          print('🔍 [TEST 24] createVectorIndex call completed WITHOUT exception!');
          buffer.writeln('\n✗ UNEXPECTED: Index creation succeeded (should have failed or been ignored)');
          buffer.writeln('   This means duplicate index creation is allowed!');
        });

        print('🔍 [TEST 24] Write transaction committed successfully');
      } catch (e) {
        print('🔍 [TEST 24] Exception caught: ${e.runtimeType}');
        print('🔍 [TEST 24] Exception message: $e');
        buffer.writeln('\n✓ Expected behavior: Got exception');
        buffer.writeln('   Exception type: ${e.runtimeType}');
        buffer.writeln('   Error: ${e.toString().split('\n').first}');
        buffer.writeln('   This prevents accidental duplicate index creation');
      }

      // Check index status after attempt
      print('🔍 [TEST 24] Checking index status after duplicate attempt...');
      final hasIndexAfter = realm.hasVectorIndex<Document>('embedding');
      print('🔍 [TEST 24] Index exists after duplicate attempt: $hasIndexAfter');

      if (hasIndexAfter) {
        final statsAfter = realm.getVectorIndexStats<Document>('embedding');
        print('🔍 [TEST 24] Index stats after: numVectors=${statsAfter?.numVectors}, maxLayer=${statsAfter?.maxLayer}');
        buffer.writeln('\nAfter duplicate attempt:');
        buffer.writeln('   hasVectorIndex = $hasIndexAfter');
        buffer.writeln('   Stats: ${statsAfter?.numVectors} vectors, ${statsAfter?.maxLayer} layers');
      }

      // Verify original index still works
      print('🔍 [TEST 24] Testing if original index still works...');
      buffer.writeln('\nVerifying original index still functional:');
      try {
        final verifyResults = realm.vectorSearchKnn<Document>(
          'embedding',
          queryVector: techQuery,
          k: 3,
        );
        print('🔍 [TEST 24] Search succeeded: ${verifyResults.length} results');
        if (verifyResults.isNotEmpty) {
          print('🔍 [TEST 24] Top result: "${verifyResults.first.object.title}"');
          print('🔍 [TEST 24] Top result distance: ${verifyResults.first.distance}');
        }
        buffer.writeln('✓ Original index working: ${verifyResults.length} results returned');
        buffer.writeln('   Top result: "${verifyResults.first.object.title}"');
        buffer.writeln('   Distance: ${verifyResults.first.distance.toStringAsFixed(4)}\n');
      } catch (e) {
        print('🔍 [TEST 24] Search FAILED: $e');
        buffer.writeln('✗ Original index NOT working: $e\n');
      }

      // TEST 25: Edge Case - Index Creation on Non-existent Property
      buffer.writeln('━━━ TEST 25: Edge Case - Index on Non-existent Property ━━━');
      print('🔍 [TEST 25] Starting test for non-existent property index');
      buffer.writeln('Test: Attempt to create index on property that doesn\'t exist\n');

      try {
        print('🔍 [TEST 25] Entering write transaction...');
        realm.write(() {
          print('🔍 [TEST 25] Attempting to create index on "nonexistent" property...');
          buffer.writeln('Attempting to create index on "nonexistent" property...');
          realm.createVectorIndex<Document>(
            'nonexistent',
            metric: VectorDistanceMetric.cosine,
          );
          print('🔍 [TEST 25] UNEXPECTED: Index creation succeeded!');
          buffer.writeln('✗ UNEXPECTED: Index creation succeeded on non-existent property');
        });
      } catch (e) {
        print('🔍 [TEST 25] Expected exception caught: ${e.runtimeType}');
        print('🔍 [TEST 25] Exception message: $e');
        buffer.writeln('✓ Expected behavior: Got exception');
        buffer.writeln('   Error: ${e.toString().split('\n').first}');
        buffer.writeln('   This prevents invalid index creation\n');
      }
      print('🔍 [TEST 25] Test completed\n');

      // TEST 26: Production Migration Pattern - Dimension Change (4D → 6D)
      print('🔍 [TEST 26] ═══════════════════════════════════════════════════════');
      print('🔍 [TEST 26] Starting Production Migration Test (4D → 6D)');
      print('🔍 [TEST 26] ═══════════════════════════════════════════════════════');
      buffer.writeln('━━━ TEST 26: Production Migration - Safe Dimension Change ━━━');
      buffer.writeln('Test: Simulating migration from 4D to 6D vectors WITHOUT data loss\n');
      buffer.writeln('Scenario: App v1 used 4D embeddings, v2 needs 6D embeddings\n');

      // Step 0: Clean up existing 6D index from previous tests
      print('🔍 [TEST 26] STEP 0: Clean up existing 6D state');
      buffer.writeln('STEP 0: Clean up existing state');
      realm.write(() {
        print('🔍 [TEST 26] Checking for existing 6D index...');
        if (realm.hasVectorIndex<Document>('embedding')) {
          print('🔍 [TEST 26] Found existing 6D index, removing...');
          realm.removeVectorIndex<Document>('embedding');
          print('🔍 [TEST 26] 6D index removed successfully');
          buffer.writeln('  • Removed existing 6D index');
        }
        print('🔍 [TEST 26] Deleting all 6D documents...');
        realm.deleteAll<Document>();
        print('🔍 [TEST 26] All documents deleted');
        buffer.writeln('  • Cleared existing 6D data\n');
      });

      // Step 1: Simulate old app state with 4D vectors
      print('🔍 [TEST 26] STEP 1: Setting up initial 4D state');
      buffer.writeln('STEP 1: Initial state (4D vectors)');
      realm.write(() {
        // Add documents with 4D embeddings first
        print('🔍 [TEST 26] Adding 5 documents with 4D embeddings...');
        buffer.writeln('  • Adding 5 documents with 4D embeddings:');
        realm.add(Document('migrate1', 'AI Article', 'Content about AI', embedding: [0.9, 0.8, 0.1, 0.1]));
        print('🔍 [TEST 26]   + migrate1: AI Article [0.9, 0.8, 0.1, 0.1]');
        buffer.writeln('    - AI Article [4D]');
        realm.add(Document('migrate2', 'Nature Guide', 'Forest exploration', embedding: [0.1, 0.2, 0.9, 0.8]));
        print('🔍 [TEST 26]   + migrate2: Nature Guide [0.1, 0.2, 0.9, 0.8]');
        buffer.writeln('    - Nature Guide [4D]');
        realm.add(Document('migrate3', 'Sports News', 'Basketball game', embedding: [0.2, 0.1, 0.1, 0.9]));
        print('🔍 [TEST 26]   + migrate3: Sports News [0.2, 0.1, 0.1, 0.9]');
        buffer.writeln('    - Sports News [4D]');
        realm.add(Document('migrate4', 'Tech Review', 'Gadget analysis', embedding: [0.85, 0.75, 0.15, 0.2]));
        print('🔍 [TEST 26]   + migrate4: Tech Review [0.85, 0.75, 0.15, 0.2]');
        buffer.writeln('    - Tech Review [4D]');
        realm.add(Document('migrate5', 'Travel Blog', 'Mountain hiking', embedding: [0.3, 0.2, 0.8, 0.7]));
        print('🔍 [TEST 26]   + migrate5: Travel Blog [0.3, 0.2, 0.8, 0.7]');
        buffer.writeln('    - Travel Blog [4D]');
        print('🔍 [TEST 26] All 5 documents added');

        // Now create 4D index
        print('🔍 [TEST 26] Creating 4D vector index (M=16, efConstruction=200)...');
        buffer.writeln('  • Creating 4D vector index...');
        realm.createVectorIndex<Document>(
          'embedding',
          metric: VectorDistanceMetric.cosine,
          m: 16,
          efConstruction: 200,
        );
        print('🔍 [TEST 26] 4D index created successfully');
      });

      final stats4D = realm.getVectorIndexStats<Document>('embedding');
      print('🔍 [TEST 26] 4D index stats: numVectors=${stats4D?.numVectors}, maxLayer=${stats4D?.maxLayer}');
      buffer.writeln('  ✓ 4D index created: ${stats4D?.numVectors} vectors, ${stats4D?.maxLayer} layers\n');

      // Verify 4D search works
      print('🔍 [TEST 26] Testing 4D search functionality...');
      buffer.writeln('  • Testing 4D search:');
      final search4D = realm.vectorSearchKnn<Document>(
        'embedding',
        queryVector: [0.9, 0.8, 0.1, 0.1], // Tech query
        k: 2,
      );
      print('🔍 [TEST 26] 4D search returned ${search4D.length} results');
      print('🔍 [TEST 26] Top result: "${search4D.first.object.title}" (distance: ${search4D.first.distance.toStringAsFixed(4)})');
      buffer.writeln('    Top result: "${search4D.first.object.title}" (${search4D.first.distance.toStringAsFixed(4)})\n');

      // Step 2: SAFE MIGRATION - Remove index, transform data, recreate index
      print('🔍 [TEST 26] ─────────────────────────────────────────────────────────');
      print('🔍 [TEST 26] STEP 2: Safe Migration to 6D (NO DATA LOSS)');
      print('🔍 [TEST 26] ─────────────────────────────────────────────────────────');
      buffer.writeln('STEP 2: Safe Migration to 6D (NO DATA LOSS)');
      realm.write(() {
        // Remove old 4D index
        print('🔍 [TEST 26] Removing 4D vector index...');
        buffer.writeln('  • Removing 4D vector index...');
        realm.removeVectorIndex<Document>('embedding');
        print('🔍 [TEST 26] 4D index removed successfully (data should be preserved!)');
        buffer.writeln('    ✓ Index removed (data preserved!)');

        // Verify data still exists
        final docsCount = realm.all<Document>().length;
        print('🔍 [TEST 26] Checking document count after index removal: $docsCount');
        buffer.writeln('    ✓ Data intact: $docsCount documents still present\n');

        // Transform all embeddings from 4D to 6D
        print('🔍 [TEST 26] Transforming embeddings 4D → 6D...');
        buffer.writeln('  • Transforming embeddings 4D → 6D:');
        final allDocs = realm.all<Document>();
        print('🔍 [TEST 26] Found ${allDocs.length} documents to transform');
        for (final doc in allDocs) {
          // Read old values first (important: make a copy before clearing!)
          final old4D = List<double>.from(doc.embedding);
          print('🔍 [TEST 26] Transforming ${doc.id}: [${old4D.join(", ")}] (${old4D.length}D)');

          // Strategy: Pad with domain-specific values (could be zeros, averages, or ML-computed)
          final new6D = [
            old4D[0], // Tech dimension (preserved)
            old4D[1], // Secondary tech (preserved)
            old4D[2], // Nature dimension (preserved)
            old4D[3], // Sports dimension (preserved)
            0.05, // New dimension 5 (cross-domain factor)
            0.05, // New dimension 6 (context factor)
          ];

          // Now clear and add atomically
          doc.embedding.clear();
          doc.embedding.addAll(new6D);

          print('🔍 [TEST 26]          → [${doc.embedding.join(", ")}] (${doc.embedding.length}D)');
          buffer.writeln('    - ${doc.id}: [${old4D.length}D] → [${doc.embedding.length}D]');
        }
        print('🔍 [TEST 26] All ${allDocs.length} documents transformed successfully');
        buffer.writeln('    ✓ All ${allDocs.length} documents transformed\n');

        // Create new 6D index
        print('🔍 [TEST 26] Creating new 6D vector index (M=16, efConstruction=200)...');
        buffer.writeln('  • Creating new 6D vector index...');
        realm.createVectorIndex<Document>(
          'embedding',
          metric: VectorDistanceMetric.cosine,
          m: 16,
          efConstruction: 200,
        );
        print('🔍 [TEST 26] 6D index created successfully');
      });

      final stats6D = realm.getVectorIndexStats<Document>('embedding');
      print('🔍 [TEST 26] 6D index stats: numVectors=${stats6D?.numVectors}, maxLayer=${stats6D?.maxLayer}');
      buffer.writeln('    ✓ 6D index created: ${stats6D?.numVectors} vectors, ${stats6D?.maxLayer} layers\n');

      // Step 3: Verify migration success
      print('🔍 [TEST 26] ─────────────────────────────────────────────────────────');
      print('🔍 [TEST 26] STEP 3: Verification');
      print('🔍 [TEST 26] ─────────────────────────────────────────────────────────');
      buffer.writeln('STEP 3: Verification');

      // Check all data preserved
      final finalDocs = realm.all<Document>();
      print('🔍 [TEST 26] Data integrity check:');
      print('🔍 [TEST 26]   Documents before migration: 5');
      print('🔍 [TEST 26]   Documents after migration: ${finalDocs.length}');
      buffer.writeln('  • Data integrity check:');
      buffer.writeln('    Documents before migration: 5');
      buffer.writeln('    Documents after migration: ${finalDocs.length}');
      if (finalDocs.length == 5) {
        print('🔍 [TEST 26]   ✓ All data preserved!');
      } else {
        print('🔍 [TEST 26]   ✗ ERROR: Data loss detected!');
      }
      buffer.writeln('    ✓ ${finalDocs.length == 5 ? "All data preserved!" : "ERROR: Data loss!"}');

      // Verify all embeddings are now 6D
      print('🔍 [TEST 26] Dimension verification:');
      buffer.writeln('\n  • Dimension verification:');
      var all6D = true;
      for (final doc in finalDocs) {
        final isCorrect = doc.embedding.length == 6;
        print('🔍 [TEST 26]   ${doc.id}: ${doc.embedding.length}D ${isCorrect ? "✓" : "✗"}');
        buffer.writeln('    ${doc.id}: ${doc.embedding.length}D ${isCorrect ? "✓" : "✗"}');
        if (!isCorrect) all6D = false;
      }
      print('🔍 [TEST 26] ${all6D ? "✓ All vectors converted to 6D" : "✗ Some vectors still have wrong dimension"}');
      buffer.writeln('    ${all6D ? "✓ All vectors converted to 6D" : "✗ Some vectors still have wrong dimension"}');

      // Test 6D search works
      print('🔍 [TEST 26] Testing 6D search functionality...');
      buffer.writeln('\n  • Testing 6D search:');
      final search6D = realm.vectorSearchKnn<Document>(
        'embedding',
        queryVector: [0.9, 0.8, 0.1, 0.1, 0.05, 0.05], // Tech query with new dims
        k: 3,
      );
      print('🔍 [TEST 26] 6D search returned ${search6D.length} results:');
      buffer.writeln('    Search returned ${search6D.length} results');
      for (var i = 0; i < search6D.length; i++) {
        print('🔍 [TEST 26]   ${i + 1}. "${search6D[i].object.title}" (dist: ${search6D[i].distance.toStringAsFixed(4)})');
        buffer.writeln('    ${i + 1}. "${search6D[i].object.title}" (dist: ${search6D[i].distance.toStringAsFixed(4)})');
      }

      // Verify semantic relationships preserved
      print('🔍 [TEST 26] Semantic relationship check:');
      buffer.writeln('\n  • Semantic relationship check:');
      final techDoc = search6D.first.object;
      print('🔍 [TEST 26]   Tech query returned: "${techDoc.title}"');
      buffer.writeln('    Tech query returned: "${techDoc.title}"');
      final isDomainCorrect = techDoc.title.contains('AI') || techDoc.title.contains('Tech');
      print('🔍 [TEST 26]   ${isDomainCorrect ? "✓" : "✗"} Correct domain detected');
      buffer.writeln('    ${isDomainCorrect ? "✓" : "✗"} Correct domain detected\n');

      print('🔍 [TEST 26] ═════════════════════════════════════════════════════════');
      print('🔍 [TEST 26] TEST 26 SUMMARY');
      print('🔍 [TEST 26] ═════════════════════════════════════════════════════════');
      print('🔍 [TEST 26] ✓ Migration completed successfully!');
      print('🔍 [TEST 26] ✓ Zero data loss (5 docs → 5 docs)');
      print('🔍 [TEST 26] ✓ All vectors transformed (4D → 6D)');
      print('🔍 [TEST 26] ✓ New index functional');
      print('🔍 [TEST 26] ✓ Search accuracy maintained');
      print('🔍 [TEST 26]');
      print('🔍 [TEST 26] Key Learnings:');
      print('🔍 [TEST 26] 1. removeVectorIndex() DOES NOT delete data');
      print('🔍 [TEST 26] 2. Data transformation can happen while index is removed');
      print('🔍 [TEST 26] 3. Schema changes to OTHER models don\'t affect vector index');
      print('🔍 [TEST 26] 4. Safe pattern: Remove → Transform → Recreate');
      print('🔍 [TEST 26] 5. Production-safe alternative to shouldDeleteIfMigrationNeeded');
      print('🔍 [TEST 26] ═════════════════════════════════════════════════════════\n');

      buffer.writeln('━━━ TEST 26 SUMMARY ━━━');
      buffer.writeln('✓ Migration completed successfully!');
      buffer.writeln('✓ Zero data loss (5 docs → 5 docs)');
      buffer.writeln('✓ All vectors transformed (4D → 6D)');
      buffer.writeln('✓ New index functional');
      buffer.writeln('✓ Search accuracy maintained');
      buffer.writeln('\nKey Learnings:');
      buffer.writeln('1. removeVectorIndex() DOES NOT delete data');
      buffer.writeln('2. Data transformation can happen while index is removed');
      buffer.writeln('3. Schema changes to OTHER models don\'t affect vector index');
      buffer.writeln('4. Safe pattern: Remove → Transform → Recreate');
      buffer.writeln('5. Production-safe alternative to shouldDeleteIfMigrationNeeded\n');

      // SUMMARY
      buffer.writeln('╔════════════════════════════════════════════════════════╗');
      buffer.writeln('║  TEST SUITE SUMMARY                                    ║');
      buffer.writeln('╚════════════════════════════════════════════════════════╝');
      buffer.writeln('✓ All 26 tests completed successfully!');
      buffer.writeln('');
      buffer.writeln('Test Coverage:');
      buffer.writeln('  ✓ Index creation and configuration');
      buffer.writeln('  ✓ Bulk document insertion (20 documents)');
      buffer.writeln('  ✓ Index statistics retrieval');
      buffer.writeln('  ✓ KNN search across different domains');
      buffer.writeln('  ✓ Cross-domain query handling');
      buffer.writeln('  ✓ Radius search with varying thresholds');
      buffer.writeln('  ✓ Edge cases (K=1, K>dataset size)');
      buffer.writeln('  ✓ Performance measurement');
      buffer.writeln('  ✓ Index verification');
      buffer.writeln('  ✓ Filtering by ID patterns');
      buffer.writeln('  ✓ Filtering by title/content keywords');
      buffer.writeln('  ✓ Filtering by distance thresholds');
      buffer.writeln('  ✓ Combined filtering criteria');
      buffer.writeln('  ✓ Realm query integration with vector search');
      buffer.writeln('  ✓ Category exclusion filtering');
      buffer.writeln('  ✓ Top-K per category selection');
      buffer.writeln('  ✓ Similarity score range filtering');
      buffer.writeln('  ✓ Duplicate index creation handling');
      buffer.writeln('  ✓ Invalid property index prevention');
      buffer.writeln('  ✓ Production-safe dimension migration (4D→6D)');
      buffer.writeln('');
      buffer.writeln('Key Findings:');
      buffer.writeln('  • Vector index supports Cosine similarity metric');
      buffer.writeln('  • 6-dimensional embeddings properly indexed');
      buffer.writeln('  • KNN correctly retrieves semantically similar docs');
      buffer.writeln('  • Radius search filters by distance threshold');
      buffer.writeln('  • Cross-domain queries return appropriate hybrids');
      buffer.writeln('  • Edge cases handled gracefully');
      buffer.writeln('  • Flexible filtering: ID, title, content, distance');
      buffer.writeln('  • Realm queries can further refine vector results');
      buffer.writeln('  • Multiple filtering criteria can be combined');
      buffer.writeln('  • Category-based filtering enables targeted results');
      buffer.writeln('');
      buffer.writeln('Production Migration Pattern:');
      buffer.writeln('  • removeVectorIndex() preserves all data (safe!)');
      buffer.writeln('  • Dimension changes: Remove → Transform → Recreate');
      buffer.writeln('  • Schema changes to other models don\'t affect index');
      buffer.writeln('  • No need for shouldDeleteIfMigrationNeeded in production');
    } catch (e, stackTrace) {
      buffer.writeln('\n❌ ERROR in vector search tests:');
      buffer.writeln('Error: $e');
      buffer.writeln('\nStack trace:');
      buffer.writeln('$stackTrace');
    }

    setState(() {
      outputText = buffer.toString();
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Realm Vector Search Demo'),
          backgroundColor: Colors.deepPurple,
        ),
        body: SingleChildScrollView(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Card(
                color: Colors.blue[50],
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Platform: ${Platform.operatingSystem}',
                        style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                      ),
                      SizedBox(height: 8),
                      Text('Cars in Realm: $carsCount'),
                      Text('Documents in Realm: $docsCount'),
                    ],
                  ),
                ),
              ),
              SizedBox(height: 16),
              Container(
                padding: EdgeInsets.all(12),
                decoration: BoxDecoration(
                  color: Colors.grey[100],
                  borderRadius: BorderRadius.circular(8),
                  border: Border.all(color: Colors.grey[300]!),
                ),
                child: SelectableText(
                  outputText,
                  style: TextStyle(fontFamily: 'monospace', fontSize: 12),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
1
likes
155
points
481
downloads

Publisher

unverified uploader

Weekly Downloads

Realm Dart SDK with built-in HNSW vector search - a mobile database with AI/ML vector similarity search capabilities for semantic search.

Repository (GitHub)
View/report issues
Contributing

Documentation

API reference

License

Apache-2.0 (license)

Dependencies

flutter, realm_dart_vector_db

More

Packages that depend on realm_flutter_vector_db

Packages that implement realm_flutter_vector_db