### Create Enterprise Environment Instance (C#) Source: https://jinaga.net/documents/linq/defining-a-starting-point Constructs an 'Environment' object using a pre-defined user's public key and the environment name. This serves as the starting point for queries in an enterprise context. ```csharp var environment = new Environment(new User(publicKey), environmentName); ``` -------------------------------- ### Install Jinaga Tool CLI Source: https://jinaga.net/documents/building-applications/define-authorization-rules This command installs the Jinaga command-line tool globally using the .NET CLI. This tool is necessary for deploying authorization rules to a hosted replicator. ```bash dotnet tool install -g Jinaga.Tool ``` -------------------------------- ### Query Customer Buyers in Environment for User (C#) Source: https://jinaga.net/documents/linq/defining-a-starting-point Defines a Jinaga specification that starts from two facts: an 'Environment' and a 'User'. It queries for 'CustomerBuyer' facts where the customer belongs to the specified environment and the buyer matches the provided user. ```csharp var customerBuyersInEnvironmentForUser = Given.Match((environment, user, facts) => from buyer in facts.OfType() where buyer.customer.environment == environment where buyer.buyer == user select buyer); ``` -------------------------------- ### Query Customers in Environment (C#) Source: https://jinaga.net/documents/linq/defining-a-starting-point Defines a Jinaga specification to retrieve all 'Customer' facts associated with a given 'Environment'. This query starts from the 'Environment' fact and looks for matching successors. ```csharp var customersInEnvironment = Given.Match((environment, facts) => from customer in facts.OfType() where customer.environment == environment select customer); ``` -------------------------------- ### Query Albums by User (C#) Source: https://jinaga.net/documents/linq/defining-a-starting-point Defines a Jinaga specification to query for all 'Album' facts created by a specific 'User'. This is an example of querying successors starting from a user fact. It uses LINQ-like syntax for defining the query. ```csharp var albumbsByUser = Given.Match((user, facts) => from album in facts.OfType() where album.creator == user select album); ``` -------------------------------- ### Install Jinaga Server NPM Package Source: https://jinaga.net/documents/replicator Command to install the Jinaga Server package using npm. This is a prerequisite for running the Replicator within a Node.js application. ```bash npm install jinaga-server ``` -------------------------------- ### Login and Retrieve User and Profile (C#) Source: https://jinaga.net/documents/linq/defining-a-starting-point Retrieves the currently logged-in user and their associated profile information. This is a common starting point for personal applications. It returns a tuple containing the user fact and the profile object. ```csharp var (user, profile) = await jinagaClient.Login(); ``` -------------------------------- ### Install jinaga-export-postgres Globally using npm Source: https://jinaga.net/documents/exporting-facts/exporting-from-postgres This command installs the jinaga-export-postgres tool globally on your system using npm. This allows you to use the `jinaga-export-postgres` command directly from your terminal without needing to prefix it with `npx`. ```bash npm install -g jinaga-export-postgres ``` -------------------------------- ### Factual File Example - Jinaga Blog Site Source: https://jinaga.net/documents/exporting-facts/factual-file-format Illustrates the Factual file format with a concrete example of creating facts for a blog site, a blog post, and its title. This includes defining fields and predecessors. ```javascript let f1: Blog.Site = { domain: "example.com" } let f2: Blog.Post = { createdAt: "2023-05-20T10:30:00Z", site: f1 } let f3: Blog.Post.Title = { post: f2, value: "My First Blog Post", prior: [] } ``` -------------------------------- ### Initialize Jinaga Client with In-Memory Store (C#) Source: https://jinaga.net/documents/building-applications/configure-jinaga Creates a Jinaga client with an in-memory store. This is a basic setup for initial development and testing. It requires the IServiceProvider to resolve dependencies. ```csharp public static class JinagaConfig { public static JinagaClient CreateJinagaClient(IServiceProvider services) { return JinagaClient.Create(opt => { // Configuration options will go here }); } } ``` -------------------------------- ### Deploy Jinaga Replicator using Docker Source: https://jinaga.net/documents/replicator Commands to pull the Jinaga Replicator Docker image, create a container, and start it. This method is suitable for deploying a replicator on your own infrastructure. ```bash docker pull jinaga/jinaga-replicator docker create --name my-replicator -p8080:8080 jinaga/jinaga-replicator docker start my-replicator ``` -------------------------------- ### Import Previous Notebook Source: https://jinaga.net/documents/modeling/setting-up-your-notebook This code block imports the content of a previously created notebook, typically used to load package references and namespace imports from a setup notebook. ```plaintext #!import "../0-setup/Packages.ipynb" ``` -------------------------------- ### Create JinagaClient - No Configuration Source: https://jinaga.net/documents/reference/jinaga-client Creates a new instance of JinagaClient without any persistent storage or network connection. This is a basic client setup for testing or offline scenarios. ```csharp static JinagaClient Create() { // Implementation details not shown } ``` -------------------------------- ### Log In User and Get Profile - Jinaga Client Source: https://jinaga.net/documents/modeling/top-level-facts/log-in Initiates the login process to retrieve the logged-in user fact and their associated profile information. This is the starting point for interacting with the Jinaga model. ```csharp // Login returns the user fact and profile information var (user, profile) = await jinagaClient.Login(); ``` -------------------------------- ### Start New Jinaga Replicator Container with Migrated Data Source: https://jinaga.net/documents/replicator/upgrading This sequence pulls the latest Jinaga replicator image, creates a new container named 'my-replicator', maps port 8080, mounts the new 'my-replicator-db' volume to '/var/lib/postgresql/data' (where the database resides), and then starts the container. ```bash docker pull jinaga/jinaga-replicator:latest docker create --name my-replicator \ -p8080:8080 \ -v my-replicator-db:/var/lib/postgresql/data \ jinaga/jinaga-replicator docker start my-replicator ``` -------------------------------- ### Example Jinaga Fact JSON Data Source: https://jinaga.net/documents/exporting-facts/json-file-format An example of a JSON file containing an array of Jinaga fact objects. This illustrates the structure for 'Blog.Site', 'Blog.Post', and 'Blog.Post.Title' facts, including their predecessors and fields. ```json [ { "hash": "SV3Yseb0FJ/uQoL4IelHHbo1g4PZjnP4bx+aivMiiCkSTn2vSaNR6314KXL+PgO9lX9jmJzWoZABTRHjiFHWdQ==", "type": "Blog.Site", "predecessors": {}, "fields": { "domain": "example.com" } }, { "hash": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6", "type": "Blog.Post", "predecessors": { "site": { "hash": "SV3Yseb0FJ/uQoL4IelHHbo1g4PZjnP4bx+aivMiiCkSTn2vSaNR6314KXL+PgO9lX9jmJzWoZABTRHjiFHWdQ==", "type": "Blog.Site" } }, "fields": { "createdAt": "2023-05-20T10:30:00Z" } }, { "hash": "z6y5x4w3v2u1t0s9r8q7p6o5n4m3l2k1j0i9h8g7f6e5d4c3b2a1", "type": "Blog.Post.Title", "predecessors": { "post": { "hash": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6", "type": "Blog.Post" } }, "fields": { "value": "My First Blog Post", "prior": [] } } ] ``` -------------------------------- ### Define Enterprise Environment Constants (C#) Source: https://jinaga.net/documents/linq/defining-a-starting-point Sets up constants for the public key of a pre-defined user and the environment name. These are typically stored in configuration and loaded on application startup for enterprise applications. ```csharp var publicKey = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzZ"; var environmentName = "Production"; ``` -------------------------------- ### Example: Export Data to JSON Format Source: https://jinaga.net/documents/exporting-facts/exporting-from-postgres This example demonstrates how to use the `jinaga-export-postgres` tool to export data in JSON format. It specifies connection details for a local PostgreSQL database and directs the output to a file named `output.json` using shell redirection. ```bash npx jinaga-export-postgres --host localhost --port 5432 --database mydb --user myuser --password mypassword --format json > output.json ``` -------------------------------- ### Example: Export Data to Factual Format Source: https://jinaga.net/documents/exporting-facts/exporting-from-postgres This example shows how to export data in the 'factual' format using the `jinaga-export-postgres` tool. It connects to a specified PostgreSQL database and saves the exported data to a file named `output.fact`. ```bash npx jinaga-export-postgres --host localhost --port 5432 --database mydb --user myuser --password mypassword --format factual > output.fact ``` -------------------------------- ### Initialize Replicator with Jinaga Fact Language Example Source: https://jinaga.net/documents/replicator/write This snippet demonstrates how to initialize the Jinaga Replicator with data using the Jinaga fact language. It shows the declaration of a site fact, followed by a post fact referencing the site, and then two title facts for the post, illustrating predecessor relationships and arrays. ```jinaga let site: Blog.Site = { domain: "qedcode.com" } let post: Blog.Post = { createdAt: "2022-08-16T15:23:13.231Z", site } let title: Blog.Post.Title = { post, value: "Introducing Jinaga Replicator", prior: [] } let title2: Blog.Post.Title = { post, value: "Introduction to the Jinaga Replicator", prior: [ title ] } ``` -------------------------------- ### Create and Manage an Observer with Jinaga's Watch Method Source: https://jinaga.net/documents/building-applications/create-a-view-model Illustrates the process of setting up an observer using Jinaga's `Watch` method. This method takes a specification, a starting point, and a projection lambda. The lambda is executed when new results are available and returns a cleanup function for when the result is removed. It handles adding new view models to the `Sites` collection and updating their properties based on changes in the projection's observable lists. ```csharp private IObserver? observer; public void Load() { // Define the specification var sitesByUser = Given.Match((user, facts) => //... ); Sites.Clear(); observer = jinagaClient.Watch(sitesByUser, user, projection => { var siteHeaderViewModel = new SiteHeaderViewModel(projection.site); Sites.Add(siteHeaderViewModel); projection.names.OnAdded(name => { siteHeaderViewModel.Name = name; }); projection.domains.OnAdded(domain => { siteHeaderViewModel.Domain = domain; }); return () => { Sites.Remove(siteHeaderViewModel); }; }); } ``` -------------------------------- ### Create Jinaga Replicator Server in Node.js Source: https://jinaga.net/documents/replicator Node.js code to create and start a Jinaga Replicator server using the 'jinaga-server' package. It configures the Express application, sets up HTTP server, and connects to a PostgreSQL database. ```typescript import express = require("express"); import * as http from "http"; import { JinagaServer } from "jinaga-server"; import process = require("process"); process.on('SIGINT', () => { console.log("\n\nStopping replicator\n"); process.exit(0); }); const app = express(); const server = http.createServer(app); app.set('port', process.env.PORT || 8080); app.use(express.json()); app.use(express.text()); const pgConnection = process.env.JINAGA_POSTGRESQL || 'postgresql://appuser:apppw@localhost:5432/appdb'; const { handler } = JinagaServer.create({ pgStore: pgConnection }); app.use('/jinaga', handler); server.listen(app.get('port'), () => { console.log(` Replicator is running at http://localhost:${app.get('port')} in ${app.get('env')} mode`); console.log(' Press CTRL-C to stop\n'); }); ``` -------------------------------- ### Subscribe to Real-time Changes Source: https://jinaga.net/documents/reference/jinaga-client Establishes a persistent connection to a remote replicator to receive real-time updates. It subscribes to changes based on a specification and a starting point. ```csharp IObserver Subscribe( Specification specification, TFact given, Action added) where TFact : class { // Implementation details not shown } ``` -------------------------------- ### Jinaga Specification Language Example for Reading Blog Posts Source: https://jinaga.net/documents/replicator/read This code snippet demonstrates a complete Jinaga specification for reading blog posts. It defines input facts, a specification body to filter posts, and projections to shape the output, including nested projections for titles. This is used with the /read endpoint for testing replicator data. ```jinaga let site: Blog.Site = { domain: "qedcode.com" } (site: Blog.Site) { post: Blog.Post [ post->site: Blog.Site = site !E { deleted: Blog.Post.Deleted [ deleted->post: Blog.Post = post ] } ] } => { id = #post createdAt = post.createdAt titles = { title: Blog.Post.Title [ title->post: Blog.Post = post !E { next: Blog.Post.Title [ next->prior: Blog.Post.Title = title ] } ] } => title.value } ``` -------------------------------- ### Handle Loading Status and Errors - C# Source: https://jinaga.net/documents/building-applications/indicate-app-state This example shows how to manage the application's busy state and indicate loading errors based on `IsLoading` and `LastLoadError` properties from the `JinagaStatus`. It provides a mechanism to set different statuses like 'Yellow' for errors and 'Green' for success. ```csharp private void JinagaClient_OnStatusChanged(JinagaStatus status) { Busy = status.IsLoading || status.IsSaving; if ( ... ) { // Indicate saving errors } else if (status.LastLoadError != null) { // The client has experienced an error on load. Status = "Yellow"; Error = status.LastLoadError.GetMessage(); } else { Status = "Green"; Error = string.Empty; } } ``` -------------------------------- ### Query Facts Source: https://jinaga.net/documents/reference/jinaga-client Retrieves results for a given specification from the local cache or upstream. It takes a specification, a starting point, and an optional cancellation token. ```csharp Task> Query( Specification specification, TFact given, CancellationToken cancellationToken = default) where TFact : class { // Implementation details not shown } ``` -------------------------------- ### Configure httpYac for Jinaga Portal Replicator Source: https://jinaga.net/documents/replicator Example .env.local file configuration for httpYac when connecting to a Jinaga Portal replicator. Includes settings for replicator URL, OAuth2 endpoints, and authentication secrets. ```dotenv replicatorUrl=https://rep.jinaga.com/xyz123 oauth2_authorizationEndpoint=https://rep.jinaga.com/xyz123/auth/apple oauth2_tokenEndpoint=https://rep.jinaga.com/xyz123/auth/token oauth2_clientId=xyz123 oauth2_usePkce=true authorizationEndpoint=https://app.jinaga.com/xyz123/authorization distributionEndpoint=https://app.jinaga.com/xyz123/distribution secret=zyx321 ``` -------------------------------- ### Simplify Jinaga Predecessor Declaration Source: https://jinaga.net/documents/replicator/write This example shows a simplified syntax for declaring a predecessor when the predecessor fact's variable name matches the field name. It achieves the same result as explicitly assigning `site: site` but is more concise. ```jinaga let post: Blog.Post = { createdAt: "2022-08-16T15:23:13.231Z", site } ``` -------------------------------- ### Configure httpYac for Docker/NPM Replicator Source: https://jinaga.net/documents/replicator Example .env.local file configuration for httpYac when connecting to a Replicator deployed via Docker or NPM package. Sets the replicator URL to localhost. ```dotenv replicatorUrl=http://localhost:8080/jinaga ``` -------------------------------- ### Declare a Jinaga Fact Source: https://jinaga.net/documents/replicator/write This example shows the basic syntax for declaring a fact in the Jinaga fact language. It defines a `Blog.Site` fact with a `domain` field, illustrating the structure of a simple fact declaration. ```jinaga let site: Blog.Site = { domain: "qedcode.com" } ``` -------------------------------- ### Create Fact Instance - C# Source: https://jinaga.net/documents/concepts/facts This code demonstrates how to create and save a new fact instance of the `Project` type asynchronously using the `j.Fact` method. It generates a new GUID for the project ID. ```csharp Project projectA = await j.Fact(new Project(user, Guid.NewGuid())); ``` -------------------------------- ### Import Models and Client Notebooks Source: https://jinaga.net/documents/modeling/setting-up-your-notebook This code block imports both the model definitions from a '1-models' notebook and the Jinaga client initialization from a '0-setup' notebook. This is common in scenario notebooks to set up the environment for testing or demonstrating fact instances. ```plaintext #!import "../1-models/YourModel.ipynb" #!import "../0-setup/Client.ipynb" ``` -------------------------------- ### Reference Jinaga NuGet Packages Source: https://jinaga.net/documents/modeling/setting-up-your-notebook This code block demonstrates how to reference the necessary Jinaga NuGet packages within a Polyglot Notebook. These are essential for utilizing Jinaga's features and modeling tools. ```csharp // Reference the Jinaga NuGet packages #r "nuget: Jinaga" #r "nuget: Jinaga.Notebooks" #r "nuget: Jinaga.UnitTest" ``` -------------------------------- ### Initialize Jinaga Test Client Source: https://jinaga.net/documents/modeling/setting-up-your-notebook This code block initializes a Jinaga client specifically configured for unit testing. It includes simulating a logged-in user, which is often required for testing Jinaga applications. ```csharp // Create a Jinaga client for unit testing var jinagaClient = JinagaTest.Create(opt => { // Simulate a logged in user opt.User = new User("--- FAKE USER ---"); }); ``` -------------------------------- ### Query Posts within a Site Source: https://jinaga.net/documents/modeling/hierarchy/child-objects Defines a Jinaga query specification to retrieve all 'Post' facts associated with a given 'Site'. The result is a list of posts, and the example shows how to get the count of these posts. ```csharp var postsInSite = Given.Match((site, facts) => from post in facts.OfType() where post.site == site select post); var posts = await jinagaClient.Query(postsInSite, site); posts.Count() ``` -------------------------------- ### JinagaClient Creation Source: https://jinaga.net/documents/reference/jinaga-client Methods for creating and configuring a JinagaClient instance. ```APIDOC ## JinagaClient Create (static) ### Description Creates a Jinaga client with no persistent storage or network connection. ### Method `static JinagaClient Create() ` ### Returns: * A new instance of `JinagaClient`. --- ## JinagaClient Create with Configuration (static) ### Description Creates a Jinaga client using the provided configuration. The configuration action is used to set properties on the `JinagaClientOptions` object. ### Method `static JinagaClient Create(Action configure) ` ### Parameters: * `configure`: Lambda function that sets properties on the `JinagaClientOptions` object. ### Returns: * A new instance of `JinagaClient`. ``` -------------------------------- ### Import Jinaga Namespaces Source: https://jinaga.net/documents/modeling/setting-up-your-notebook This code block shows how to import the core Jinaga namespaces into your notebook. This allows you to use Jinaga's classes and functions directly without fully qualifying them. ```csharp using Jinaga; using Jinaga.Notebooks; using Jinaga.UnitTest; ``` -------------------------------- ### Create JinagaClient - With Configuration Source: https://jinaga.net/documents/reference/jinaga-client Creates a JinagaClient instance using provided configuration options. A lambda function is used to customize the JinagaClientOptions. ```csharp static JinagaClient Create(Action configure) { // Implementation details not shown } ``` -------------------------------- ### Set up PostgreSQL Database for Jinaga Replicator using Docker Source: https://jinaga.net/documents/replicator Docker commands to pull and run a pre-configured PostgreSQL database for the Jinaga Replicator. This includes setting environment variables for database credentials. ```bash docker pull jinaga/jinaga-postgres-fact-keystore docker create --name jinaga-postgres -p5432:5432 \ -e POSTGRES_PASSWORD=secretpw \ -e APP_USERNAME=appuser \ -e APP_PASSWORD=apppw \ -e APP_DATABASE=appdb \ jinaga/jinaga-postgres-fact-keystore docker start jinaga-postgres ``` -------------------------------- ### Get Jinaga Authentication State (C#) Source: https://jinaga.net/documents/reference/jinaga-status Retrieves the current authentication state of the Jinaga client. This property is read-only and returns a JinagaAuthenticationState enum. ```csharp JinagaAuthenticationState AuthenticationState { get; } ``` -------------------------------- ### Print Authorization Rules to File Source: https://jinaga.net/documents/building-applications/define-authorization-rules This command writes the authorization rules from a specified assembly to a file named authorization.txt. This is used when running your own replicator instead of a hosted one. ```bash dotnet jinaga print authorization {assembly} > authorization.txt ``` -------------------------------- ### Get Jinaga Saving Status (C#) Source: https://jinaga.net/documents/reference/jinaga-status Retrieves a boolean indicating if the Jinaga client is currently saving facts to the remote replicator. This property is read-only. ```csharp bool IsSaving { get; } ``` -------------------------------- ### Get Jinaga Loading Status (C#) Source: https://jinaga.net/documents/reference/jinaga-status Retrieves a boolean indicating if the Jinaga client is currently loading facts from the remote replicator. This property is read-only. ```csharp bool IsLoading { get; } ``` -------------------------------- ### Get Jinaga Save Queue Length (C#) Source: https://jinaga.net/documents/reference/jinaga-status Retrieves the number of facts currently waiting in the queue to be saved to the remote replicator. This property is read-only and an integer value. ```csharp int QueueLength { get; } ``` -------------------------------- ### Create Post Publish Fact Source: https://jinaga.net/documents/modeling/workflow/steps Demonstrates creating and saving a 'PostPublish' fact using the Jinaga client. This involves instantiating the fact with relevant data and then rendering it. ```csharp var post1Publish0 = await jinagaClient.Fact(new PostPublish(post1, postTitle1, postContent1, [])); jinagaClient.RenderFacts(post1Publish0) ``` -------------------------------- ### Get Jinaga Last Save Error (C#) Source: https://jinaga.net/documents/reference/jinaga-status Retrieves the last exception that occurred during the fact saving process to the remote replicator. This property is read-only and may be null if no error has occurred. ```csharp Exception LastSaveError { get; } ``` -------------------------------- ### Create Jinaga Test Client in C# Source: https://jinaga.net/documents/concepts Illustrates how to create a Jinaga client for use in unit tests, utilizing an in-memory store. This is useful for testing Jinaga logic without the overhead of a persistent database. It requires specifying a test user. ```csharp JinagaClient j = JinagaTest.Create(options => { options.User = new User("--- TEST USER ---"); }); ``` -------------------------------- ### Get Jinaga Last Load Error (C#) Source: https://jinaga.net/documents/reference/jinaga-status Retrieves the last exception that occurred during the fact loading process from the remote replicator. This property is read-only and may be null if no error has occurred. ```csharp Exception LastLoadError { get; } ``` -------------------------------- ### Logger Factory Configuration for JinagaClient Source: https://jinaga.net/documents/reference/jinaga-client-options Configures the logging behavior for the Jinaga client. If no LoggerFactory is provided, logging is disabled by default. This property accepts an ILoggerFactory instance for custom logging setup. ```csharp ILoggerFactory LoggerFactory { get; set; } ``` -------------------------------- ### Data Synchronization and Management Source: https://jinaga.net/documents/reference/jinaga-client Methods for pushing data, unloading, and managing local storage. ```APIDOC ## Push ### Description Sends any facts in the queue to the replicator. ### Method `Task Push(CancellationToken cancellationToken) ` ### Parameters: * `cancellationToken`: To cancel the operation. ### Returns: * Resolved when the queue has been emptied. --- ## Unload ### Description Waits for any background processes to stop. ### Method `Task Unload() ` ### Returns: * Resolved when all background processes are finished. --- ## DisposeAsync ### Description Disposes of resources asynchronously. ### Method `ValueTask DisposeAsync() ` ### Returns: * A task representing the asynchronous dispose operation. --- ## Local ### Description Operate on the local store without making a network connection. When the `Local` property is used, all fact operations are handled locally without any attempt to sync with a remote server or replicator. This mode is useful when you want to work entirely offline or avoid network overhead. ### Property `LocalJinagaClient Local { get; } ` ``` -------------------------------- ### Register Authentication Components in MauiProgram (C#) Source: https://jinaga.net/documents/building-applications/configure-jinaga Registers the authentication settings, WebAuthenticator, and Jinaga authentication services in the .NET MAUI application. This setup is necessary for enabling user authentication in the application. ```csharp builder.Services.AddSingleton(JinagaConfig.CreateAuthenticationSettings); builder.Services.AddSingleton(WebAuthenticator.Default); builder.Services.AddJinagaAuthentication(); ``` -------------------------------- ### IObserver Methods Source: https://jinaga.net/documents/reference/iobserver Details about the methods of the IObserver interface, including 'Refresh' and 'Stop'. ```APIDOC ## IObserver Methods ### Refresh #### Description Checks the replicator for new facts and updates the observer with any changes. #### Parameters: * `cancellationToken` (CancellationToken?) - Optional: A `CancellationToken` to cancel the operation if needed. #### Returns: * `Task` - A `Task` that is completed once the observer has been updated with new facts from the replicator. ### Stop #### Description Stops updating the results and removes the observer. Call this method when unloading a view model or when the observer is no longer needed. #### Returns: * `void` ``` -------------------------------- ### Monitor Observer Progress with Cached and Loaded Tasks Source: https://jinaga.net/documents/building-applications/create-a-view-model Provides a method `Monitor` that demonstrates how to track the progress of an observer. It utilizes the `Cached` and `Loaded` tasks of the `IObserver` to determine when data is available locally and from the replicator, respectively. Error handling is included, and loading states are managed using observable properties. ```csharp [ObservableProperty] private bool loading = false; [ObservableProperty] private string error = string.Empty; private async void Monitor(IObserver observer) { try { Loading = true; bool wasInCache = await observer.Cached; if (!wasInCache) { await observer.Loaded; } Error = string.Empty; } catch (Exception ex) { Error = ex.Message; } finally { Loading = false; } } ``` -------------------------------- ### Login User and Get Profile - C# Source: https://jinaga.net/documents/concepts/facts This code snippet demonstrates how to log in a user and retrieve their profile using the Jinaga library. It is an asynchronous operation that returns the user and their profile upon successful login. ```csharp (User user, UserProfile profile) = await j.Login(); ``` -------------------------------- ### Create an Observable Collection for View Models Source: https://jinaga.net/documents/building-applications/create-a-view-model Shows how to create an `ObservableCollection` to hold multiple view model instances. This collection is used to store and manage a list of `SiteHeaderViewModel` objects, enabling the UI to react to additions and removals from this list. ```csharp public ObservableCollection Sites { get; } = new(); ``` -------------------------------- ### Create and Render Site Domain Fact Source: https://jinaga.net/documents/modeling/entities/additional-mutable-properties Shows how to create a new 'SiteDomain' fact using a Jinaga client and then render it along with another fact, 'siteName2'. This illustrates the process of adding new data and making it available for querying. ```csharp var siteDomain0 = await jinagaClient.Fact(new SiteDomain(site, "example.com", [])); jinagaClient.RenderFacts(siteDomain0, siteName2) ``` -------------------------------- ### Retrieve Current Site Name Value - C# Source: https://jinaga.net/documents/modeling/entities/mutable-properties Retrieves the value of the current site name after querying for it. This example assumes that the previous query returns a single result, and extracts the 'value' property from that result. ```csharp names.Single().value ``` -------------------------------- ### Share Site Names with Creator (C#) Source: https://jinaga.net/documents/building-applications/define-distribution-rules This C# snippet demonstrates how to share specific data, like site names, with the creator of a site. It uses the `Share` and `With` methods to define a specification and grant access to the site's creator. ```csharp // Distribute site names to the site creator. .Share(Given.Match((site, facts) => from name in facts.OfType() where name.site == site && !facts.Any(next => next.prior.Contains(name)) select name )).With(site => site.creator) ``` -------------------------------- ### Create Jinaga SQLite Client in C# Source: https://jinaga.net/documents/concepts Demonstrates how to create a Jinaga client configured to use an SQLite database for local data persistence. It shows how to set the HTTP endpoint for the Jinaga replicator and specify the path for the SQLite database file. ```csharp JinagaClient j = JinagaSQLiteClient.Create(options => { // Connect to the Jinaga replicator that you host yourself, or that we host for you. options.HttpEndpoint = new Uri("https://rep.jinaga.com/myreplicator"); // Use the SQLite store to persist data locally. options.SQLitePath = System.IO.Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "jinaga", "myapplication.sqlite" ); }); ``` -------------------------------- ### Query Projects Created by a User in Jinaga (C#) Source: https://jinaga.net/documents/concepts/predecessors This C# code snippet demonstrates how to query for all 'Project' facts that were created by a given 'User' using Jinaga's 'Successors' extension method. It first creates a couple of projects and then defines a query specification to retrieve them. ```csharp using Jinaga.Extensions; // Create a couple more projects. Project projectB = await j.Fact(new Project(user, Guid.NewGuid())); Project projectC = await j.Fact(new Project(user, Guid.NewGuid())); var projectsCreatedByUser = Given.Match(u => u.Successors().OfType(p => p.creator) ); ImmutableList projects = await j.Query(projectsCreatedByUser, user); ``` -------------------------------- ### Inspect and Get Old Replicator Volume Name Source: https://jinaga.net/documents/replicator/upgrading This command inspects the 'my-old-replicator' container to find the name of the managed volume used for its Postgres database. This volume name (a hexadecimal string) is crucial for copying data to a new volume. ```bash docker inspect -f '{{ (index .Mounts 0).Name }}' my-old-replicator ``` -------------------------------- ### Jinaga Existential Condition Example Source: https://jinaga.net/documents/replicator/read This Jinaga code demonstrates an existential condition, specifically a negative existential (!E). It checks for the non-existence of related facts, in this case, a deleted post record. This is used to filter out posts that have been marked as deleted. ```jinaga !E { deleted: Blog.Post.Deleted [ deleted->post: Blog.Post = post ] } ``` -------------------------------- ### Query Successors with LINQ - C# Source: https://jinaga.net/documents/modeling/top-level-facts/query-for-successors This code snippet defines a Jinaga specification to find all 'Site' facts created by a given 'User'. It uses `Given.Match()` to set up the query and `OfType()` to filter facts from the repository. The `jinagaClient.Query` method is then used to execute the specification against the fact repository. ```csharp // The parameters to the lambda are the given fact (in this case, the user) and // the fact repository. Use the OfType method to get facts from the repository. var sitesByUser = Given.Match((user, facts) => from site in facts.OfType() where site.creator == user select site); // Query for facts matching the specification. var sites = await jinagaClient.Query(sitesByUser, user); jinagaClient.RenderFacts(sites) ``` -------------------------------- ### Valid Jinaga Specification: Filtering by Fact Relationship Source: https://jinaga.net/documents/linq/limitations Presents a valid Jinaga specification that correctly filters query results by establishing a relationship between facts. This example defines a `Term` fact and links `Offering` facts to it, allowing filtering based on the `Term` fact itself. ```csharp [FactType("Term")] public record Term(School school, string name); [FactType("Offering")] public record Offering(Term term, Course course); // This is a valid specification. var offeringsInTerm = Given.Match((term, facts) => from offering in facts.OfType() where offering.term == term select offering); // First recreate the term fact to use as a query parameter. var term = new Term(school, "Fall 2024"); // Then query for facts matching the specification. var offerings = await jinagaClient.Query(offeringsInTerm, term); ``` -------------------------------- ### Authorize Post Creation with Guest Bloggers in C# Source: https://jinaga.net/documents/building-applications/define-authorization-rules This C# snippet demonstrates how to define a Type rule for creating 'Post' facts. It uses a LINQ query with two parameters (the fact and the fact repository) to authorize users who are guest bloggers associated with the same site as the post. ```csharp .Type((post, facts) => from guestBlogger in facts.OfType() where guestBlogger.site == post.site from user in facts.OfType() where user == guestBlogger.guest select user ) ``` -------------------------------- ### Jinaga Specification Body - Relating Facts Source: https://jinaga.net/documents/replicator/read This example illustrates the specification body in Jinaga, where unknowns are declared and related to givens or other unknowns using conditions. It shows how to define an unknown fact and specify conditions to filter it, such as following a path to a predecessor. ```jinaga post: Blog.Post [ post->site: Blog.Site = site ] ``` -------------------------------- ### Jinaga Projection Example - Selecting Fields Source: https://jinaga.net/documents/replicator/read This Jinaga projection demonstrates how to reshape the results of a specification. It selects specific fields from the matched facts, such as 'id' and 'createdAt', to create a more focused output. This projection is applied after the specification body has matched the desired tuples. ```jinaga => { id = #post createdAt = post.createdAt } ``` -------------------------------- ### Deploy Distribution Rules (Bash) Source: https://jinaga.net/documents/building-applications/define-distribution-rules This command deploys distribution rules to a hosted Jinaga replicator. It requires the path to the assembly containing JinagaConfig, the replicator's endpoint, and a secret for authentication. ```bash dotnet jinaga deploy distribution {assembly} {endpoint} {secret} ``` -------------------------------- ### Jinaga Projection Example - Nested Specification Source: https://jinaga.net/documents/replicator/read This Jinaga code showcases a projection that includes a child specification. It defines a 'titles' field which itself runs a sub-specification to retrieve related 'Blog.Post.Title' facts and projects their values. This allows for building complex JSON structures from related data. ```jinaga titles = { title: Blog.Post.Title [ title->post: Blog.Post = post !E { next: Blog.Post.Title [ next->prior: Blog.Post.Title = title ] } ] } => title.value ``` -------------------------------- ### Create Jinaga Authentication Settings (C#) Source: https://jinaga.net/documents/building-applications/configure-jinaga Defines the settings required for authenticating with a Jinaga replicator using OAuth providers like Google and Apple. This includes URLs for authentication, token revocation, callback, client ID, scope, and a callback for updating user names. ```csharp public static AuthenticationSettings CreateAuthenticationSettings(IServiceProvider services) { var settings = new Settings(); var authUrlByProvider = ImmutableDictionary.Empty; authUrlByProvider = authUrlByProvider.Add("Apple", settings.AppleAuthUrl); authUrlByProvider = authUrlByProvider.Add("Google", settings.GoogleAuthUrl); var authenticationSettings = new AuthenticationSettings( authUrlByProvider, settings.AccessTokenUrl, settings.RevokeUrl, settings.CallbackUrl, settings.ClientId, settings.Scope, UpdateUserName); return authenticationSettings; } private static async Task UpdateUserName(JinagaClient jinagaClient, User user, UserProfile profile) { // Called when the user logs in so that the app can record the user's name. } ``` -------------------------------- ### Create and Render Post Facts Source: https://jinaga.net/documents/modeling/hierarchy/child-objects Demonstrates creating two 'Post' facts with distinct timestamps and then rendering them using the Jinaga client. This is a foundational step for adding new posts to the system. ```csharp var post0 = await jinagaClient.Fact(new Post(site, user, DateTime.UtcNow)); var post1 = await jinagaClient.Fact(new Post(site, user, DateTime.UtcNow)); jinagaClient.RenderFacts(post0, post1) ``` -------------------------------- ### Define Tree View Specification in C# Source: https://jinaga.net/documents/modeling/hierarchy/tree-view Defines a Jinaga specification to query sites and their associated posts, including names and domains. This specification is designed to be extended for hierarchical display, starting from a User and drilling down into Site and Post details. It filters out deleted items by checking for subsequent restoration events. ```csharp var sitesAndPostsByUser = Given.Match((user, facts) => from site in facts.OfType() where site.creator == user where !facts.Any( sd => sd.site == site && !facts.Any(sr => sr.deleted == sd)) select new { Site = site, Names = from name in facts.OfType() where name.site == site where !facts.Any(next => next.prior.Contains(name)) select name.value, Domains = from domain in facts.OfType() where domain.site == site where !facts.Any(next => next.prior.Contains(domain)) select domain.value, Posts = from post in facts.OfType() where post.site == site where !facts.Any(pd => pd.post == post && !facts.Any(pr => pr.deleted == pd)) select new { Post = post, Title = from title in facts.OfType() where title.post == post where !facts.Any(next => next.prior.Contains(title)) select title.value }); var sitesAndPosts = await jinagaClient.Query(sitesAndPostsByUser, user); sitesAndPosts ``` -------------------------------- ### Deploy Authorization Rules to Hosted Replicator Source: https://jinaga.net/documents/building-applications/define-authorization-rules This command deploys authorization rules to a hosted Jinaga replicator. It requires the assembly path, replicator endpoint, and secret as parameters. ```bash dotnet jinaga deploy authorization {assembly} {endpoint} {secret} ``` -------------------------------- ### Configure Jinaga Authentication Provider (C#) Source: https://jinaga.net/documents/building-applications/configure-jinaga Sets the HTTP authentication provider for the Jinaga client, enabling users to log in with existing Google or Apple accounts. Requires an IHttpAuthenticationProvider implementation to be registered in the service provider. ```csharp return JinagaClient.Create(opt => { opt.HttpAuthenticationProvider = services.GetRequiredService(); }); ``` -------------------------------- ### Define Jinaga Settings Structure (C#) Source: https://jinaga.net/documents/building-applications/define-settings This snippet defines the structure of settings for a Jinaga mobile application using a C# partial class. It outlines the properties and includes comments guiding developers on how to create a local settings file. This approach ensures that sensitive local configurations are not committed to source control. ```csharp public partial class Settings { // Create a file named Settings.Local.cs // Set the properties in the Settings constructor // Do not check Settings.Local.cs into source control // For example: /* partial class Settings { public Settings() { ReplicatorUrl = "https://repdev.jinaga.com/xxxXXXXxxxyyyyYYYyyy"; AppleAuthUrl = "..."; ... } } */ public string? ReplicatorUrl { get; } public string? AppleAuthUrl { get; } public string? GoogleAuthUrl { get; } public string? AccessTokenUrl { get; } public string? RevokeUrl { get; } public string? ClientId { get; } public string Scope { get; } = "profile read write"; public string CallbackUrl { get; } = "blogmaui://callback"; } ``` -------------------------------- ### Query and ViewModel for Visitor Posts - C# Source: https://jinaga.net/documents/modeling/workflow/captured-versions This snippet illustrates how to query posts for visitors and construct their ViewModel. Visitors see the content based on the `Publish` fact, ensuring they always see the officially published version. ```csharp publishedPosts = await jinagaClient.Query(publishedPostsInSite, site); var publishedPostsViewModel = publishedPosts.Select(p => new { Title = p.Title, Content = p.Content }); publishedPostsViewModel ``` -------------------------------- ### Create ViewModel from Jinaga Projection Results Source: https://jinaga.net/documents/modeling/entities/projections This C# snippet demonstrates how to transform the results of a Jinaga query into a view model. It takes the `sites` collection, which contains site information and a collection of names, and creates a new anonymous object with a single `Name` property. It uses `FirstOrDefault` to get the first name or defaults to 'New site' if no names are found. ```csharp var sitesViewModel = sites.Select(s => new { Name = s.Names.FirstOrDefault() ?? "New site" }); sitesViewModel ``` -------------------------------- ### Query Sites by User (LINQ) - Jinaga Source: https://jinaga.net/documents/building-applications/query-facts This snippet demonstrates querying for all 'Site' facts created by a specific user using LINQ query syntax in Jinaga. It utilizes 'Given.Match' to define the context and filters facts of type 'Site' where the creator matches the given user. ```csharp var sitesByUser = Given.Match((user, facts) => from site in facts.OfType() where site.creator == user select site ); ``` -------------------------------- ### Print Distribution Rules to File (Bash) Source: https://jinaga.net/documents/building-applications/define-distribution-rules This command prints the distribution rules to a text file, which is useful when running a self-hosted Jinaga replicator. It requires the path to the assembly containing the JinagaConfig class. ```bash dotnet jinaga print distribution {assembly} > distribution.txt ``` -------------------------------- ### Alternate Specification for Published Posts Source: https://jinaga.net/documents/modeling/workflow/steps An alternative Jinaga specification designed to return one result per published post, even if multiple titles or contents exist. It projects collections of titles and contents within the result. ```csharp var publishedPostsInSiteAlternate = Given.Match((site, facts) => from publish in facts.OfType() where publish.post.site == site where !facts.Any(next => next.prior.Contains(publish)) from post in facts.OfType() where post == publish.post select new { Post = post, Titles = from title in facts.OfType() where title == publish.title select title.value, Contents = ``` -------------------------------- ### Create Initial Project Name Fact (C#) Source: https://jinaga.net/documents/concepts/mutable-properties Creates the first 'ProjectName' fact for a given project, initializing it with a value and an empty 'prior' array, signifying no previous name. ```csharp ProjectName projectAName1 = await j.Fact(new ProjectName(projectA, "Cheyenne Expansion", [])); ``` -------------------------------- ### Query Posts in All Sites (Method Syntax) - Jinaga Source: https://jinaga.net/documents/building-applications/query-facts This snippet shows how to query for 'Post' facts across all sites created by a user using method syntax in Jinaga. It uses chained 'OfType()', 'Where()', and 'SelectMany()' with nested 'OfType()' and 'Where()' clauses to achieve the result. ```csharp var postsInAllSites = Given.Match((user, facts) => facts.OfType() .Where(site => site.creator == user && !facts.Any(deleted => deleted.site == site && !facts.Any(restored => restored.deleted == deleted))) .SelectMany(site => facts.OfType() .Where(post => post.site == site && !facts.Any(deleted => deleted.post == post && !facts.Any(restored => restored.deleted == deleted)))) ); ``` -------------------------------- ### Query Posts in All Sites (LINQ) - Jinaga Source: https://jinaga.net/documents/building-applications/query-facts This snippet demonstrates querying for all 'Post' facts across all sites created by a user, using LINQ query syntax. It combines filtering for sites and then filtering for posts within those sites, while also handling deleted and restored posts. ```csharp var postsInAllSites = Given.Match((user, facts) => from site in facts.OfType() where site.creator == user && !facts.Any(deleted => deleted.site == site && !facts.Any(restored => restored.deleted == deleted) ) from post in facts.OfType() where post.site == site && !facts.Any(deleted => deleted.post == post && !facts.Any(restored => restored.deleted == deleted) ) select post ); ```