{"id":15069026,"url":"https://github.com/fauna/fauna-jvm","last_synced_at":"2026-02-05T00:37:05.080Z","repository":{"id":252191878,"uuid":"706250316","full_name":"fauna/fauna-jvm","owner":"fauna","description":"JVM driver for Fauna v10","archived":false,"fork":false,"pushed_at":"2025-01-28T15:00:42.000Z","size":2713,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-07-10T23:56:33.328Z","etag":null,"topics":["clients","database","driver","fauna","fauna-db","faunadb","java","java-11","java-17","java-22","jvm","no-sql-databases","nosql","nosql-database","nosql-databases","serverless"],"latest_commit_sha":null,"homepage":"https://fauna.com","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fauna.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-10-17T15:23:39.000Z","updated_at":"2025-01-28T15:00:45.000Z","dependencies_parsed_at":"2024-08-19T13:17:07.681Z","dependency_job_id":"a1eaceff-6532-4d0d-bc0c-9e13f4b94fd8","html_url":"https://github.com/fauna/fauna-jvm","commit_stats":null,"previous_names":["fauna/fauna-jvm"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/fauna/fauna-jvm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fauna%2Ffauna-jvm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fauna%2Ffauna-jvm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fauna%2Ffauna-jvm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fauna%2Ffauna-jvm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fauna","download_url":"https://codeload.github.com/fauna/fauna-jvm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fauna%2Ffauna-jvm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29103421,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-04T22:44:52.815Z","status":"ssl_error","status_checked_at":"2026-02-04T22:44:16.428Z","response_time":62,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clients","database","driver","fauna","fauna-db","faunadb","java","java-11","java-17","java-22","jvm","no-sql-databases","nosql","nosql-database","nosql-databases","serverless"],"created_at":"2024-09-25T01:40:05.253Z","updated_at":"2026-02-05T00:37:05.044Z","avatar_url":"https://github.com/fauna.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Official JVM Driver for [Fauna v10](https://fauna.com) (current)\n\nThe Fauna JVM driver is a lightweight, open-source wrapper for Fauna's [HTTP\nAPI](https://docs.fauna.com/fauna/current/reference/http/reference/). You can\nuse the driver to run FQL queries and get results from a Java application.\n\nSee the [Fauna docs](https://docs.fauna.com/fauna/current/) for\nadditional information on how to configure and query your databases.\n\nThis driver can only be used with FQL v10 and is not compatible with earlier\nversions of FQL. To query your databases with earlier API versions, use the\n[faunadb-jvm](https://github.com/fauna/faunadb-jvm) driver.\n\n\n## Requirements\n\n- Java 11 or later\n\n\n## API reference\n\nAPI reference documentation for the driver is available at\nhttps://fauna.github.io/fauna-jvm/. The docs are generated using Javadoc.\n\n\n## Installation\n\nThe driver is available on the [Maven central\nrepository](https://central.sonatype.com/artifact/com.fauna/fauna-jvm).\nYou can add the driver to your Java project using Gradle or Maven.\n\n\n### Gradle\n\nFile `build.gradle`:\n```\ndependencies {\n    ...\n    implementation \"com.fauna:fauna-jvm:X.Y.Z\"\n    ...\n}\n```\n\n\n### Maven\n\nFile `fauna-java/pom.xml`:\n```xml\n\u003cdependencies\u003e\n    ...\n    \u003cdependency\u003e\n      \u003cgroupId\u003ecom.fauna\u003c/groupId\u003e\n      \u003cartifactId\u003efauna-jvm\u003c/artifactId\u003e\n      \u003cversion\u003eX.Y.Z\u003c/version\u003e\n    \u003c/dependency\u003e\n    ...\n\u003c/dependencies\u003e\n```\n\n\n## Basic usage\n\nThe following application:\n\n* Initializes a client instance to connect to Fauna.\n* Composes a basic FQL query using an FQL template.\n* Runs the query using `query()` and `asyncQuery()`.\n\n```java\npackage org.example;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\n\nimport com.fauna.client.Fauna;\nimport com.fauna.client.FaunaClient;\nimport com.fauna.exception.FaunaException;\nimport com.fauna.query.builder.Query;\nimport com.fauna.response.QuerySuccess;\nimport com.fauna.types.Page;\n\nimport static com.fauna.codec.Generic.pageOf;\nimport static com.fauna.query.builder.Query.fql;\n\n\npublic class App {\n\n    // Define class for `Product` documents\n    // in expected results.\n    public static class Product {\n        public String name;\n\n        public String description;\n\n        public Integer price;\n    }\n\n    public static void main(String[] args) {\n        try {\n            // Initialize a default client.\n            // It will get the secret from the $FAUNA_SECRET environment variable.\n            FaunaClient client = Fauna.client();\n\n            // Compose a query.\n            Query query = fql(\"\"\"\n                Product.sortedByPriceLowToHigh() {\n                    name,\n                    description,\n                    price\n                }\n            \"\"\");\n\n            // Run the query synchronously.\n            System.out.println(\"Running synchronous query:\");\n            runSynchronousQuery(client, query);\n\n            // Run the query asynchronously.\n            System.out.println(\"\\nRunning asynchronous query:\");\n            runAsynchronousQuery(client, query);\n        } catch (FaunaException e) {\n            System.err.println(\"Fauna error occurred: \" + e.getMessage());\n            e.printStackTrace();\n        } catch (InterruptedException | ExecutionException e) {\n            e.printStackTrace();\n        }\n    }\n\n\n    private static void runSynchronousQuery(FaunaClient client, Query query) throws FaunaException {\n        // Use `query()` to run a synchronous query.\n        // Synchronous queries block the current thread until the query completes.\n        // Accepts the query, expected result class, and a nullable set of query options.\n        QuerySuccess\u003cPage\u003cProduct\u003e\u003e result = client.query(query, pageOf(Product.class));\n        printResults(result.getData());\n    }\n\n    private static void runAsynchronousQuery(FaunaClient client, Query query) throws ExecutionException, InterruptedException {\n        // Use `asyncQuery()` to run an asynchronous, non-blocking query.\n        // Accepts the query, expected result class, and a nullable set of query options.\n        CompletableFuture\u003cQuerySuccess\u003cPage\u003cProduct\u003e\u003e\u003e futureResult = client.asyncQuery(query, pageOf(Product.class));\n\n        QuerySuccess\u003cPage\u003cProduct\u003e\u003e result = futureResult.get();\n        printResults(result.getData());\n    }\n\n    // Iterate through the products in the page.\n    private static void printResults(Page\u003cProduct\u003e page) {\n        for (Product product : page.getData()) {\n            System.out.println(\"Name: \" + product.name);\n            System.out.println(\"Description: \" + product.description);\n            System.out.println(\"Price: \" + product.price);\n            System.out.println(\"--------\");\n        }\n        // Print the `after` cursor to paginate through results.\n        System.out.println(\"After: \" + page.getAfter());\n    }\n}\n```\n\n\n## Connect to Fauna\n\nTo send query requests to Fauna, initialize a `FaunaClient` instance with a\nFauna authentication secret. You can pass the secret in a `FaunaConfig` object:\n\n```java\nFaunaConfig config = FaunaConfig.builder().secret(\"FAUNA_SECRET\").build();\n\n\nFaunaClient client = Fauna.client(config);\n```\n\nIf not specified, `secret` defaults to the `FAUNA_SECRET` environment variable.\nFor example:\n\n```java\n// Defaults to the secret in the `FAUNA_SECRET` env var.\nFaunaClient client = Fauna.client();\n```\n\nThe client comes with a helper config for connecting to Fauna running locally.\n\n```java\n// Connects to Fauna running locally via Docker (http://localhost:8443 and secret \"secret\").\nFaunaClient local = Fauna.local();\n```\n\n\n### Scoped client\nYou can scope a client to a specific database (and role).\n\n```java\nFaunaClient db1 = Fauna.scoped(client, FaunaScope.builder(\"Database1\").build());\n\nFaunaScope scope2 = FaunaScope.builder(\"Database2\").withRole(FaunaRole.named(\"MyRole\")).build();\nFaunaClient db2 = Fauna.scoped(client, scope2);\n```\n\n\n### Multiple connections\n\nYou can use a single client instance to run multiple asynchronous queries at\nonce. The driver manages HTTP connections as needed. Your app doesn't need to\nimplement connection pools or other connection management strategies.\n\nYou can create multiple client instances to connect to Fauna using different\nsecrets or client configurations.\n\n\n## Run FQL queries\n\nUse `fql` templates to compose FQL queries. To run the query, pass the template\nand an expected result class to `query()` or `asyncQuery()`:\n\n```java\nQuery query = fql(\"Product.sortedByPriceLowToHigh()\");\nQuerySuccess\u003cPage\u003cProduct\u003e\u003e result = client.query(query, pageOf(Product.class));\n```\n\nYou can also pass a nullable set of [query options](#query-options) to `query()`\nor `asyncQuery()`. These options control how the query runs in Fauna. See [Query\noptions](#query-options).\n\n\n### Define a custom class for your data\n\nUse annotations to map a Java class to a Fauna document or object shape:\n\n```java\nimport com.fauna.annotation.FaunaField;\nimport com.fauna.annotation.FaunaId;\n\nclass Person {\n\n    @FaunaId\n    private String id;\n\n    private String firstName;\n\n    @FaunaField( name = \"dob\")\n    private String dateOfBirth;\n}\n```\n\nYou can use the `com.fauna.annotation` package to modify encoding and decoding of\nspecific fields in classes used as arguments and results of queries.\n* `@FaunaId`: Should only be used once per class and be associated with a field named `id` that represents the Fauna document ID. It's not encoded unless the `isClientGenerated` flag is `true`.\n* `@FaunaTs`: Should only be used once per class and be associated with a field named `ts` that represents the timestamp of a document. It's not encoded.\n* `@FaunaColl`: Typically goes unmodeled. Should only be used once per class and be associated with a field named `coll` that represents the collection field of a document. It will never be encoded.\n* `@FaunaField`: Can be associated with any field to override its name in Fauna.\n* `@FaunaIgnore`: Can be used to ignore fields during encoding and decoding.\n\nUse classes in the `com.fauna.codec` package to handle type erasure when the top-level result\nof a query is a generic, including:\n* `PageOf\u003cT\u003e` where `T` is the element type.\n* `ListOf\u003cT\u003e` where `T` is the element type.\n* `MapOf\u003cT\u003e` where `T` is the value type.\n* `OptionalOf\u003cT\u003e` where `T` is the value type.\n* `NullableDocumentOf\u003cT\u003e` where `T` is the value type. This is specifically for cases when you return a Fauna document that may be null and want to receive a concrete `NullDocument\u003cT\u003e` or `NonNullDocument\u003cT\u003e` instead of catching a `NullDocumentException`.\n\n### Variable interpolation\n\nUse `${}` to pass native Java variables to FQL. You can escape a variable by\nprepending an additional `$`.\n\n```java\n// Create a native Java var.\nvar collectionName = \"Product\";\n\n// Pass the var to an FQL query.\nQuery query = fql(\"\"\"\n    let collection = Collection(${collectionName})\n    collection.sortedByPriceLowToHigh()\n    \"\"\",\n    Map.of(\n        \"collectionName\", collectionName\n    ));\n```\n\nPassed variables are encoded to an appropriate type and passed to Fauna's HTTP\nAPI. This helps prevent injection attacks.\n\n\u003c!-- TODO: Subqueries --\u003e\n\n## Pagination\nUse `paginate()` to asynchronously iterate through sets that contain more than one page of results.\n\n`paginate()` accepts the same [query options](#query-options) as `query()` and `asyncQuery()`.\n\n```java\nimport com.fauna.client.Fauna;\nimport com.fauna.client.FaunaClient;\nimport com.fauna.client.PageIterator;\n\npublic class App {\n    public static void main(String[] args) {\n        FaunaClient client = Fauna.client();\n\n        // `paginate()` will make an async request to Fauna.\n        PageIterator\u003cProduct\u003e iter1 = client.paginate(fql(\"Product.all()\"), Product.class);\n\n        // Handle each page. `PageIterator` extends the Java Iterator interface.\n        while (iter1.hasNext()) {\n            Page\u003cProduct\u003e page = iter1.next();\n            List\u003cProduct\u003e pageData = page.data();\n            // Do something with your data.\n        }\n\n        PageIterator\u003cProduct\u003e iter2 = client.paginate(fql(\"Product.all()\"), Product.class);\n\n        // Use the `flatten()` on PageIterator to iterate over every item in a set.\n        Iterator\u003cProduct\u003e productIter = iter2.flatten();\n        List\u003cProduct\u003e products = new ArrayList\u003c\u003e();\n\n        // Iterate over Product elements without worrying about pages.\n        iter2.forEachRemaining((Product p) -\u003e products.add(p));\n    }\n}\n```\n\n## Query statistics\n\nSuccessful query responses and `ServiceException` exceptions include query\nstatistics:\n\n```java\npackage org.example;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\n\nimport com.fauna.client.Fauna;\nimport com.fauna.client.FaunaClient;\nimport com.fauna.exception.FaunaException;\nimport com.fauna.exception.ServiceException;\nimport com.fauna.query.builder.Query;\nimport static com.fauna.query.builder.Query.fql;\nimport com.fauna.response.QueryResponse;\nimport com.fauna.response.QuerySuccess;\n\npublic class App {\n    public static void main(String[] args) {\n        try {\n            FaunaClient client = Fauna.client();\n\n            Query query = fql(\"'Hello world'\");\n\n            CompletableFuture\u003cQuerySuccess\u003cString\u003e\u003e futureResponse = client.asyncQuery(query, String.class);\n\n            QueryResponse response = futureResponse.get();\n\n            System.out.println(response.getStats().toString());\n\n        } catch (FaunaException e) {\n            if (e instanceof ServiceException) {\n                ServiceException serviceException = (ServiceException) e;\n                System.out.println(serviceException.getStats().toString());\n            }\n            System.out.println(e);\n        } catch (InterruptedException | ExecutionException e) {\n            e.printStackTrace();\n        }\n    }\n}\n```\n\n\n## Client configuration\n\nYou can pass a `FaunaConfig` object to customize the configuration of a\n`FaunaClient` instance.\n\n```java\nFaunaConfig config = new FaunaConfig.Builder()\n        .secret(\"FAUNA_SECRET\")\n        .build();\n\nFaunaClient client = Fauna.client(config);\n```\n\n\n### Environment variables\n\nBy default, `secret` and `endpoint` default to the respective `FAUNA_SECRET` and\n`FAUNA_ENDPOINT` environment variables.\n\nFor example, if you set the following environment variables:\n\n```sh\nexport FAUNA_SECRET=FAUNA_SECRET\nexport FAUNA_ENDPOINT=https://db.fauna.com/\n```\n\nYou can initialize the client with a default configuration:\n\n```java\nFaunaClient client = Fauna.client();\n```\n\n\n### Retries\n\nThe client automatically retries queries that receive a response with 429 HTTP\nstatus code. The client will retry a query up to 4 times, including the original\nquery request. Retries use an exponential backoff.\n\n\n## Query options\n\nYou can pass a `QueryOptions` object to `query()` or `asyncQuery()` to control\nhow a query runs in Fauna. You can also use query options to instrument\na query for monitoring and debugging.\n\n```java\nQuery query = Query.fql(\"Hello World\");\n\nQueryOptions options = QueryOptions.builder()\n    .linearized(true)\n    .queryTags(Map.of(\"tag\", \"value\"))\n    .timeout(Duration.ofSeconds(10))\n    .traceParent(\"00-750efa5fb6a131eb2cf4db39f28366cb-000000000000000b-00\")\n    .typeCheck(false)\n    .build();\n\nQuerySuccess result = client.query(query, String.class, options);\n```\n\n## Event feeds\n\nThe driver supports [event feeds](https://docs.fauna.com/fauna/current/learn/cdc/#event-feeds).\n\n### Request an event feed\n\nAn event feed asynchronously polls an [event\nsource](https://docs.fauna.com/fauna/current/learn/cdc/#create-an-event-source)\nfor paginated events.\n\nTo get an event source, append\n[`eventSource()`](https://docs.fauna.com/fauna/current/reference/fql-api/schema-entities/set/eventsource/)\nor\n[`eventsOn()`](https://docs.fauna.com/fauna/current/reference/fql-api/schema-entities/set/eventson/)\nto a [supported Set](https://docs.fauna.com/fauna/current/reference/cdc/#sets).\n\nTo get an event feed, you can use one of the following methods:\n\n* `feed()`: Synchronously fetches an event feed and returns a `FeedIterator`\n   that you can use to iterate through the pages of events.\n\n* `asyncFeed()`: Asynchronously fetches an event feed and returns a\n   `CompletableFuture\u003cFeedIterator\u003e` that you can use to iterate through the\n   pages of events.\n\n* `poll()`: Asynchronously fetches a single page of events from the event feed\n   and returns a `CompletableFuture\u003cFeedPage\u003e` that you can use to handle each\n   page individually. You can repeatedly call `poll()` to get successive pages.\n\nYou can use `flatten()` on a `FeedIterator` to iterate through events rather\nthan pages.\n\n```java\nimport com.fauna.client.Fauna;\nimport com.fauna.client.FaunaClient;\nimport com.fauna.event.FeedIterator;\nimport com.fauna.event.EventSource;\nimport com.fauna.event.FeedOptions;\nimport com.fauna.event.FeedPage;\nimport com.fauna.event.EventSource;\nimport com.fauna.response.QuerySuccess;\nimport com.fauna.event.FaunaEvent;\n\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.concurrent.CompletableFuture;\n\nimport static com.fauna.query.builder.Query.fql;\n\n// Import the Product class for event data.\nimport org.example.Product;\n\npublic class EventFeedExample {\n    private static void printEventDetails(FaunaEvent\u003cProduct\u003e event) {\n        System.out.println(\"Event Details:\");\n        System.out.println(\"  Type: \" + event.getType());\n        System.out.println(\"  Cursor: \" + event.getCursor());\n\n        event.getTimestamp().ifPresent(ts -\u003e\n            System.out.println(\"  Timestamp: \" + ts)\n        );\n\n        event.getData().ifPresent(product -\u003e\n            System.out.println(\"  Product: \" + product.toString())\n        );\n\n        if (event.getStats() != null) {\n            System.out.println(\"  Stats: \" + event.getStats());\n        }\n\n        if (event.getError() != null) {\n            System.out.println(\"  Error: \" + event.getError());\n        }\n\n        System.out.println(\"-------------------\");\n    }\n\n    public static void main(String[] args) {\n        FaunaClient client = Fauna.client();\n\n        long tenMinutesAgo = System.currentTimeMillis() * 1000 - (10 * 60 * 1000 * 1000);\n        FeedOptions options = FeedOptions.builder()\n                .startTs(tenMinutesAgo)\n                .pageSize(10)\n                .build();\n\n        // Example 1: Using `feed()`\n        FeedIterator\u003cProduct\u003e syncIterator = client.feed(\n            fql(\"Product.all().eventsOn(.price, .stock)\"),\n            options,\n            Product.class\n        );\n\n        System.out.println(\"----------------------\");\n        System.out.println(\"`feed()` results:\");\n        System.out.println(\"----------------------\");\n        syncIterator.forEachRemaining(page -\u003e {\n            for (FaunaEvent\u003cProduct\u003e event : page.getEvents()) {\n                printEventDetails(event);\n            }\n        });\n\n        // Example 2: Using `asyncFeed()`\n        CompletableFuture\u003cFeedIterator\u003cProduct\u003e\u003e iteratorFuture = client.asyncFeed(\n            fql(\"Product.all().eventsOn(.price, .stock)\"),\n            options,\n            Product.class\n        );\n\n        FeedIterator\u003cProduct\u003e iterator = iteratorFuture.join();\n        System.out.println(\"----------------------\");\n        System.out.println(\"`asyncFeed()` results:\");\n        System.out.println(\"----------------------\");\n        iterator.forEachRemaining(page -\u003e {\n            for (FaunaEvent\u003cProduct\u003e event : page.getEvents()) {\n                printEventDetails(event);\n            }\n        });\n\n        // Example 3: Using `flatten()` on a `FeedIterator`\n        FeedIterator\u003cProduct\u003e flattenedIterator = client.feed(\n            fql(\"Product.all().eventSource()\"),\n            options,\n            Product.class\n        );\n\n        Iterator\u003cFaunaEvent\u003cProduct\u003e\u003e eventIterator = flattenedIterator.flatten();\n        List\u003cFaunaEvent\u003cProduct\u003e\u003e allEvents = new ArrayList\u003c\u003e();\n        eventIterator.forEachRemaining(allEvents::add);\n        System.out.println(\"----------------------\");\n        System.out.println(\"`flatten()` results:\");\n        System.out.println(\"----------------------\");\n        for (FaunaEvent\u003cProduct\u003e event : allEvents) {\n            printEventDetails(event);\n        }\n\n        // Example 4: Using `poll()`\n        QuerySuccess\u003cEventSource\u003e sourceQuery = client.query(\n            fql(\"Product.all().eventSource()\"),\n            EventSource.class\n        );\n        EventSource source = EventSource.fromResponse(sourceQuery.getData());\n\n        CompletableFuture\u003cFeedPage\u003cProduct\u003e\u003e pageFuture = client.poll(\n            source,\n            options,\n            Product.class\n        );\n\n        while (pageFuture != null) {\n            FeedPage\u003cProduct\u003e page = pageFuture.join();\n            List\u003cFaunaEvent\u003cProduct\u003e\u003e events = page.getEvents();\n\n            System.out.println(\"----------------------\");\n            System.out.println(\"`poll()` results:\");\n            System.out.println(\"----------------------\");\n            for (FaunaEvent\u003cProduct\u003e event : events) {\n                printEventDetails(event);\n            }\n\n            if (page.hasNext()) {\n                FeedOptions nextPageOptions = options.nextPage(page);\n                pageFuture = client.poll(source, nextPageOptions, Product.class);\n            } else {\n                pageFuture = null;\n            }\n        }\n    }\n}\n```\n\nIf you pass an event source directly to `feed()` or `poll()` and changes occur\nbetween the creation of the event source and the event feed request, the feed\nreplays and emits any related events.\n\nIn most cases, you'll get events after a specific start time or cursor.\n\n### Get events after a specific start time\n\nWhen you first poll an event source using an event feed, you usually include a\n`startTs` (start timestamp) in the `FeedOptions` passed to `feed()`,\n`asyncFeed()`, or `poll()`.\n\n`startTs` is an integer representing a time in microseconds since the Unix\nepoch. The request returns events that occurred after the specified timestamp\n(exclusive).\n\n```java\nQuery query = fql(\"Product.all().eventsOn(.price, .stock)\");\n\n// Calculate the timestamp for 10 minutes ago in microseconds.\nlong tenMinutesAgo = System.currentTimeMillis() * 1000 - (10 * 60 * 1000 * 1000);\n\nFeedOptions options = FeedOptions.builder()\n        .startTs(tenMinutesAgo)\n        .pageSize(10)\n        .build();\n\n// Example 1: Using `feed()`\nFeedIterator\u003cProduct\u003e syncIterator = client.feed(\n    query,\n    options,\n    Product.class\n);\n\n// Example 2: Using `asyncFeed()`\nCompletableFuture\u003cFeedIterator\u003cProduct\u003e\u003e iteratorFuture = client.asyncFeed(\n    query,\n    options,\n    Product.class\n);\n\n// Example 3: Using `poll()`\nQuerySuccess\u003cEventSource\u003e sourceQuery = client.query(\n    query,\n    EventSource.class\n);\nEventSource source = EventSource.fromResponse(sourceQuery.getData());\n\nCompletableFuture\u003cFeedPage\u003cProduct\u003e\u003e pageFuture = client.poll(\n    source,\n    options,\n    Product.class\n);\n```\n\n### Get events after a specific event cursor\n\nAfter the initial request, you usually get subsequent events using the cursor\nfor the last page or event. To get events after a cursor (exclusive), include\nthe cursor in the `FeedOptions` passed to passed to `feed()`,\n`asyncFeed()`, or `poll()`.\n\n```java\nQuery query = fql(\"Product.all().eventsOn(.price, .stock)\");\n\nFeedOptions options = FeedOptions.builder()\n        .cursor(\"gsGabc456\") // Cursor for the last page\n        .pageSize(10)\n        .build();\n\n// Example 1: Using `feed()`\nFeedIterator\u003cProduct\u003e syncIterator = client.feed(\n    query,\n    options,\n    Product.class\n);\n\n// Example 2: Using `asyncFeed()`\nCompletableFuture\u003cFeedIterator\u003cProduct\u003e\u003e iteratorFuture = client.asyncFeed(\n    query,\n    options,\n    Product.class\n);\n\n// Example 3: Using `poll()`\nQuerySuccess\u003cEventSource\u003e sourceQuery = client.query(\n    query,\n    EventSource.class\n);\nEventSource source = EventSource.fromResponse(sourceQuery.getData());\n\nCompletableFuture\u003cFeedPage\u003cProduct\u003e\u003e pageFuture = client.poll(\n    source,\n    options,\n    Product.class\n);\n```\n\n### Error handling\n\nExceptions can be raised in two different places:\n\n* While fetching a page\n* While iterating a page's events\n\nThis distinction lets ignore errors originating from event processing. For\nexample:\n\n```java\ntry {\n    FeedIterator\u003cProduct\u003e syncIterator = client.feed(\n        fql(\"Product.all().map(.details.toUpperCase()).eventSource()\"),\n        options,\n        Product.class\n    );\n\n    syncIterator.forEachRemaining(page -\u003e {\n        try {\n            for (FaunaEvent\u003cProduct\u003e event : page.getEvents()) {\n                // Event-specific handling.\n                System.out.println(\"Event: \" + event);\n            }\n        } catch (FaunaException e) {\n            // Handle errors for specific events within the page.\n            System.err.println(\"Error processing event: \" + e.getMessage());\n        }\n    });\n\n} catch (FaunaException e) {\n    // Additional handling for initialization errors.\n    System.err.println(\"Error occurred with event feed initialization: \" + e.getMessage());\n}\n```\n\n## Event streams\n\nThe driver supports [event\nstreams](https://docs.fauna.com/fauna/current/learn/cdc/#event-streaming).\n\nAn event stream lets you consume events from an [event\nsource](https://docs.fauna.com/fauna/current/learn/cdc/#create-an-event-source)\nas a real-time subscription.\n\nTo get an event source, append\n[`eventSource()`](https://docs.fauna.com/fauna/current/reference/reference/schema_entities/set/eventsource)\nor\n[`eventsOn()`](https://docs.fauna.com/fauna/current/reference/reference/schema_entities/set/eventson)\nto a [supported Set](https://docs.fauna.com/fauna/current/reference/cdc/#sets).\n\nTo start and subscribe to the stream, pass an `EventSource` and related\n`StreamOptions` to `stream()` or `asyncStream()`:\n\n```java\n// Get an event source.\nQuery query = fql(\"Product.all().eventSource() { name, stock }\");\nQuerySuccess\u003cEventSource\u003e tokenResponse = client.query(query, EventSource.class);\nEventSource eventSource = EventSource.fromResponse(querySuccess.getData());\n\n// Calculate the timestamp for 10 minutes ago in microseconds.\nlong tenMinutesAgo = System.currentTimeMillis() * 1000 - (10 * 60 * 1000 * 1000);\nStreamOptions streamOptions = StreamOptions.builder().startTimestamp(tenMinutesAgo).build();\n\n// Example 1: Using `stream()`\nFaunaStream\u003cProduct\u003e stream = client.stream(eventSource, streamOptions, Product.class);\n\n// Example 2: Using `asyncStream()`\nCompletableFuture\u003cFaunaStream\u003cProduct\u003e\u003e futureStream = client.asyncStream(source, streamOptions, Product.class);\n```\n\nIf changes occur between the creation of the event source and the stream\nrequest, the stream replays and emits any related events.\n\nAlternatively, you can pass an FQL query that returns an event source to `stream()` or\n`asyncStream()`:\n\n```java\nQuery query = fql(\"Product.all().eventSource() { name, stock }\");\n\n// Example 1: Using `stream()`\nFaunaStream\u003cProduct\u003e stream = client.stream(query, Product.class);\n\n// Example 2: Using `asyncStream()`\nCompletableFuture\u003cFaunaStream\u003cProduct\u003e\u003e futureStream = client.asyncStream(query, Product.class);\n```\n\n### Create a subscriber class\n\nThe methods return a\n[`FaunaStream`](https://fauna.github.io/fauna-jvm/latest/com/fauna/client/FaunaStream.html)\npublisher that lets you handle events as they arrive. Create a class with the\n`Flow.Subscriber` interface to process events:\n\n```java\npackage org.example;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.Flow;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport com.fauna.client.Fauna;\nimport com.fauna.client.FaunaClient;\nimport com.fauna.client.FaunaConfig;\nimport com.fauna.event.FaunaEvent;\nimport com.fauna.event.FaunaStream;\nimport com.fauna.exception.FaunaException;\n\nimport static com.fauna.query.builder.Query.fql;\n\n// Import the Product class for event data.\nimport org.example.Product;\n\npublic class EventStreamExample {\n    public static void main(String[] args) throws InterruptedException {\n        try {\n            FaunaConfig config = FaunaConfig.builder()\n                    .secret(\"FAUNA_SECRET\")\n                    .build();\n            FaunaClient client = Fauna.client(config);\n\n            // Create a stream of all products. Project the name and stock.\n            FaunaStream\u003cProduct\u003e stream = client.stream(fql(\"Product.all().eventSource() { name, stock }\"), Product.class);\n\n            // Create a subscriber to handle stream events.\n            ProductSubscriber subscriber = new ProductSubscriber();\n            stream.subscribe(subscriber);\n\n            // Wait for the subscriber to complete.\n            subscriber.awaitCompletion();\n        } catch (FaunaException e) {\n            System.err.println(\"Fauna error occurred: \" + e.getMessage());\n            e.printStackTrace();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n    static class ProductSubscriber implements Flow.Subscriber\u003cFaunaEvent\u003cProduct\u003e\u003e {\n        private final AtomicInteger eventCount = new AtomicInteger(0);\n        private Flow.Subscription subscription;\n        private final int maxEvents;\n        private final CountDownLatch completionLatch = new CountDownLatch(1);\n\n        public ProductSubscriber() {\n            // Stream closes after 3 events.\n            this.maxEvents = 3;\n        }\n\n        @Override\n        public void onSubscribe(Flow.Subscription subscription) {\n            this.subscription = subscription;\n            subscription.request(1);\n        }\n\n        @Override\n        public void onNext(FaunaEvent\u003cProduct\u003e event) {\n            // Handle each event...\n            int count = eventCount.incrementAndGet();\n            System.out.println(\"Received event \" + count + \":\");\n            System.out.println(\"  Type: \" + event.getType());\n            System.out.println(\"  Cursor: \" + event.getCursor());\n            System.out.println(\"  Timestamp: \" + event.getTimestamp());\n            System.out.println(\"  Data: \" + event.getData().orElse(null));\n\n            if (count \u003e= maxEvents) {\n                System.out.println(\"Closing stream after \" + maxEvents + \" events\");\n                subscription.cancel();\n                completionLatch.countDown();\n            } else {\n                subscription.request(1);\n            }\n        }\n\n        @Override\n        public void onError(Throwable throwable) {\n            System.err.println(\"Error in stream: \" + throwable.getMessage());\n            completionLatch.countDown();\n        }\n\n        @Override\n        public void onComplete() {\n            System.out.println(\"Stream completed.\");\n            completionLatch.countDown();\n        }\n\n        public int getEventCount() {\n            return eventCount.get();\n        }\n\n        public void awaitCompletion() throws InterruptedException {\n            completionLatch.await();\n        }\n    }\n}\n```\n\n## Debugging / Tracing\nIf you would like to see the requests and responses the client is making and receiving, you can set the environment\nvariable `FAUNA_DEBUG=1`. Fauna log the request and response (including headers) to `stderr`. You can also pass in your\nown log handler. Setting `Level.WARNING` is equivalent to `FAUNA_DEBUG=0`, while `Level.FINE` is equivalent to\n`FAUNA_DEBUG=1`. The client will log the request body at `Level.FINEST`.\n\n```java\nimport java.util.logging.ConsoleHandler;\nimport java.util.logging.Handler;\nimport java.util.logging.Level;\nimport java.util.logging.SimpleFormatter;\n\nimport com.fauna.client.Fauna;\nimport com.fauna.client.FaunaClient;\n\nclass App {\n    public static void main(String[] args) {\n        Handler handler = new ConsoleHandler();\n        handler.setLevel(Level.FINEST);\n        handler.setFormatter(new SimpleFormatter());\n        FaunaClient client = Fauna.client(FaunaConfig.builder().logHandler(handler).build());\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffauna%2Ffauna-jvm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffauna%2Ffauna-jvm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffauna%2Ffauna-jvm/lists"}