diff --git a/src/current/_includes/example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml b/src/current/_includes/example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml new file mode 100644 index 00000000000..33b7849437b --- /dev/null +++ b/src/current/_includes/example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "bank" +version = "0.1.0" +edition = "2021" + +[dependencies] +openssl = "0.10.41" +postgres-openssl = "0.5.0" +chrono = "0.4.22" + +[dependencies.postgres] +version = "0.19.3" +features = [ + "with-uuid-1" +] + +[dependencies.uuid] +version = "1.1.2" diff --git a/src/current/_includes/example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs b/src/current/_includes/example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs new file mode 100644 index 00000000000..19498a7075b --- /dev/null +++ b/src/current/_includes/example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs @@ -0,0 +1,23 @@ +/// Runs op inside a transaction and retries it as needed. +/// On non-retryable failures, the transaction is aborted and +/// rolled back; on success, the transaction is committed. +fn execute_txn(client: &mut Client, op: F) -> Result +where + F: Fn(&mut Transaction) -> Result, +{ + let mut txn = client.transaction()?; + loop { + // Set a retry savepoint + // See https://www.cockroachlabs.com/docs/stable/advanced-client-side-transaction-retries + let mut sp = txn.savepoint("cockroach_restart")?; + match op(&mut sp).and_then(|t| sp.commit().map(|_| t)) { + Err(ref err) + if err + .code() + .map(|e| *e == SqlState::T_R_SERIALIZATION_FAILURE) + .unwrap_or(false) => {} + r => break r, + } + } + .and_then(|t| txn.commit().map(|_| t)) +} diff --git a/src/current/_includes/example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs b/src/current/_includes/example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs new file mode 100644 index 00000000000..4dcef36b5ad --- /dev/null +++ b/src/current/_includes/example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs @@ -0,0 +1,19 @@ +fn transfer_funds(txn: &mut Transaction, from: Uuid, to: Uuid, amount: i64) -> Result<(), Error> { + // Read the balance. + let from_balance: i64 = txn + .query_one("SELECT balance FROM accounts WHERE id = $1", &[&from])? + .get(0); + + assert!(from_balance >= amount); + + // Perform the transfer. + txn.execute( + "UPDATE accounts SET balance = balance - $1 WHERE id = $2", + &[&amount, &from], + )?; + txn.execute( + "UPDATE accounts SET balance = balance + $1 WHERE id = $2", + &[&amount, &to], + )?; + Ok(()) +} diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-go-gorm/master/main.go b/src/current/_includes/example-apps/cockroachlabs/example-app-go-gorm/master/main.go new file mode 100644 index 00000000000..47d50d0222b --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-go-gorm/master/main.go @@ -0,0 +1,158 @@ +package main + +import ( + "context" + "fmt" + "log" + "math/rand" + "os" + "time" + + "github.com/cockroachdb/cockroach-go/v2/crdb/crdbgorm" + "github.com/google/uuid" + "gorm.io/driver/postgres" + "gorm.io/gorm" +) + +// Account is our model, which corresponds to the "accounts" table +type Account struct { + ID uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4()"` + Balance int +} + +// The `acctIDs` global variable tracks the random IDs generated by `addAccounts` +var acctIDs []uuid.UUID + +// Insert new rows into the "accounts" table +// This function generates new UUIDs and random balances for each row, and +// then it appends the ID to the `acctIDs`, which other functions use to track the IDs +func addAccounts(db *gorm.DB, numRows int, transferAmount int) error { + log.Printf("Creating %d new accounts...", numRows) + for i := 0; i < numRows; i++ { + newID := uuid.New() + newBalance := rand.Intn(10000) + transferAmount + if err := db.Create(&Account{ID: newID, Balance: newBalance}).Error; err != nil { + return err + } + acctIDs = append(acctIDs, newID) + } + log.Println("Accounts created.") + return nil +} + +// Transfer funds between accounts +// This function adds `amount` to the "balance" column of the row with the "id" column matching `toID`, +// and removes `amount` from the "balance" column of the row with the "id" column matching `fromID` +func transferFunds(db *gorm.DB, fromID uuid.UUID, toID uuid.UUID, amount int) error { + log.Printf("Transferring %d from account %s to account %s...", amount, fromID, toID) + var fromAccount Account + var toAccount Account + + db.First(&fromAccount, fromID) + db.First(&toAccount, toID) + + if fromAccount.Balance < amount { + return fmt.Errorf("account %s balance %d is lower than transfer amount %d", fromAccount.ID, fromAccount.Balance, amount) + } + + fromAccount.Balance -= amount + toAccount.Balance += amount + + if err := db.Save(&fromAccount).Error; err != nil { + return err + } + if err := db.Save(&toAccount).Error; err != nil { + return err + } + log.Println("Funds transferred.") + return nil +} + +// Print IDs and balances for all rows in "accounts" table +func printBalances(db *gorm.DB) { + var accounts []Account + db.Find(&accounts) + fmt.Printf("Balance at '%s':\n", time.Now()) + for _, account := range accounts { + fmt.Printf("%s %d\n", account.ID, account.Balance) + } +} + +// Delete all rows in "accounts" table inserted by `main` (i.e., tracked by `acctIDs`) +func deleteAccounts(db *gorm.DB, accountIDs []uuid.UUID) error { + log.Println("Deleting accounts created...") + err := db.Where("id IN ?", accountIDs).Delete(Account{}).Error + if err != nil { + return err + } + log.Println("Accounts deleted.") + return nil +} + +func main() { + + db, err := gorm.Open(postgres.Open(os.Getenv("DATABASE_URL")+"&application_name=$ docs_simplecrud_gorm"), &gorm.Config{}) + if err != nil { + log.Fatal(err) + } + + // Automatically create the "accounts" table based on the `Account` + // model. + db.AutoMigrate(&Account{}) + + // The number of initial rows to insert + const numAccts int = 5 + + // The amount to be transferred between two accounts. + const transferAmt int = 100 + + // Insert `numAccts` rows into the "accounts" table. + // To handle potential transaction retry errors, we wrap the call + // to `addAccounts` in `crdbgorm.ExecuteTx`, a helper function for + // GORM which implements a retry loop + if err := crdbgorm.ExecuteTx(context.Background(), db, nil, + func(tx *gorm.DB) error { + return addAccounts(db, numAccts, transferAmt) + }, + ); err != nil { + // For information and reference documentation, see: + // https://www.cockroachlabs.com/docs/stable/error-handling-and-troubleshooting.html + fmt.Println(err) + } + + // Print balances before transfer. + printBalances(db) + + // Select two account IDs + fromID := acctIDs[0] + toID := acctIDs[0:][rand.Intn(len(acctIDs))] + + // Transfer funds between accounts. To handle potential + // transaction retry errors, we wrap the call to `transferFunds` + // in `crdbgorm.ExecuteTx` + if err := crdbgorm.ExecuteTx(context.Background(), db, nil, + func(tx *gorm.DB) error { + return transferFunds(tx, fromID, toID, transferAmt) + }, + ); err != nil { + // For information and reference documentation, see: + // https://www.cockroachlabs.com/docs/stable/error-handling-and-troubleshooting.html + fmt.Println(err) + } + + // Print balances after transfer to ensure that it worked. + printBalances(db) + + // Delete all accounts created by the earlier call to `addAccounts` + // To handle potential transaction retry errors, we wrap the call + // to `deleteAccounts` in `crdbgorm.ExecuteTx` + if err := crdbgorm.ExecuteTx(context.Background(), db, nil, + func(tx *gorm.DB) error { + return deleteAccounts(db, acctIDs) + }, + ); err != nil { + // For information and reference documentation, see: + // https://www.cockroachlabs.com/docs/stable/error-handling-and-troubleshooting.html + fmt.Println(err) + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-go-pgx/main/main.go b/src/current/_includes/example-apps/cockroachlabs/example-app-go-pgx/main/main.go new file mode 100644 index 00000000000..677584e3883 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-go-pgx/main/main.go @@ -0,0 +1,155 @@ +package main + +import ( + "context" + "log" + "os" + + "github.com/cockroachdb/cockroach-go/v2/crdb/crdbpgxv5" + "github.com/google/uuid" + "github.com/jackc/pgx/v5" +) + +func initTable(ctx context.Context, tx pgx.Tx) error { + // Dropping existing table if it exists + log.Println("Drop existing accounts table if necessary.") + if _, err := tx.Exec(ctx, "DROP TABLE IF EXISTS accounts"); err != nil { + return err + } + + // Create the accounts table + log.Println("Creating accounts table.") + if _, err := tx.Exec(ctx, + "CREATE TABLE accounts (id UUID PRIMARY KEY DEFAULT gen_random_uuid(), balance INT8)"); err != nil { + return err + } + return nil +} + +func insertRows(ctx context.Context, tx pgx.Tx, accts [4]uuid.UUID) error { + // Insert four rows into the "accounts" table. + log.Println("Creating new rows...") + if _, err := tx.Exec(ctx, + "INSERT INTO accounts (id, balance) VALUES ($1, $2), ($3, $4), ($5, $6), ($7, $8)", accts[0], 250, accts[1], 100, accts[2], 500, accts[3], 300); err != nil { + return err + } + return nil +} + +func printBalances(conn *pgx.Conn) error { + rows, err := conn.Query(context.Background(), "SELECT id, balance FROM accounts") + if err != nil { + log.Fatal(err) + } + defer rows.Close() + for rows.Next() { + var id uuid.UUID + var balance int + if err := rows.Scan(&id, &balance); err != nil { + log.Fatal(err) + } + log.Printf("%s: %d\n", id, balance) + } + return nil +} + +func transferFunds(ctx context.Context, tx pgx.Tx, from uuid.UUID, to uuid.UUID, amount int) error { + // Read the balance. + var fromBalance int + if err := tx.QueryRow(ctx, + "SELECT balance FROM accounts WHERE id = $1", from).Scan(&fromBalance); err != nil { + return err + } + + if fromBalance < amount { + log.Println("insufficient funds") + } + + // Perform the transfer. + log.Printf("Transferring funds from account with ID %s to account with ID %s...", from, to) + if _, err := tx.Exec(ctx, + "UPDATE accounts SET balance = balance - $1 WHERE id = $2", amount, from); err != nil { + return err + } + if _, err := tx.Exec(ctx, + "UPDATE accounts SET balance = balance + $1 WHERE id = $2", amount, to); err != nil { + return err + } + return nil +} + +func deleteRows(ctx context.Context, tx pgx.Tx, one uuid.UUID, two uuid.UUID) error { + // Delete two rows into the "accounts" table. + log.Printf("Deleting rows with IDs %s and %s...", one, two) + if _, err := tx.Exec(ctx, + "DELETE FROM accounts WHERE id IN ($1, $2)", one, two); err != nil { + return err + } + return nil +} + +func main() { + // Read in connection string + config, err := pgx.ParseConfig(os.Getenv("DATABASE_URL")) + if err != nil { + log.Fatal(err) + } + config.RuntimeParams["application_name"] = "$ docs_simplecrud_gopgx" + conn, err := pgx.ConnectConfig(context.Background(), config) + if err != nil { + log.Fatal(err) + } + defer conn.Close(context.Background()) + + // Set up table + err = crdbpgx.ExecuteTx(context.Background(), conn, pgx.TxOptions{}, func(tx pgx.Tx) error { + return initTable(context.Background(), tx) + }) + + // Insert initial rows + var accounts [4]uuid.UUID + for i := 0; i < len(accounts); i++ { + accounts[i] = uuid.New() + } + + err = crdbpgx.ExecuteTx(context.Background(), conn, pgx.TxOptions{}, func(tx pgx.Tx) error { + return insertRows(context.Background(), tx, accounts) + }) + if err == nil { + log.Println("New rows created.") + } else { + log.Fatal("error: ", err) + } + + // Print out the balances + log.Println("Initial balances:") + printBalances(conn) + + // Run a transfer + err = crdbpgx.ExecuteTx(context.Background(), conn, pgx.TxOptions{}, func(tx pgx.Tx) error { + return transferFunds(context.Background(), tx, accounts[2], accounts[1], 100) + }) + if err == nil { + log.Println("Transfer successful.") + } else { + log.Fatal("error: ", err) + } + + // Print out the balances + log.Println("Balances after transfer:") + printBalances(conn) + + // Delete rows + err = crdbpgx.ExecuteTx(context.Background(), conn, pgx.TxOptions{}, func(tx pgx.Tx) error { + return deleteRows(context.Background(), tx, accounts[0], accounts[1]) + }) + if err == nil { + log.Println("Rows deleted.") + } else { + log.Fatal("error: ", err) + } + + // Print out the balances + log.Println("Balances after deletion:") + printBalances(conn) +} diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java b/src/current/_includes/example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java new file mode 100644 index 00000000000..e92740b8bd2 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java @@ -0,0 +1,205 @@ +package com.cockroachlabs; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Random; +import java.util.function.Function; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.JDBCException; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.cfg.Configuration; + +public class Sample implements Serializable { + + private static final Random RAND = new Random(); + private static final boolean FORCE_RETRY = false; + private static final String RETRY_SQL_STATE = "40001"; + private static final int MAX_ATTEMPT_COUNT = 6; + + private static Function addAccounts() throws JDBCException { + Function f = s -> { + BigDecimal rv = new BigDecimal(0); + try { + s.save(new Account(1, 1000)); + s.save(new Account(2, 250)); + s.save(new Account(3, 314159)); + rv = BigDecimal.valueOf(1); + System.out.printf("APP: addAccounts() --> %.2f\n", rv); + } catch (JDBCException e) { + throw e; + } + return rv; + }; + return f; + } + + private static Function transferFunds(long fromId, long toId, BigDecimal amount) throws JDBCException { + Function f = s -> { + BigDecimal rv = new BigDecimal(0); + try { + Account fromAccount = (Account) s.get(Account.class, fromId); + Account toAccount = (Account) s.get(Account.class, toId); + if (!(amount.compareTo(fromAccount.getBalance()) > 0)) { + fromAccount.balance = fromAccount.balance.subtract(amount); + toAccount.balance = toAccount.balance.add(amount); + s.save(fromAccount); + s.save(toAccount); + rv = amount; + System.out.printf("APP: transferFunds(%d, %d, %.2f) --> %.2f\n", fromId, toId, amount, rv); + } + } catch (JDBCException e) { + throw e; + } + return rv; + }; + return f; + } + + // Test our retry handling logic if FORCE_RETRY is true. This + // method is only used to test the retry logic. It is not + // intended for production code. + private static Function forceRetryLogic() throws JDBCException { + Function f = s -> { + BigDecimal rv = new BigDecimal(-1); + try { + System.out.printf("APP: testRetryLogic: BEFORE EXCEPTION\n"); + s.createNativeQuery("SELECT crdb_internal.force_retry('1s')").executeUpdate(); + } catch (JDBCException e) { + System.out.printf("APP: testRetryLogic: AFTER EXCEPTION\n"); + throw e; + } + return rv; + }; + return f; + } + + private static Function getAccountBalance(long id) throws JDBCException { + Function f = s -> { + BigDecimal balance; + try { + Account account = s.get(Account.class, id); + balance = account.getBalance(); + System.out.printf("APP: getAccountBalance(%d) --> %.2f\n", id, balance); + } catch (JDBCException e) { + throw e; + } + return balance; + }; + return f; + } + + // Run SQL code in a way that automatically handles the + // transaction retry logic so we don't have to duplicate it in + // various places. + private static BigDecimal runTransaction(Session session, Function fn) { + BigDecimal rv = new BigDecimal(0); + int attemptCount = 0; + + while (attemptCount < MAX_ATTEMPT_COUNT) { + attemptCount++; + + if (attemptCount > 1) { + System.out.printf("APP: Entering retry loop again, iteration %d\n", attemptCount); + } + + Transaction txn = session.beginTransaction(); + System.out.printf("APP: BEGIN;\n"); + + if (attemptCount == MAX_ATTEMPT_COUNT) { + String err = String.format("hit max of %s attempts, aborting", MAX_ATTEMPT_COUNT); + throw new RuntimeException(err); + } + + // This block is only used to test the retry logic. + // It is not necessary in production code. See also + // the method 'testRetryLogic()'. + if (FORCE_RETRY) { + session.createNativeQuery("SELECT now()").list(); + } + + try { + rv = fn.apply(session); + if (!rv.equals(-1)) { + txn.commit(); + System.out.printf("APP: COMMIT;\n"); + break; + } + } catch (JDBCException e) { + if (RETRY_SQL_STATE.equals(e.getSQLState())) { + // Since this is a transaction retry error, we + // roll back the transaction and sleep a little + // before trying again. Each time through the + // loop we sleep for a little longer than the last + // time (A.K.A. exponential backoff). + System.out.printf("APP: retryable exception occurred:\n sql state = [%s]\n message = [%s]\n retry counter = %s\n", e.getSQLState(), e.getMessage(), attemptCount); + System.out.printf("APP: ROLLBACK;\n"); + txn.rollback(); + int sleepMillis = (int) (Math.pow(2, attemptCount) * 100) + RAND.nextInt(100); + System.out.printf("APP: Hit 40001 transaction retry error, sleeping %s milliseconds\n", sleepMillis); + try { + Thread.sleep(sleepMillis); + } catch (InterruptedException ignored) { + // no-op + } + rv = BigDecimal.valueOf(-1); + } else { + throw e; + } + } + } + return rv; + } + + public static void main(String[] args) { + // Create a SessionFactory based on our hibernate.cfg.xml configuration + // file, which defines how to connect to the database. + SessionFactory sessionFactory + = new Configuration() + .configure("hibernate.cfg.xml") + .addAnnotatedClass(Account.class) + .buildSessionFactory(); + + try (Session session = sessionFactory.openSession()) { + long fromAccountId = 1; + long toAccountId = 2; + BigDecimal transferAmount = BigDecimal.valueOf(100); + + if (FORCE_RETRY) { + System.out.printf("APP: About to test retry logic in 'runTransaction'\n"); + runTransaction(session, forceRetryLogic()); + } else { + + runTransaction(session, addAccounts()); + BigDecimal fromBalance = runTransaction(session, getAccountBalance(fromAccountId)); + BigDecimal toBalance = runTransaction(session, getAccountBalance(toAccountId)); + if (!fromBalance.equals(-1) && !toBalance.equals(-1)) { + // Success! + System.out.printf("APP: getAccountBalance(%d) --> %.2f\n", fromAccountId, fromBalance); + System.out.printf("APP: getAccountBalance(%d) --> %.2f\n", toAccountId, toBalance); + } + + // Transfer $100 from account 1 to account 2 + BigDecimal transferResult = runTransaction(session, transferFunds(fromAccountId, toAccountId, transferAmount)); + if (!transferResult.equals(-1)) { + // Success! + System.out.printf("APP: transferFunds(%d, %d, %.2f) --> %.2f \n", fromAccountId, toAccountId, transferAmount, transferResult); + + BigDecimal fromBalanceAfter = runTransaction(session, getAccountBalance(fromAccountId)); + BigDecimal toBalanceAfter = runTransaction(session, getAccountBalance(toAccountId)); + if (!fromBalanceAfter.equals(-1) && !toBalanceAfter.equals(-1)) { + // Success! + System.out.printf("APP: getAccountBalance(%d) --> %.2f\n", fromAccountId, fromBalanceAfter); + System.out.printf("APP: getAccountBalance(%d) --> %.2f\n", toAccountId, toBalanceAfter); + } + } + } + } finally { + sessionFactory.close(); + } + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java b/src/current/_includes/example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java new file mode 100644 index 00000000000..aaac5410867 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java @@ -0,0 +1,428 @@ +package com.cockroachlabs; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.time.LocalTime; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.UUID; +import javax.sql.DataSource; +import org.postgresql.ds.PGSimpleDataSource; + +/** + * Main class for the basic JDBC example. + **/ +public class BasicExample { + + public static void main(String[] args) { + + // Configure the database connection. + PGSimpleDataSource ds = new PGSimpleDataSource(); + ds.setApplicationName("docs_simplecrud_jdbc"); + ds.setUrl(System.getenv("JDBC_DATABASE_URL")); + + // Create DAO. + BasicExampleDAO dao = new BasicExampleDAO(ds); + + // Test our retry handling logic if FORCE_RETRY is true. This + // method is only used to test the retry logic. It is not + // necessary in production code. + dao.testRetryHandling(); + + // Create the accounts table if it doesn't exist + dao.createAccountsTable(); + + // Insert a few accounts "by hand", using INSERTs on the backend. + Map balances = new HashMap<>(); + UUID id1 = UUID.randomUUID(); + UUID id2 = UUID.randomUUID(); + balances.put(id1.toString(), "1000"); + balances.put(id2.toString(), "250"); + int updatedAccounts = dao.updateAccounts(balances); + System.out.printf("BasicExampleDAO.updateAccounts:\n => %s total updated accounts\n", updatedAccounts); + + // How much money is in these accounts? + BigDecimal balance1 = dao.getAccountBalance(id1); + BigDecimal balance2 = dao.getAccountBalance(id2); + System.out.printf("main:\n => Account balances at time '%s':\n ID %s => $%s\n ID %s => $%s\n", LocalTime.now(), 1, balance1, 2, balance2); + + // Transfer $100 from account 1 to account 2 + UUID fromAccount = UUID.randomUUID(); + UUID toAccount = UUID.randomUUID(); + BigDecimal transferAmount = BigDecimal.valueOf(100); + int transferredAccounts = dao.transferFunds(fromAccount, toAccount, transferAmount); + if (transferredAccounts != -1) { + System.out.printf("BasicExampleDAO.transferFunds:\n => $%s transferred between accounts %s and %s, %s rows updated\n", transferAmount, fromAccount, toAccount, transferredAccounts); + } + + balance1 = dao.getAccountBalance(id1); + balance2 = dao.getAccountBalance(id2); + System.out.printf("main:\n => Account balances at time '%s':\n ID %s => $%s\n ID %s => $%s\n", LocalTime.now(), 1, balance1, 2, balance2); + + // Bulk insertion example using JDBC's batching support. + int totalRowsInserted = dao.bulkInsertRandomAccountData(); + System.out.printf("\nBasicExampleDAO.bulkInsertRandomAccountData:\n => finished, %s total rows inserted\n", totalRowsInserted); + + // Print out 10 account values. + int accountsRead = dao.readAccounts(10); + } +} + +/** + * Data access object used by 'BasicExample'. Abstraction over some + * common CockroachDB operations, including: + * + * - Auto-handling transaction retries in the 'runSQL' method + * + * - Example of bulk inserts in the 'bulkInsertRandomAccountData' + * method + */ + +class BasicExampleDAO { + + private static final int MAX_RETRY_COUNT = 3; + private static final String RETRY_SQL_STATE = "40001"; + private static final boolean FORCE_RETRY = false; + + private final DataSource ds; + + private final Random rand = new Random(); + + BasicExampleDAO(DataSource ds) { + this.ds = ds; + } + + /** + Used to test the retry logic in 'runSQL'. It is not necessary + in production code. + */ + void testRetryHandling() { + if (BasicExampleDAO.FORCE_RETRY) { + runSQL("SELECT crdb_internal.force_retry('1s':::INTERVAL)"); + } + } + + /** + * Run SQL code in a way that automatically handles the + * transaction retry logic so we don't have to duplicate it in + * various places. + * + * @param sqlCode a String containing the SQL code you want to + * execute. Can have placeholders, e.g., "INSERT INTO accounts + * (id, balance) VALUES (?, ?)". + * + * @param args String Varargs to fill in the SQL code's + * placeholders. + * @return Integer Number of rows updated, or -1 if an error is thrown. + */ + public Integer runSQL(String sqlCode, String... args) { + + // This block is only used to emit class and method names in + // the program output. It is not necessary in production + // code. + StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace(); + StackTraceElement elem = stacktrace[2]; + String callerClass = elem.getClassName(); + String callerMethod = elem.getMethodName(); + + int rv = 0; + + try (Connection connection = ds.getConnection()) { + + // We're managing the commit lifecycle ourselves so we can + // automatically issue transaction retries. + connection.setAutoCommit(false); + + int retryCount = 0; + + while (retryCount <= MAX_RETRY_COUNT) { + + if (retryCount == MAX_RETRY_COUNT) { + String err = String.format("hit max of %s retries, aborting", MAX_RETRY_COUNT); + throw new RuntimeException(err); + } + + // This block is only used to test the retry logic. + // It is not necessary in production code. See also + // the method 'testRetryHandling()'. + if (FORCE_RETRY) { + forceRetry(connection); // SELECT 1 + } + + try (PreparedStatement pstmt = connection.prepareStatement(sqlCode)) { + + // Loop over the args and insert them into the + // prepared statement based on their types. In + // this simple example we classify the argument + // types as "integers" and "everything else" + // (a.k.a. strings). + for (int i=0; i %10s\n", name, val); + } + } + } + } else { + int updateCount = pstmt.getUpdateCount(); + rv += updateCount; + + // This printed output is for debugging and/or demonstration + // purposes only. It would not be necessary in production code. + System.out.printf("\n%s.%s:\n '%s'\n", callerClass, callerMethod, pstmt); + } + + connection.commit(); + break; + + } catch (SQLException e) { + + if (RETRY_SQL_STATE.equals(e.getSQLState())) { + // Since this is a transaction retry error, we + // roll back the transaction and sleep a + // little before trying again. Each time + // through the loop we sleep for a little + // longer than the last time + // (A.K.A. exponential backoff). + System.out.printf("retryable exception occurred:\n sql state = [%s]\n message = [%s]\n retry counter = %s\n", e.getSQLState(), e.getMessage(), retryCount); + connection.rollback(); + retryCount++; + int sleepMillis = (int)(Math.pow(2, retryCount) * 100) + rand.nextInt(100); + System.out.printf("Hit 40001 transaction retry error, sleeping %s milliseconds\n", sleepMillis); + try { + Thread.sleep(sleepMillis); + } catch (InterruptedException ignored) { + // Necessary to allow the Thread.sleep() + // above so the retry loop can continue. + } + + rv = -1; + } else { + rv = -1; + throw e; + } + } + } + } catch (SQLException e) { + System.out.printf("BasicExampleDAO.runSQL ERROR: { state => %s, cause => %s, message => %s }\n", + e.getSQLState(), e.getCause(), e.getMessage()); + rv = -1; + } + + return rv; + } + + /** + * Helper method called by 'testRetryHandling'. It simply issues + * a "SELECT 1" inside the transaction to force a retry. This is + * necessary to take the connection's session out of the AutoRetry + * state, since otherwise the other statements in the session will + * be retried automatically, and the client (us) will not see a + * retry error. Note that this information is taken from the + * following test: + * https://github.com/cockroachdb/cockroach/blob/master/pkg/sql/logictest/testdata/logic_test/manual_retry + * + * @param connection Connection + */ + private void forceRetry(Connection connection) throws SQLException { + try (PreparedStatement statement = connection.prepareStatement("SELECT 1")){ + statement.executeQuery(); + } + } + + /** + * Update accounts by passing in a Map of (ID, Balance) pairs. + * + * @param accounts (Map) + * @return The number of updated accounts (int) + */ + public int updateAccounts(Map accounts) { + int rows = 0; + for (Map.Entry account : accounts.entrySet()) { + + String k = account.getKey(); + String v = account.getValue(); + + String[] args = {k, v}; + rows += runSQL("INSERT INTO accounts (id, balance) VALUES (?, ?)", args); + } + return rows; + } + + /** + * Transfer funds between one account and another. Handles + * transaction retries in case of conflict automatically on the + * backend. + * @param fromId (UUID) + * @param toId (UUID) + * @param amount (int) + * @return The number of updated accounts (int) + */ + public int transferFunds(UUID fromId, UUID toId, BigDecimal amount) { + String sFromId = fromId.toString(); + String sToId = toId.toString(); + String sAmount = amount.toPlainString(); + + // We have omitted explicit BEGIN/COMMIT statements for + // brevity. Individual statements are treated as implicit + // transactions by CockroachDB (see + // https://www.cockroachlabs.com/docs/stable/transactions.html#individual-statements). + + String sqlCode = "UPSERT INTO accounts (id, balance) VALUES" + + "(?, ((SELECT balance FROM accounts WHERE id = ?) - ?))," + + "(?, ((SELECT balance FROM accounts WHERE id = ?) + ?))"; + + return runSQL(sqlCode, sFromId, sFromId, sAmount, sToId, sToId, sAmount); + } + + /** + * Get the account balance for one account. + * + * We skip using the retry logic in 'runSQL()' here for the + * following reasons: + * + * 1. Since this is a single read ("SELECT"), we don't expect any + * transaction conflicts to handle + * + * 2. We need to return the balance as an integer + * + * @param id (UUID) + * @return balance (int) + */ + public BigDecimal getAccountBalance(UUID id) { + BigDecimal balance = BigDecimal.valueOf(0); + + try (Connection connection = ds.getConnection()) { + + // Check the current balance. + ResultSet res = connection.createStatement() + .executeQuery(String.format("SELECT balance FROM accounts WHERE id = '%s'", id.toString())); + if(!res.next()) { + System.out.printf("No users in the table with id %d", id); + } else { + balance = res.getBigDecimal("balance"); + } + } catch (SQLException e) { + System.out.printf("BasicExampleDAO.getAccountBalance ERROR: { state => %s, cause => %s, message => %s }\n", + e.getSQLState(), e.getCause(), e.getMessage()); + } + + return balance; + } + + /** + * Insert randomized account data (ID, balance) using the JDBC + * fast path for bulk inserts. The fastest way to get data into + * CockroachDB is the IMPORT statement. However, if you must bulk + * ingest from the application using INSERT statements, the best + * option is the method shown here. It will require the following: + * + * 1. Add `rewriteBatchedInserts=true` to your JDBC connection + * settings (see the connection info in 'BasicExample.main'). + * + * 2. Inserting in batches of 128 rows, as used inside this method + * (see BATCH_SIZE), since the PGJDBC driver's logic works best + * with powers of two, such that a batch of size 128 can be 6x + * faster than a batch of size 250. + * @return The number of new accounts inserted (int) + */ + public int bulkInsertRandomAccountData() { + + Random random = new Random(); + int BATCH_SIZE = 128; + int totalNewAccounts = 0; + + try (Connection connection = ds.getConnection()) { + + // We're managing the commit lifecycle ourselves so we can + // control the size of our batch inserts. + connection.setAutoCommit(false); + + // In this example we are adding 500 rows to the database, + // but it could be any number. What's important is that + // the batch size is 128. + try (PreparedStatement pstmt = connection.prepareStatement("INSERT INTO accounts (id, balance) VALUES (?, ?)")) { + for (int i=0; i<=(500/BATCH_SIZE);i++) { + for (int j=0; j %s row(s) updated in this batch\n", count.length); + } + connection.commit(); + } catch (SQLException e) { + System.out.printf("BasicExampleDAO.bulkInsertRandomAccountData ERROR: { state => %s, cause => %s, message => %s }\n", + e.getSQLState(), e.getCause(), e.getMessage()); + } + } catch (SQLException e) { + System.out.printf("BasicExampleDAO.bulkInsertRandomAccountData ERROR: { state => %s, cause => %s, message => %s }\n", + e.getSQLState(), e.getCause(), e.getMessage()); + } + return totalNewAccounts; + } + + /** + * Read out a subset of accounts from the data store. + * + * @param limit (int) + * @return Number of accounts read (int) + */ + public int readAccounts(int limit) { + return runSQL("SELECT id, balance FROM accounts LIMIT ?", Integer.toString(limit)); + } + + /** + * Create the accounts table if it doesn't already exist. + * + */ + public void createAccountsTable() { + runSQL("CREATE TABLE IF NOT EXISTS accounts (id UUID PRIMARY KEY, balance int8)"); + } + +} diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-node-postgres/main/app.js b/src/current/_includes/example-apps/cockroachlabs/example-app-node-postgres/main/app.js new file mode 100644 index 00000000000..69c1a362f9b --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-node-postgres/main/app.js @@ -0,0 +1,138 @@ +const { Pool } = require("pg"); +const { v4: uuidv4 } = require("uuid"); + +var accountValues = Array(3); + +// Wrapper for a transaction. This automatically re-calls the operation with +// the client as an argument as long as the database server asks for +// the transaction to be retried. +async function retryTxn(n, max, client, operation, callback) { + const backoffInterval = 100; // millis + const maxTries = 5; + let tries = 0; + + while (true) { + await client.query('BEGIN;'); + + tries++; + + try { + const result = await operation(client, callback); + await client.query('COMMIT;'); + return result; + } catch (err) { + await client.query('ROLLBACK;'); + + if (err.code !== '40001' || tries == maxTries) { + throw err; + } else { + console.log('Transaction failed. Retrying.'); + console.log(err.message); + await new Promise(r => setTimeout(r, tries * backoffInterval)); + } + } + } +} + +// This function is called within the first transaction. It inserts some initial values into the "accounts" table. +async function initTable(client, callback) { + let i = 0; + while (i < accountValues.length) { + accountValues[i] = await uuidv4(); + i++; + } + + const insertStatement = + "INSERT INTO accounts (id, balance) VALUES ($1, 1000), ($2, 250), ($3, 0);"; + await client.query(insertStatement, accountValues, callback); + + const selectBalanceStatement = "SELECT id, balance FROM accounts;"; + await client.query(selectBalanceStatement, callback); +} + +// This function updates the values of two rows, simulating a "transfer" of funds. +async function transferFunds(client, callback) { + const from = accountValues[0]; + const to = accountValues[1]; + const amount = 100; + const selectFromBalanceStatement = + "SELECT balance FROM accounts WHERE id = $1;"; + const selectFromValues = [from]; + await client.query( + selectFromBalanceStatement, + selectFromValues, + (err, res) => { + if (err) { + return callback(err); + } else if (res.rows.length === 0) { + console.log("account not found in table"); + return callback(err); + } + var acctBal = res.rows[0].balance; + if (acctBal < amount) { + return callback(new Error("insufficient funds")); + } + } + ); + + const updateFromBalanceStatement = + "UPDATE accounts SET balance = balance - $1 WHERE id = $2;"; + const updateFromValues = [amount, from]; + await client.query(updateFromBalanceStatement, updateFromValues, callback); + + const updateToBalanceStatement = + "UPDATE accounts SET balance = balance + $1 WHERE id = $2;"; + const updateToValues = [amount, to]; + await client.query(updateToBalanceStatement, updateToValues, callback); + + const selectBalanceStatement = "SELECT id, balance FROM accounts;"; + await client.query(selectBalanceStatement, callback); +} + +// This function deletes the third row in the accounts table. +async function deleteAccounts(client, callback) { + const deleteStatement = "DELETE FROM accounts WHERE id = $1;"; + await client.query(deleteStatement, [accountValues[2]], callback); + + const selectBalanceStatement = "SELECT id, balance FROM accounts;"; + await client.query(selectBalanceStatement, callback); +} + +// Run the transactions in the connection pool +(async () => { + const connectionString = process.env.DATABASE_URL; + const pool = new Pool({ + connectionString, + application_name: "$ docs_simplecrud_node-postgres", + }); + + // Connect to database + const client = await pool.connect(); + + // Callback + function cb(err, res) { + if (err) throw err; + + if (res.rows.length > 0) { + console.log("New account balances:"); + res.rows.forEach((row) => { + console.log(row); + }); + } + } + + // Initialize table in transaction retry wrapper + console.log("Initializing accounts table..."); + await retryTxn(0, 15, client, initTable, cb); + + // Transfer funds in transaction retry wrapper + console.log("Transferring funds..."); + await retryTxn(0, 15, client, transferFunds, cb); + + // Delete a row in transaction retry wrapper + console.log("Deleting a row..."); + await retryTxn(0, 15, client, deleteAccounts, cb); + + // Exit program + process.exit(); +})().catch((err) => console.log(err.stack)); diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql b/src/current/_includes/example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql new file mode 100644 index 00000000000..a875ed39ef6 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql @@ -0,0 +1,4 @@ +CREATE TABLE accounts ( + id UUID PRIMARY KEY, + balance INT8 +); diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-node-prisma/main/index.js b/src/current/_includes/example-apps/cockroachlabs/example-app-node-prisma/main/index.js new file mode 100644 index 00000000000..d136289a195 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-node-prisma/main/index.js @@ -0,0 +1,60 @@ +const { PrismaClient } = require('@prisma/client') +const { v4: uuidv4 } = require('uuid') + +const prisma = new PrismaClient({ + datasources: { + db: { + url: process.env.DATABASE_URL + "&application_name=$ docs_simplecrud_node-prisma", + }, + }, +}) + +const main = async () => { + const customerIds = Array(10).fill().map(() => ({ id: uuidv4() })) + const accountValues = Array(10).fill().map((_, index) => ({ + id: uuidv4(), + customer_id: customerIds[index].id, + balance: Math.floor(Math.random() * 1000) + })) + + const insertCustomerRows = await prisma.customer.createMany({ + data: customerIds + }) + + console.log('Customer rows inserted.', insertCustomerRows) + + const insertAccountRows = await prisma.account.createMany({ + data: accountValues + }) + + console.log('Account rows inserted.', insertAccountRows) + console.log('Initial Account row values:\n', await prisma.account.findMany()) + + const updateRows = await prisma.account.updateMany({ + where: { + balance: { + gt: 100 + } + }, + data: { + balance: { + decrement: 5 + } + } + }) + + console.log('Account rows updated.', updateRows) + console.log('Updated Account row values:\n', await prisma.account.findMany()) + + const deleteAllRows = await prisma.customer.deleteMany() + + console.log('All Customer rows deleted.', deleteAllRows) +} + +main() + .catch((e) => { + throw e + }) + .finally(async () => { + await prisma.$disconnect() + }) diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py b/src/current/_includes/example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py new file mode 100644 index 00000000000..75be4756b32 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py @@ -0,0 +1,30 @@ +from django.db import models +import uuid + + +class Customers(models.Model): + id = models.UUIDField( + primary_key=True, + default=uuid.uuid4, + editable=False) + name = models.CharField(max_length=250) + + +class Products(models.Model): + id = models.UUIDField( + primary_key=True, + default=uuid.uuid4, + editable=False) + name = models.CharField(max_length=250) + price = models.DecimalField(max_digits=18, decimal_places=2) + + +class Orders(models.Model): + id = models.UUIDField( + primary_key=True, + default=uuid.uuid4, + editable=False) + subtotal = models.DecimalField(max_digits=18, decimal_places=2) + customer = models.ForeignKey( + Customers, on_delete=models.CASCADE, null=True) + product = models.ManyToManyField(Products) diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py b/src/current/_includes/example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py new file mode 100644 index 00000000000..66e81e20f93 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py @@ -0,0 +1,20 @@ +from django.contrib import admin +from django.urls import path + +from .views import CustomersView, OrdersView, PingView, ProductView + +urlpatterns = [ + path('admin/', admin.site.urls), + + path('ping/', PingView.as_view()), + + # Endpoints for customers URL. + path('customer/', CustomersView.as_view(), name='customers'), + path('customer//', CustomersView.as_view(), name='customers'), + + # Endpoints for customers URL. + path('product/', ProductView.as_view(), name='product'), + path('product//', ProductView.as_view(), name='product'), + + path('order/', OrdersView.as_view(), name='order'), +] diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py b/src/current/_includes/example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py new file mode 100644 index 00000000000..22c85dfe340 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py @@ -0,0 +1,113 @@ +from django.http import JsonResponse, HttpResponse +from django.utils.decorators import method_decorator +from django.views.generic import View +from django.views.decorators.csrf import csrf_exempt +from django.db import Error, IntegrityError +from django.db.transaction import atomic +from psycopg2 import errorcodes +import json +import sys +import time + +from .models import * + +# Warning: Do not use retry_on_exception in an inner nested transaction. + + +def retry_on_exception(num_retries=3, on_failure=HttpResponse(status=500), delay_=0.5, backoff_=1.5): + def retry(view): + def wrapper(*args, **kwargs): + delay = delay_ + for i in range(num_retries): + try: + return view(*args, **kwargs) + except IntegrityError as ex: + if i == num_retries - 1: + return on_failure + elif getattr(ex.__cause__, 'pgcode', '') == errorcodes.SERIALIZATION_FAILURE: + time.sleep(delay) + delay *= backoff_ + except Error as ex: + return on_failure + return wrapper + return retry + + +class PingView(View): + def get(self, request, *args, **kwargs): + return HttpResponse("python/django", status=200) + + +@method_decorator(csrf_exempt, name='dispatch') +class CustomersView(View): + def get(self, request, id=None, *args, **kwargs): + if id is None: + customers = list(Customers.objects.values()) + else: + customers = list(Customers.objects.filter(id=id).values()) + return JsonResponse(customers, safe=False) + + @retry_on_exception(3) + @atomic + def post(self, request, *args, **kwargs): + form_data = json.loads(request.body.decode()) + name = form_data['name'] + c = Customers(name=name) + c.save() + return HttpResponse(status=200) + + @retry_on_exception(3) + @atomic + def delete(self, request, id=None, *args, **kwargs): + if id is None: + return HttpResponse(status=404) + Customers.objects.filter(id=id).delete() + return HttpResponse(status=200) + + # The PUT method is shadowed by the POST method, so there doesn't seem + # to be a reason to include it. + + +@method_decorator(csrf_exempt, name='dispatch') +class ProductView(View): + def get(self, request, id=None, *args, **kwargs): + if id is None: + products = list(Products.objects.values()) + else: + products = list(Products.objects.filter(id=id).values()) + return JsonResponse(products, safe=False) + + @retry_on_exception(3) + @atomic + def post(self, request, *args, **kwargs): + form_data = json.loads(request.body.decode()) + name, price = form_data['name'], form_data['price'] + p = Products(name=name, price=price) + p.save() + return HttpResponse(status=200) + + # The REST API outlined in the github does not say that /product/ needs + # a PUT and DELETE method + + +@method_decorator(csrf_exempt, name='dispatch') +class OrdersView(View): + def get(self, request, id=None, *args, **kwargs): + if id is None: + orders = list(Orders.objects.values()) + else: + orders = list(Orders.objects.filter(id=id).values()) + return JsonResponse(orders, safe=False) + + @retry_on_exception(3) + @atomic + def post(self, request, *args, **kwargs): + form_data = json.loads(request.body.decode()) + c = Customers.objects.get(id=form_data['customer']['id']) + o = Orders(subtotal=form_data['subtotal'], customer=c) + o.save() + for p in form_data['products']: + p = Products.objects.get(id=p['id']) + o.product.add(p) + o.save() + return HttpResponse(status=200) diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-python-django/master/requirements.txt b/src/current/_includes/example-apps/cockroachlabs/example-app-python-django/master/requirements.txt new file mode 100644 index 00000000000..a78f4fb7f32 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-python-django/master/requirements.txt @@ -0,0 +1,3 @@ +psycopg2-binary +django==5.0.1 +django-cockroachdb==5.0 diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql b/src/current/_includes/example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql new file mode 100644 index 00000000000..a875ed39ef6 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql @@ -0,0 +1,4 @@ +CREATE TABLE accounts ( + id UUID PRIMARY KEY, + balance INT8 +); diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py b/src/current/_includes/example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py new file mode 100644 index 00000000000..81e92720971 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py @@ -0,0 +1,103 @@ +"""This simple CRUD application performs the following operations sequentially: + 1. Creates 100 new accounts with randomly generated IDs and randomly-computed balance amounts. + 2. Chooses two accounts at random and takes half of the money from the first and deposits it + into the second. + 3. Chooses five accounts at random and deletes them. +""" + +from math import floor +import os +import random +import uuid + +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from sqlalchemy_cockroachdb import run_transaction +from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound + +from models import Account + +# The code below inserts new accounts. + + +def create_accounts(session, num): + """Create N new accounts with random account IDs and account balances. + """ + print("Creating new accounts...") + new_accounts = [] + while num > 0: + account_id = uuid.uuid4() + account_balance = floor(random.random()*1_000_000) + new_accounts.append(Account(id=account_id, balance=account_balance)) + seen_account_ids.append(account_id) + print(f"Created new account with id {account_id} and balance {account_balance}.") + num = num - 1 + session.add_all(new_accounts) + + +def transfer_funds_randomly(session, one, two): + """Transfer money between two accounts. + """ + try: + source = session.query(Account).filter(Account.id == one).one() + except NoResultFound: + print("No result was found") + except MultipleResultsFound: + print("Multiple results were found") + dest = session.query(Account).filter(Account.id == two).first() + print(f"Random account balances:\nAccount {one}: {source.balance}\nAccount {two}: {dest.balance}") + + amount = floor(source.balance/2) + print(f"Transferring {amount} from account {one} to account {two}...") + + # Check balance of the first account. + if source.balance < amount: + raise ValueError(f"Insufficient funds in account {one}") + source.balance -= amount + dest.balance += amount + + print(f"Transfer complete.\nNew balances:\nAccount {one}: {source.balance}\nAccount {two}: {dest.balance}") + + +def delete_accounts(session, num): + """Delete N existing accounts, at random. + """ + print("Deleting existing accounts...") + delete_ids = [] + while num > 0: + delete_id = random.choice(seen_account_ids) + delete_ids.append(delete_id) + seen_account_ids.remove(delete_id) + num = num - 1 + + accounts = session.query(Account).filter(Account.id.in_(delete_ids)).all() + + for account in accounts: + print(f"Deleted account {account.id}.") + session.delete(account) + + +if __name__ == '__main__': + # For cockroach demo: + # DATABASE_URL=postgresql://demo:@127.0.0.1:26257?sslmode=require + # For CockroachCloud: + # DATABASE_URL=postgresql://:@:26257/.defaultdb?sslmode=verify-full&sslrootcert=/ + db_uri = os.environ['DATABASE_URL'].replace("postgresql://", "cockroachdb://") + try: + engine = create_engine(db_uri, connect_args={"application_name":"docs_simplecrud_sqlalchemy"}) + except Exception as e: + print("Failed to connect to database.") + print(f"{e}") + + seen_account_ids = [] + + run_transaction(sessionmaker(bind=engine), + lambda s: create_accounts(s, 100)) + + from_id = random.choice(seen_account_ids) + to_id = random.choice([id for id in seen_account_ids if id != from_id]) + + run_transaction(sessionmaker(bind=engine), + lambda s: transfer_funds_randomly(s, from_id, to_id)) + + run_transaction(sessionmaker(bind=engine), lambda s: delete_accounts(s, 5)) diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py b/src/current/_includes/example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py new file mode 100644 index 00000000000..b429b23fe71 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py @@ -0,0 +1,13 @@ +from sqlalchemy import Column, Integer +from sqlalchemy.dialects.postgresql import UUID +from sqlalchemy.orm import declarative_base + +Base = declarative_base() + + +class Account(Base): + """The Account class corresponds to the "accounts" database table. + """ + __tablename__ = 'accounts' + id = Column(UUID(as_uuid=True), primary_key=True) + balance = Column(Integer) diff --git a/src/current/_includes/example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt b/src/current/_includes/example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt new file mode 100644 index 00000000000..6259bc58e61 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt @@ -0,0 +1,3 @@ +psycopg2-binary +sqlalchemy +sqlalchemy-cockroachdb diff --git a/src/current/_includes/example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs b/src/current/_includes/example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs new file mode 100644 index 00000000000..fc005e164d1 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs @@ -0,0 +1,122 @@ +using System; +using System.Data; +using System.Net.Security; +using Npgsql; + +namespace Cockroach +{ + class MainClass + { + static void Main(string[] args) + { + var connStringBuilder = new NpgsqlConnectionStringBuilder(); + connStringBuilder.Host = "{host-name}"; + connStringBuilder.Port = 26257; + connStringBuilder.SslMode = SslMode.VerifyFull; + connStringBuilder.Username = "{username}"; + connStringBuilder.Password = "{password}"; + connStringBuilder.Database = "bank"; + TxnSample(connStringBuilder.ConnectionString); + } + + static void TransferFunds(NpgsqlConnection conn, NpgsqlTransaction tran, int from, int to, int amount) + { + int balance = 0; + using (var cmd = new NpgsqlCommand(String.Format("SELECT balance FROM accounts WHERE id = {0}", from), conn, tran)) + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + balance = reader.GetInt32(0); + } + else + { + throw new DataException(String.Format("Account id={0} not found", from)); + } + } + if (balance < amount) + { + throw new DataException(String.Format("Insufficient balance in account id={0}", from)); + } + using (var cmd = new NpgsqlCommand(String.Format("UPDATE accounts SET balance = balance - {0} where id = {1}", amount, from), conn, tran)) + { + cmd.ExecuteNonQuery(); + } + using (var cmd = new NpgsqlCommand(String.Format("UPDATE accounts SET balance = balance + {0} where id = {1}", amount, to), conn, tran)) + { + cmd.ExecuteNonQuery(); + } + } + + static void TxnSample(string connString) + { + using (var conn = new NpgsqlConnection(connString)) + { + conn.Open(); + + // Create the "accounts" table. + new NpgsqlCommand("CREATE TABLE IF NOT EXISTS accounts (id INT PRIMARY KEY, balance INT)", conn).ExecuteNonQuery(); + + // Insert two rows into the "accounts" table. + using (var cmd = new NpgsqlCommand()) + { + cmd.Connection = conn; + cmd.CommandText = "UPSERT INTO accounts(id, balance) VALUES(@id1, @val1), (@id2, @val2)"; + cmd.Parameters.AddWithValue("id1", 1); + cmd.Parameters.AddWithValue("val1", 1000); + cmd.Parameters.AddWithValue("id2", 2); + cmd.Parameters.AddWithValue("val2", 250); + cmd.ExecuteNonQuery(); + } + + // Print out the balances. + System.Console.WriteLine("Initial balances:"); + using (var cmd = new NpgsqlCommand("SELECT id, balance FROM accounts", conn)) + using (var reader = cmd.ExecuteReader()) + while (reader.Read()) + Console.Write("\taccount {0}: {1}\n", reader.GetValue(0), reader.GetValue(1)); + + try + { + using (var tran = conn.BeginTransaction()) + { + tran.Save("cockroach_restart"); + while (true) + { + try + { + TransferFunds(conn, tran, 1, 2, 100); + tran.Commit(); + break; + } + catch (NpgsqlException e) + { + // Check if the error code indicates a SERIALIZATION_FAILURE. + if (e.ErrorCode == 40001) + { + // Signal the database that we will attempt a retry. + tran.Rollback("cockroach_restart"); + } + else + { + throw; + } + } + } + } + } + catch (DataException e) + { + Console.WriteLine(e.Message); + } + + // Now printout the results. + Console.WriteLine("Final balances:"); + using (var cmd = new NpgsqlCommand("SELECT id, balance FROM accounts", conn)) + using (var reader = cmd.ExecuteReader()) + while (reader.Read()) + Console.Write("\taccount {0}: {1}\n", reader.GetValue(0), reader.GetValue(1)); + } + } + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/hello-world-csharp/main/basic.cs b/src/current/_includes/example-apps/cockroachlabs/hello-world-csharp/main/basic.cs new file mode 100644 index 00000000000..0618c46d01b --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/hello-world-csharp/main/basic.cs @@ -0,0 +1,64 @@ +using System; +using System.Data; +using System.Net.Security; +using Npgsql; + +namespace Cockroach +{ + class MainClass + { + static void Main(string[] args) + { + var connStringBuilder = new NpgsqlConnectionStringBuilder(); + connStringBuilder.SslMode = SslMode.VerifyFull; + string? databaseUrlEnv = Environment.GetEnvironmentVariable("DATABASE_URL"); + if (databaseUrlEnv == null) { + connStringBuilder.Host = "localhost"; + connStringBuilder.Port = 26257; + connStringBuilder.Username = "{username}"; + connStringBuilder.Password = "{password}"; + } else { + Uri databaseUrl = new Uri(databaseUrlEnv); + connStringBuilder.Host = databaseUrl.Host; + connStringBuilder.Port = databaseUrl.Port; + var items = databaseUrl.UserInfo.Split(new[] { ':' }); + if (items.Length > 0) connStringBuilder.Username = items[0]; + if (items.Length > 1) connStringBuilder.Password = items[1]; + } + connStringBuilder.Database = "bank"; + Simple(connStringBuilder.ConnectionString); + } + + static void Simple(string connString) + { + using (var conn = new NpgsqlConnection(connString)) + { + conn.Open(); + + // Create the "accounts" table. + using (var cmd = new NpgsqlCommand("CREATE TABLE IF NOT EXISTS accounts (id INT PRIMARY KEY, balance INT)", conn)) + { + cmd.ExecuteNonQuery(); + } + // Insert two rows into the "accounts" table. + using (var cmd = new NpgsqlCommand()) + { + cmd.Connection = conn; + cmd.CommandText = "UPSERT INTO accounts(id, balance) VALUES(@id1, @val1), (@id2, @val2)"; + cmd.Parameters.AddWithValue("id1", 1); + cmd.Parameters.AddWithValue("val1", 1000); + cmd.Parameters.AddWithValue("id2", 2); + cmd.Parameters.AddWithValue("val2", 250); + cmd.ExecuteNonQuery(); + } + + // Print out the balances. + System.Console.WriteLine("Initial balances:"); + using (var cmd = new NpgsqlCommand("SELECT id, balance FROM accounts", conn)) + using (var reader = cmd.ExecuteReader()) + while (reader.Read()) + Console.Write("\taccount {0}: {1}\n", reader.GetValue(0), reader.GetValue(1)); + } + } + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs b/src/current/_includes/example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs new file mode 100644 index 00000000000..0b2581462cf --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs @@ -0,0 +1,133 @@ +using System; +using System.Data; +using System.Net.Security; +using Npgsql; + +namespace Cockroach +{ + class TransactionsClass + { + static void Main(string[] args) + { + var connStringBuilder = new NpgsqlConnectionStringBuilder(); + connStringBuilder.SslMode = SslMode.VerifyFull; + // use the DATABASE_URL environment variable if it is set + string? databaseUrlEnv = Environment.GetEnvironmentVariable("DATABASE_URL"); + if (databaseUrlEnv == null) { + connStringBuilder.Host = "localhost"; + connStringBuilder.Port = 26257; + connStringBuilder.Username = "{username}"; + connStringBuilder.Password = "{password}"; + } else { + Uri databaseUrl = new Uri(databaseUrlEnv); + connStringBuilder.Host = databaseUrl.Host; + connStringBuilder.Port = databaseUrl.Port; + var items = databaseUrl.UserInfo.Split(new[] { ':' }); + if (items.Length > 0) connStringBuilder.Username = items[0]; + if (items.Length > 1) connStringBuilder.Password = items[1]; + } + connStringBuilder.Database = "bank"; + TxnSample(connStringBuilder.ConnectionString); + } + + static void TransferFunds(NpgsqlConnection conn, NpgsqlTransaction tran, int from, int to, int amount) + { + int balance = 0; + using (var cmd = new NpgsqlCommand(String.Format("SELECT balance FROM accounts WHERE id = {0}", from), conn, tran)) + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + balance = reader.GetInt32(0); + } + else + { + throw new DataException(String.Format("Account id={0} not found", from)); + } + } + if (balance < amount) + { + throw new DataException(String.Format("Insufficient balance in account id={0}", from)); + } + using (var cmd = new NpgsqlCommand(String.Format("UPDATE accounts SET balance = balance - {0} where id = {1}", amount, from), conn, tran)) + { + cmd.ExecuteNonQuery(); + } + using (var cmd = new NpgsqlCommand(String.Format("UPDATE accounts SET balance = balance + {0} where id = {1}", amount, to), conn, tran)) + { + cmd.ExecuteNonQuery(); + } + } + + static void TxnSample(string connString) + { + using (var conn = new NpgsqlConnection(connString)) + { + conn.Open(); + + // Create the "accounts" table. + new NpgsqlCommand("CREATE TABLE IF NOT EXISTS accounts (id INT PRIMARY KEY, balance INT)", conn).ExecuteNonQuery(); + + // Insert two rows into the "accounts" table. + using (var cmd = new NpgsqlCommand()) + { + cmd.Connection = conn; + cmd.CommandText = "UPSERT INTO accounts(id, balance) VALUES(@id1, @val1), (@id2, @val2)"; + cmd.Parameters.AddWithValue("id1", 1); + cmd.Parameters.AddWithValue("val1", 1000); + cmd.Parameters.AddWithValue("id2", 2); + cmd.Parameters.AddWithValue("val2", 250); + cmd.ExecuteNonQuery(); + } + + // Print out the balances. + System.Console.WriteLine("Initial balances:"); + using (var cmd = new NpgsqlCommand("SELECT id, balance FROM accounts", conn)) + using (var reader = cmd.ExecuteReader()) + while (reader.Read()) + Console.Write("\taccount {0}: {1}\n", reader.GetValue(0), reader.GetValue(1)); + + try + { + using (var tran = conn.BeginTransaction()) + { + tran.Save("cockroach_restart"); + while (true) + { + try + { + TransferFunds(conn, tran, 1, 2, 100); + tran.Commit(); + break; + } + catch (NpgsqlException e) + { + // Check if the error code indicates a SERIALIZATION_FAILURE. + if (e.ErrorCode == 40001) + { + // Signal the database that we will attempt a retry. + tran.Rollback("cockroach_restart"); + } + else + { + throw; + } + } + } + } + } + catch (DataException e) + { + Console.WriteLine(e.Message); + } + + // Now printout the results. + Console.WriteLine("Final balances:"); + using (var cmd = new NpgsqlCommand("SELECT id, balance FROM accounts", conn)) + using (var reader = cmd.ExecuteReader()) + while (reader.Read()) + Console.Write("\taccount {0}: {1}\n", reader.GetValue(0), reader.GetValue(1)); + } + } + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__database.sql b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__database.sql new file mode 100644 index 00000000000..8df5243188d --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__database.sql @@ -0,0 +1 @@ +CREATE DATABASE movr PRIMARY REGION "gcp-us-east1" REGIONS "gcp-us-east1", "gcp-europe-west1", "gcp-us-west1"; diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__rides.sql b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__rides.sql new file mode 100644 index 00000000000..3268e0f3ecc --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__rides.sql @@ -0,0 +1,13 @@ +CREATE TABLE rides ( + id uuid PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(), + city STRING NOT NULL, + vehicle_id uuid, + rider_id uuid, + start_location STRING, + end_location STRING, + start_time timestamptz, + end_time timestamptz, + length interval, + CONSTRAINT fk_city_ref_users FOREIGN KEY (rider_id) REFERENCES users (id), + CONSTRAINT fk_vehicle_ref_vehicles FOREIGN KEY (vehicle_id) REFERENCES vehicles (id)) + LOCALITY REGIONAL BY ROW; diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__users.sql b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__users.sql new file mode 100644 index 00000000000..958d42cafb4 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__users.sql @@ -0,0 +1,11 @@ +CREATE TABLE IF NOT EXISTS users ( + id uuid PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(), + city STRING NOT NULL, + first_name STRING, + last_name STRING, + email STRING, + username STRING, + password_hash STRING, + is_owner bool, + UNIQUE INDEX users_username_key (username ASC)) + LOCALITY REGIONAL BY ROW; diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__vehicles.sql b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__vehicles.sql new file mode 100644 index 00000000000..c0c12d913c4 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__vehicles.sql @@ -0,0 +1,12 @@ +CREATE TABLE vehicles ( + id UUID PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(), + type STRING, + city STRING, + owner_id UUID, + date_added date, + status STRING, + last_location STRING, + color STRING, + brand STRING, + CONSTRAINT fk_ref_users FOREIGN KEY (owner_id) REFERENCES users (id)) + LOCALITY REGIONAL BY ROW; diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__front.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__front.py new file mode 100644 index 00000000000..4fb0a6d146e --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__front.py @@ -0,0 +1,9 @@ +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import Column, String, DateTime, Boolean, Interval, ForeignKey, PrimaryKeyConstraint +from sqlalchemy.types import DATE +from sqlalchemy.dialects.postgresql import UUID +import datetime +from werkzeug.security import generate_password_hash +from flask_login import UserMixin + +Base = declarative_base() diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__ride.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__ride.py new file mode 100644 index 00000000000..81eb6144a0f --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__ride.py @@ -0,0 +1,24 @@ +class Ride(Base): + """ + Represents rows of the rides table. + + Arguments: + Base {DeclaritiveMeta} -- Base class for declarative SQLAlchemy class definitions that produces appropriate `sqlalchemy.schema.Table` objects. + + Returns: + Ride -- Instance of the Ride class. + """ + __tablename__ = 'rides' + id = Column(UUID, primary_key=True) + city = Column(String, ForeignKey('vehicles.city')) + rider_id = Column(UUID, ForeignKey('users.id')) + vehicle_id = Column(UUID, ForeignKey('vehicles.id')) + start_location = Column(String) + end_location = Column(String) + start_time = Column(DateTime) + end_time = Column(DateTime) + length = Column(Interval) + + def __repr__(self): + return "".format( + self.city, self.id, self.rider_id, self.vehicle_id) diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__user.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__user.py new file mode 100644 index 00000000000..dc4792e1916 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__user.py @@ -0,0 +1,30 @@ +class User(Base, UserMixin): + """ + Represents rows of the users table. + + Arguments: + Base {DeclaritiveMeta} -- Base class for declarative SQLAlchemy class definitions that produces appropriate `sqlalchemy.schema.Table` objects. + UserMixin {UserMixin} -- Mixin object that provides default implementations for the methods that Flask-Login expects user objects to have. + + Returns: + User -- Instance of the User class. + """ + __tablename__ = 'users' + id = Column(UUID, primary_key=True) + city = Column(String) + first_name = Column(String) + last_name = Column(String) + email = Column(String) + username = Column(String, unique=True) + password_hash = Column(String) + is_owner = Column(Boolean) + + def set_password(self, password): + """ + Hash the password set by the user at registration. + """ + self.password_hash = generate_password_hash(password) + + def __repr__(self): + return "".format( + self.city, self.id, self.first_name + ' ' + self.last_name) diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__vehicle.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__vehicle.py new file mode 100644 index 00000000000..4d7bbd1428d --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__vehicle.py @@ -0,0 +1,24 @@ +class Vehicle(Base): + """ + Represents rows of the vehicles table. + + Arguments: + Base {DeclaritiveMeta} -- Base class for declarative SQLAlchemy class definitions that produces appropriate `sqlalchemy.schema.Table` objects. + + Returns: + Vehicle -- Instance of the Vehicle class. + """ + __tablename__ = 'vehicles' + id = Column(UUID, primary_key=True) + city = Column(String) + type = Column(String) + owner_id = Column(UUID, ForeignKey('users.id')) + date_added = Column(DATE, default=datetime.date.today) + status = Column(String) + last_location = Column(String) + color = Column(String) + brand = Column(String) + + def __repr__(self): + return "".format( + self.city, self.id, self.type, self.status) diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__front.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__front.py new file mode 100644 index 00000000000..ad52b6fac52 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__front.py @@ -0,0 +1,23 @@ +from movr.transactions import start_ride_txn, end_ride_txn, add_user_txn, add_vehicle_txn, get_users_txn, get_user_txn, get_vehicles_txn, get_rides_txn, remove_user_txn, remove_vehicle_txn +from cockroachdb.sqlalchemy import run_transaction +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from sqlalchemy.dialects import registry +registry.register("cockroachdb", "cockroachdb.sqlalchemy.dialect", + "CockroachDBDialect") + + +class MovR: + """ + Wraps the database connection. The class methods wrap database transactions. + """ + + def __init__(self, conn_string): + """ + Establish a connection to the database, creating Engine and Sessionmaker objects. + + Arguments: + conn_string {String} -- CockroachDB connection string. + """ + self.engine = create_engine(conn_string, convert_unicode=True) + self.sessionmaker = sessionmaker(bind=self.engine) diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__start-ride.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__start-ride.py new file mode 100644 index 00000000000..e5db7d6ed73 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__start-ride.py @@ -0,0 +1,12 @@ + def start_ride(self, city, rider_id, vehicle_id): + """ + Wraps a `run_transaction` call that starts a ride. + + Arguments: + city {String} -- The ride's city. + rider_id {UUID} -- The user's unique ID. + vehicle_id {UUID} -- The vehicle's unique ID. + """ + return run_transaction( + self.sessionmaker, lambda session: start_ride_txn( + session, city, rider_id, vehicle_id)) diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__front.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__front.py new file mode 100644 index 00000000000..900da4bed0d --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__front.py @@ -0,0 +1,3 @@ +from movr.models import Vehicle, Ride, User +import datetime +import uuid diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-rides-txn.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-rides-txn.py new file mode 100644 index 00000000000..e8c90a9a7ef --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-rides-txn.py @@ -0,0 +1,21 @@ +def get_rides_txn(session, rider_id): + """ + Select the rows of the rides table for a specific user. + + Arguments: + session {.Session} -- The active session for the database connection. + rider_id {UUID} -- The user's unique ID. + + Returns: + List -- A list of dictionaries containing ride information. + """ + rides = session.query(Ride).filter( + Ride.rider_id == rider_id).order_by(Ride.start_time).all() + return list(map(lambda ride: {'city': ride.city, + 'id': ride.id, + 'vehicle_id': ride.vehicle_id, + 'start_time': ride.start_time, + 'end_time': ride.end_time, + 'rider_id': ride.rider_id, + 'length': ride.length}, + rides)) diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-vehicles-txn.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-vehicles-txn.py new file mode 100644 index 00000000000..fd8cd2a302d --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-vehicles-txn.py @@ -0,0 +1,26 @@ +def get_vehicles_txn(session, city): + """ + Select the rows of the vehicles table for a specific city. + + Arguments: + session {.Session} -- The active session for the database connection. + city {String} -- The vehicle's city. + + Returns: + List -- A list of dictionaries containing vehicle information. + """ + vehicles = session.query(Vehicle).filter( + Vehicle.city == city, Vehicle.status != 'removed').all() + return list( + map( + lambda vehicle: { + 'city': vehicle.city, + 'id': vehicle.id, + 'owner_id': vehicle.owner_id, + 'type': vehicle.type, + 'last_location': vehicle.last_location + ', ' + vehicle.city, + 'status': vehicle.status, + 'date_added': vehicle.date_added, + 'color': vehicle.color, + 'brand': vehicle.brand}, + vehicles)) diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__start-ride-txn.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__start-ride-txn.py new file mode 100644 index 00000000000..9b93d1ce48d --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__start-ride-txn.py @@ -0,0 +1,24 @@ +def start_ride_txn(session, city, rider_id, vehicle_id): + """ + Insert a new row into the rides table and update a row of the vehicles table. + + Arguments: + session {.Session} -- The active session for the database connection. + city {String} -- The vehicle's city. + rider_id {UUID} -- The user's unique ID. + rider_city {String} -- The city in which the rider is registered. + vehicle_id {UUID} -- The vehicle's unique ID. + """ + v = session.query(Vehicle).filter(Vehicle.id == vehicle_id).first() + r = Ride( + city=city, + id=str( + uuid.uuid4()), + rider_id=rider_id, + vehicle_id=vehicle_id, + start_location=v.last_location, + start_time=datetime.datetime.now( + datetime.timezone.utc)) + + session.add(r) + v.status = "unavailable" diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__connect.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__connect.py new file mode 100644 index 00000000000..43ce428fb12 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__connect.py @@ -0,0 +1,2 @@ +conn_string = app.config.get('DB_URI') +movr = MovR(conn_string) diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__front.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__front.py new file mode 100644 index 00000000000..87b7e4afe61 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__front.py @@ -0,0 +1,8 @@ +from flask import Flask, render_template, session, redirect, flash, url_for, Markup, request, Response +from flask_bootstrap import Bootstrap, WebCDN +from flask_login import LoginManager, current_user, login_user, logout_user, login_required +from werkzeug.security import check_password_hash +from movr.movr import MovR +from web.forms import CredentialForm, RegisterForm, VehicleForm, StartRideForm, EndRideForm, RemoveUserForm, RemoveVehicleForm +from web.config import Config +from sqlalchemy.exc import DBAPIError diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__init.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__init.py new file mode 100644 index 00000000000..e57c1ca1b71 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__init.py @@ -0,0 +1,9 @@ +DEFAULT_ROUTE_AUTHENTICATED = "vehicles" +DEFAULT_ROUTE_NOT_AUTHENTICATED = "login_page" + +# Initialize the app +app = Flask(__name__) +app.config.from_object(Config) +Bootstrap(app) +login = LoginManager(app) +protocol = ('https', 'http')[app.config.get('DEBUG') == 'True'] diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__login-page.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__login-page.py new file mode 100644 index 00000000000..64cc7e677f1 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__login-page.py @@ -0,0 +1,32 @@ +@app.route('/login', methods=['GET', 'POST']) +def login_page(): + if current_user.is_authenticated: + return redirect(url_for(DEFAULT_ROUTE_AUTHENTICATED, _external=True, _scheme=protocol)) + else: + form = CredentialForm() + if form.validate_on_submit(): + try: + user = movr.get_user(username=form.username.data) + if user is None or not check_password_hash( + user.password_hash, form.password.data): + flash( + Markup( + 'Invalid user credentials.
If you aren\'t registered with MovR, go Sign Up!' + ).format( + url_for('register', + _external=True, + _scheme=protocol))) + return redirect( + url_for('login_page', _external=True, + _scheme=protocol)) + login_user(user) + return redirect( + url_for(DEFAULT_ROUTE_AUTHENTICATED, _external=True, _scheme=protocol)) + except Exception as error: + flash('{0}'.format(error)) + return redirect( + url_for('login_page', _external=True, _scheme=protocol)) + return render_template('login.html', + title='Log In', + form=form, + available=session['region']) diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__user-loader.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__user-loader.py new file mode 100644 index 00000000000..f7be03965a8 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__user-loader.py @@ -0,0 +1,3 @@ +@login.user_loader +def load_user(user_id): + return movr.get_user(user_id=user_id) diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/config.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/config.py new file mode 100644 index 00000000000..0e2757559d0 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/config.py @@ -0,0 +1,16 @@ +# This file defines classes for flask configuration +import os + + +class Config: + """Flask configuration class. + """ + DEBUG = os.environ['DEBUG'] + SECRET_KEY = os.environ['SECRET_KEY'] + API_KEY = os.environ['API_KEY'] + DB_URI = os.environ['DB_URI'] + REGION = os.environ['REGION'] + PREFERRED_URL_SCHEME = ('https', 'http')[DEBUG == 'True'] + CITY_MAP = {'gcp-us-east1': ['new york', 'boston', 'washington dc'], + 'gcp-us-west1': ['san francisco', 'seattle', 'los angeles'], + 'gcp-europe-west1': ['amsterdam', 'paris', 'rome']} diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__credentialform.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__credentialform.py new file mode 100644 index 00000000000..4f7fbdcc6da --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__credentialform.py @@ -0,0 +1,6 @@ +class CredentialForm(FlaskForm): + """Login form class. + """ + username = StringField('Username: ', validators=[data_required()]) + password = PasswordField('Password: ', validators=[data_required()]) + submit = SubmitField('Sign In') diff --git a/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__vehicleform.py b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__vehicleform.py new file mode 100644 index 00000000000..e30584de729 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__vehicleform.py @@ -0,0 +1,11 @@ +class VehicleForm(FlaskForm): + """Vehicle registration form class. + """ + type = SelectField(label='Type', + choices=[('bike', 'Bike'), ('scooter', 'Scooter'), + ('skateboard', 'Skateboard')]) + color = StringField(label='Color', validators=[data_required()]) + brand = StringField(label='Brand') + location = StringField(label='Current location: ', + validators=[data_required()]) + submit = SubmitField('Add vehicle') diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java new file mode 100644 index 00000000000..e4f6dd62495 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java @@ -0,0 +1,35 @@ +package io.roach.data.jdbc; + +import java.math.BigDecimal; + +import org.springframework.data.annotation.Id; + +/** + * Domain entity mapped to the account table. + */ +public class Account { + @Id + private Long id; + + private String name; + + private AccountType type; + + private BigDecimal balance; + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public AccountType getType() { + return type; + } + + public BigDecimal getBalance() { + return balance; + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java new file mode 100644 index 00000000000..92a981772d6 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java @@ -0,0 +1,154 @@ +package io.roach.data.jdbc; + +import java.math.BigDecimal; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataRetrievalFailureException; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.PageableDefault; +import org.springframework.data.web.PagedResourcesAssembler; +import org.springframework.hateoas.IanaLinkRelations; +import org.springframework.hateoas.Link; +import org.springframework.hateoas.PagedModel; +import org.springframework.hateoas.RepresentationModel; +import org.springframework.hateoas.UriTemplate; +import org.springframework.hateoas.server.RepresentationModelAssembler; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; +import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW; + +/** + * Main remoting and transaction boundary in the form of a REST controller. The discipline + * when following the entity-control-boundary (ECB) pattern is that only service boundaries + * are allowed to start and end transactions. A service boundary can be a controller, business + * service facade or service activator (JMS/Kafka listener). + *

+ * This is enforced by the REQUIRES_NEW propagation attribute of @Transactional annotated + * controller methods. Between the web container's HTTP listener and the transaction proxy, + * there's yet another transparent proxy in the form of a retry loop advice with exponential + * backoff. It takes care of retrying transactions that are aborted by transient SQL errors, + * rather than having these propagate all the way over the wire to the client / user agent. + * + * @see RetryableTransactionAspect + */ +@RestController +public class AccountController { + @Autowired + private AccountRepository accountRepository; + + @Autowired + private PagedResourcesAssembler pagedResourcesAssembler; + + /** + * Provides the service index resource representation which is only links + * for clients to follow. + */ + @GetMapping + public ResponseEntity index() { + RepresentationModel index = new RepresentationModel(); + + // Type-safe way to generate URLs bound to controller methods + index.add(linkTo(methodOn(AccountController.class) + .listAccounts(PageRequest.of(0, 5))) + .withRel("accounts")); // Lets skip curies and affordances for now + + index.add(Link.of(UriTemplate.of(linkTo(AccountController.class) + .toUriComponentsBuilder().path( + "/transfer/{?fromId,toId,amount}") // RFC-6570 template + .build().toUriString()), + "transfer" + ).withTitle("Transfer funds")); + + + // Spring boot actuators for observability / monitoring + index.add(Link.of( + ServletUriComponentsBuilder + .fromCurrentContextPath() + .pathSegment("actuator") + .buildAndExpand() + .toUriString() + ).withRel("actuator")); + + return new ResponseEntity<>(index, HttpStatus.OK); + } + + /** + * Provides a paged representation of accounts (sort order omitted). + */ + @GetMapping("/account") + @Transactional(propagation = REQUIRES_NEW) + public HttpEntity> listAccounts( + @PageableDefault(size = 5, direction = Sort.Direction.ASC) Pageable page) { + return ResponseEntity + .ok(pagedResourcesAssembler.toModel(accountRepository.findAll(page), accountModelAssembler())); + } + + /** + * Provides a point lookup of a given account. + */ + @GetMapping(value = "/account/{id}") + @Transactional(propagation = REQUIRES_NEW, readOnly = true) // Notice its marked read-only + public HttpEntity getAccount(@PathVariable("id") Long accountId) { + return new ResponseEntity<>(accountModelAssembler().toModel( + accountRepository.findById(accountId) + .orElseThrow(() -> new DataRetrievalFailureException("No such account: " + accountId))), + HttpStatus.OK); + } + + /** + * Main funds transfer method. + */ + @PostMapping(value = "/transfer") + @Transactional(propagation = REQUIRES_NEW) + public HttpEntity transfer( + @RequestParam("fromId") Long fromId, + @RequestParam("toId") Long toId, + @RequestParam("amount") BigDecimal amount + ) { + if (amount.compareTo(BigDecimal.ZERO) < 0) { + throw new IllegalArgumentException("Negative amount"); + } + if (fromId.equals(toId)) { + throw new IllegalArgumentException("From and to accounts must be different"); + } + + BigDecimal fromBalance = accountRepository.getBalance(fromId).add(amount.negate()); + // Application level invariant check. + // Could be enhanced or replaced with a CHECK constraint like: + // ALTER TABLE account ADD CONSTRAINT check_account_positive_balance CHECK (balance >= 0) + if (fromBalance.compareTo(BigDecimal.ZERO) < 0) { + throw new NegativeBalanceException("Insufficient funds " + amount + " for account " + fromId); + } + + accountRepository.updateBalance(fromId, amount.negate()); + accountRepository.updateBalance(toId, amount); + + return ResponseEntity.ok().build(); + } + + private RepresentationModelAssembler accountModelAssembler() { + return (entity) -> { + AccountModel model = new AccountModel(); + model.setName(entity.getName()); + model.setType(entity.getType()); + model.setBalance(entity.getBalance()); + model.add(linkTo(methodOn(AccountController.class) + .getAccount(entity.getId()) + ).withRel(IanaLinkRelations.SELF)); + return model; + }; + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java new file mode 100644 index 00000000000..6ee47d48f4b --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java @@ -0,0 +1,42 @@ +package io.roach.data.jdbc; + +import java.math.BigDecimal; + +import org.springframework.hateoas.RepresentationModel; +import org.springframework.hateoas.server.core.Relation; + +/** + * Account resource represented in HAL+JSON via REST API. + */ +@Relation(value = "account", collectionRelation = "accounts") +public class AccountModel extends RepresentationModel { + private String name; + + private AccountType type; + + private BigDecimal balance; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public AccountType getType() { + return type; + } + + public void setType(AccountType type) { + this.type = type; + } + + public BigDecimal getBalance() { + return balance; + } + + public void setBalance(BigDecimal balance) { + this.balance = balance; + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java new file mode 100644 index 00000000000..c5bc0b55bb8 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java @@ -0,0 +1,27 @@ +package io.roach.data.jdbc; + +import java.math.BigDecimal; + +import org.springframework.data.jdbc.repository.query.Modifying; +import org.springframework.data.jdbc.repository.query.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import static org.springframework.transaction.annotation.Propagation.MANDATORY; + +/** + * The main account repository, notice there's no implementation needed since its auto-proxied by + * spring-data. + */ +@Repository +@Transactional(propagation = MANDATORY) +public interface AccountRepository extends CrudRepository, PagedAccountRepository { + @Query(value = "SELECT balance FROM account WHERE id=:id FOR UPDATE") + BigDecimal getBalance(@Param("id") Long id); + + @Modifying + @Query("UPDATE account SET balance = balance + :balance WHERE id=:id") + void updateBalance(@Param("id") Long id, @Param("balance") BigDecimal balance); +} diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java new file mode 100644 index 00000000000..7ab7e13c9f9 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java @@ -0,0 +1,119 @@ +package io.roach.data.jdbc; + +import java.math.BigDecimal; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Deque; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.core.Ordered; +import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories; +import org.springframework.hateoas.Link; +import org.springframework.hateoas.config.EnableHypermediaSupport; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestTemplate; + +/** + * Spring boot server application using spring-data-jdbc for data access. + */ +@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL) +@EnableJdbcRepositories +@EnableAspectJAutoProxy(proxyTargetClass = true) +@EnableTransactionManagement(order = Ordered.LOWEST_PRECEDENCE - 1) // Bump up one level to enable extra advisors +@SpringBootApplication +public class JdbcApplication implements CommandLineRunner { + protected static final Logger logger = LoggerFactory.getLogger(JdbcApplication.class); + + public static void main(String[] args) { + new SpringApplicationBuilder(JdbcApplication.class) + .web(WebApplicationType.SERVLET) + .run(args); + } + + @Override + public void run(String... args) { + final Link transferLink = Link.of("http://localhost:9090/transfer{?fromId,toId,amount}"); + + int concurrency = 1; + + LinkedList argsList = new LinkedList<>(Arrays.asList(args)); + while (!argsList.isEmpty()) { + String arg = argsList.pop(); + if (arg.startsWith("--concurrency=")) { + concurrency = Integer.parseInt(arg.split("=")[1]); + } + } + + logger.info("Lets move some $$ around! (concurrency level {})", concurrency); + + final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(concurrency); + + Deque> futures = new ArrayDeque<>(); + + for (int i = 0; i < concurrency; i++) { + Future future = executorService.submit(() -> { + RestTemplate template = new RestTemplate(); + + int errors = 0; + + for (int j = 0; j < 100; j++) { + int fromId = j % 4 + 1; + int toId = fromId % 4 + 1; + + BigDecimal amount = new BigDecimal("10.00"); + + Map form = new HashMap<>(); + form.put("fromId", fromId); + form.put("toId", toId); + form.put("amount", amount); + + String uri = transferLink.expand(form).getHref(); + + logger.debug("({}) Transfer {} from {} to {}", uri, amount, fromId, toId); + + try { + template.postForEntity(uri, null, String.class); + } catch (HttpStatusCodeException e) { + logger.warn(e.getResponseBodyAsString()); + errors++; + } + } + return errors; + }); + futures.add(future); + } + + int totalErrors = 0; + + while (!futures.isEmpty()) { + try { + int errors = futures.pop().get(); + totalErrors += errors; + logger.info("Worker finished with {} errors - {} remaining", errors, futures.size()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (ExecutionException e) { + logger.warn("Worker failed", e.getCause()); + } + } + + logger.info("All client workers finished with {} errors and server keeps running. Have a nice day!", + totalErrors); + + executorService.shutdownNow(); + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java new file mode 100644 index 00000000000..b4d83471a9d --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java @@ -0,0 +1,88 @@ +package io.roach.data.jdbc; + +import java.lang.reflect.UndeclaredThrowableException; +import java.util.concurrent.atomic.AtomicLong; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.dao.TransientDataAccessException; +import org.springframework.stereotype.Component; +import org.springframework.transaction.TransactionSystemException; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.util.Assert; + +/** + * Aspect with an around advice that intercepts and retries transient concurrency exceptions. + * Methods matching the pointcut expression (annotated with @Transactional) are retried a number + * of times with exponential backoff. + *

+ * This advice needs to runs in a non-transactional context, which is before the underlying + * transaction advisor (@Order ensures that). + */ +@Component +@Aspect +// Before TX advisor +@Order(Ordered.LOWEST_PRECEDENCE - 2) +public class RetryableTransactionAspect { + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + @Pointcut("execution(* io.roach..*(..)) && @annotation(transactional)") + public void anyTransactionBoundaryOperation(Transactional transactional) { + } + + @Around(value = "anyTransactionBoundaryOperation(transactional)", + argNames = "pjp,transactional") + public Object retryableOperation(ProceedingJoinPoint pjp, Transactional transactional) + throws Throwable { + final int totalRetries = 30; + int numAttempts = 0; + AtomicLong backoffMillis = new AtomicLong(150); + + Assert.isTrue(!TransactionSynchronizationManager.isActualTransactionActive(), "TX active"); + + do { + try { + numAttempts++; + return pjp.proceed(); + } catch (TransientDataAccessException | TransactionSystemException ex) { + handleTransientException(ex, numAttempts, totalRetries, pjp, backoffMillis); + } catch (UndeclaredThrowableException ex) { + Throwable t = ex.getUndeclaredThrowable(); + if (t instanceof TransientDataAccessException) { + handleTransientException(t, numAttempts, totalRetries, pjp, backoffMillis); + } else { + throw ex; + } + } + } while (numAttempts < totalRetries); + + throw new ConcurrencyFailureException("Too many transient errors (" + numAttempts + ") for method [" + + pjp.getSignature().toLongString() + "]. Giving up!"); + } + + private void handleTransientException(Throwable ex, int numAttempts, int totalAttempts, + ProceedingJoinPoint pjp, AtomicLong backoffMillis) { + if (logger.isWarnEnabled()) { + logger.warn("Transient data access exception (" + numAttempts + " of max " + totalAttempts + ") " + + "detected (retry in " + backoffMillis + " ms) " + + "in method '" + pjp.getSignature().getDeclaringTypeName() + "." + pjp.getSignature().getName() + + "': " + ex.getMessage()); + } + if (backoffMillis.get() >= 0) { + try { + Thread.sleep(backoffMillis.get()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + backoffMillis.set(Math.min((long) (backoffMillis.get() * 1.5), 1500)); + } + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java new file mode 100644 index 00000000000..0eae2cba3ba --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java @@ -0,0 +1,63 @@ +package io.roach.data.jdbc; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.util.Assert; + +/** + * Aspect with an around advice that intercepts and sets transaction attributes. + *

+ * This advice needs to runs in a transactional context, which is after the underlying + * transaction advisor. + */ +@Component +@Aspect +// After TX advisor +@Order(Ordered.LOWEST_PRECEDENCE) +public class TransactionHintsAspect { + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private JdbcTemplate jdbcTemplate; + + private String applicationName = "roach-data"; + + @Pointcut("execution(* io.roach..*(..)) && @annotation(transactional)") + public void anyTransactionBoundaryOperation(Transactional transactional) { + } + + @Around(value = "anyTransactionBoundaryOperation(transactional)", + argNames = "pjp,transactional") + public Object setTransactionAttributes(ProceedingJoinPoint pjp, Transactional transactional) + throws Throwable { + Assert.isTrue(TransactionSynchronizationManager.isActualTransactionActive(), "TX not active"); + + // https://www.cockroachlabs.com/docs/v19.2/set-vars.html + jdbcTemplate.update("SET application_name=?", applicationName); + + if (transactional.timeout() != TransactionDefinition.TIMEOUT_DEFAULT) { + logger.info("Setting statement time {} for {}", transactional.timeout(), + pjp.getSignature().toShortString()); + jdbcTemplate.update("SET statement_timeout=?", transactional.timeout() * 1000); + } + + if (transactional.readOnly()) { + logger.info("Setting transaction read only for {}", pjp.getSignature().toShortString()); + jdbcTemplate.execute("SET transaction_read_only=true"); + } + + return pjp.proceed(); + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml new file mode 100644 index 00000000000..66a052f6467 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml @@ -0,0 +1,41 @@ + + + + + + + ANY + + + + + + 1 + Alice + + asset + + + 2 + Bob + + expense + + + 3 + Bobby Tables + + asset + + + 4 + Doris + + expense + + + diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql new file mode 100644 index 00000000000..f53212c445b --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql @@ -0,0 +1,18 @@ +create table account +( + id int not null primary key default unique_rowid(), + balance numeric(19, 2) not null, + name varchar(128) not null, + type varchar(25) not null, + updated timestamptz not null default clock_timestamp() +); + +-- insert into account (id,balance,name,type) +-- values +-- (1,100.50,'a','expense'), +-- (2,100.50,'b','expense'), +-- (3,100.50,'c','expense'), +-- (4,100.50,'d','expense'), +-- (5,100.50,'e','expense'); + +-- select * from account AS OF SYSTEM TIME '-5s'; diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java new file mode 100644 index 00000000000..42f397c0dd3 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java @@ -0,0 +1,40 @@ +package io.roach.data.jpa; + +import java.math.BigDecimal; + +import javax.persistence.*; + +@Entity +@Table(name = "account") +public class Account { + @Id + @Column + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(length = 128, nullable = false, unique = true) + private String name; + + @Column(length = 25, nullable = false) + @Enumerated(EnumType.STRING) + private AccountType type; + + @Column(length = 25, nullable = false) + private BigDecimal balance; + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public AccountType getType() { + return type; + } + + public BigDecimal getBalance() { + return balance; + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java new file mode 100644 index 00000000000..4dd65053c6c --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java @@ -0,0 +1,105 @@ +package io.roach.data.jpa; + +import java.math.BigDecimal; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.PageableDefault; +import org.springframework.data.web.PagedResourcesAssembler; +import org.springframework.hateoas.IanaLinkRelations; +import org.springframework.hateoas.PagedModel; +import org.springframework.hateoas.RepresentationModel; +import org.springframework.hateoas.server.RepresentationModelAssembler; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; +import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW; + +@RestController +public class AccountController { + @Autowired + private AccountRepository accountRepository; + + @Autowired + private PagedResourcesAssembler pagedResourcesAssembler; + + @GetMapping + public ResponseEntity index() { + RepresentationModel index = new RepresentationModel(); + + index.add(linkTo(methodOn(AccountController.class) + .listAccounts(PageRequest.of(0, 5))) + .withRel("accounts")); + + index.add(linkTo(AccountController.class) + .slash("transfer{?fromId,toId,amount}") + .withRel("transfer")); + + return new ResponseEntity<>(index, HttpStatus.OK); + } + + @GetMapping("/account") + @Transactional(propagation = REQUIRES_NEW) + public HttpEntity> listAccounts( + @PageableDefault(size = 5, direction = Sort.Direction.ASC) Pageable page) { + return ResponseEntity + .ok(pagedResourcesAssembler.toModel(accountRepository.findAll(page), accountModelAssembler())); + } + + @GetMapping(value = "/account/{id}") + @Transactional(propagation = REQUIRES_NEW) + public HttpEntity getAccount(@PathVariable("id") Long accountId) { + return new ResponseEntity<>(accountModelAssembler().toModel(accountRepository.getOne(accountId)), + HttpStatus.OK); + } + + @PostMapping(value = "/transfer") + @Transactional(propagation = REQUIRES_NEW) + public HttpEntity transfer( + @RequestParam("fromId") Long fromId, + @RequestParam("toId") Long toId, + @RequestParam("amount") BigDecimal amount + ) { + if (amount.compareTo(BigDecimal.ZERO) < 0) { + throw new IllegalArgumentException("Negative amount"); + } + if (fromId.equals(toId)) { + throw new IllegalArgumentException("From and to accounts must be different"); + } + + BigDecimal fromBalance = accountRepository.getBalance(fromId).add(amount.negate()); + +// if (fromBalance.compareTo(BigDecimal.ZERO) < 0) { +// throw new NegativeBalanceException("Insufficient funds " + amount + " for account " + fromId); +// } + + accountRepository.updateBalance(fromId, amount.negate()); + accountRepository.updateBalance(toId, amount); + + return ResponseEntity.ok().build(); + } + + private RepresentationModelAssembler accountModelAssembler() { + return (entity) -> { + AccountModel model = new AccountModel(); + model.setName(entity.getName()); + model.setType(entity.getType()); + model.setBalance(entity.getBalance()); + model.add(linkTo(methodOn(AccountController.class) + .getAccount(entity.getId()) + ).withRel(IanaLinkRelations.SELF)); + return model; + }; + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java new file mode 100644 index 00000000000..0106b2ee4c5 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java @@ -0,0 +1,39 @@ +package io.roach.data.jpa; + +import java.math.BigDecimal; + +import org.springframework.hateoas.RepresentationModel; +import org.springframework.hateoas.server.core.Relation; + +@Relation(value = "account", collectionRelation = "accounts") +public class AccountModel extends RepresentationModel { + private String name; + + private AccountType type; + + private BigDecimal balance; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public AccountType getType() { + return type; + } + + public void setType(AccountType type) { + this.type = type; + } + + public BigDecimal getBalance() { + return balance; + } + + public void setBalance(BigDecimal balance) { + this.balance = balance; + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java new file mode 100644 index 00000000000..a8ff08af6a7 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java @@ -0,0 +1,27 @@ +package io.roach.data.jpa; + +import java.math.BigDecimal; + +import javax.persistence.LockModeType; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Lock; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import static org.springframework.transaction.annotation.Propagation.MANDATORY; + +@Repository +@Transactional(propagation = MANDATORY) +public interface AccountRepository extends JpaRepository, JpaSpecificationExecutor { + @Query(value = "select balance from Account where id=?1") + @Lock(LockModeType.PESSIMISTIC_READ) + BigDecimal getBalance(Long id); + + @Modifying + @Query("update Account set balance = balance + ?2 where id=?1") + void updateBalance(Long id, BigDecimal balance); +} diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java new file mode 100644 index 00000000000..0ac5ce23b81 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java @@ -0,0 +1,103 @@ +package io.roach.data.jpa; + +import java.math.BigDecimal; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.hateoas.Link; +import org.springframework.hateoas.config.EnableHypermediaSupport; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestTemplate; + +@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL) +@EnableJpaRepositories +@EnableAspectJAutoProxy(proxyTargetClass = true) +@EnableTransactionManagement +@SpringBootApplication +public class JpaApplication implements CommandLineRunner { + protected static final Logger logger = LoggerFactory.getLogger(JpaApplication.class); + + public static void main(String[] args) { + new SpringApplicationBuilder(JpaApplication.class) + .web(WebApplicationType.SERVLET) + .run(args); + } + + @Override + public void run(String... args) throws Exception { + logger.info("Lets move some $$ around!"); + + final Link transferLink = Link.of("http://localhost:9090/transfer{?fromId,toId,amount}"); + + final int concurrency = args.length > 0 ? Integer.parseInt(args[0]) : 1; + + final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(concurrency); + + Deque> futures = new ArrayDeque<>(); + + for (int i = 0; i < concurrency; i++) { + Future future = executorService.submit(() -> { + RestTemplate template = new RestTemplate(); + int errors = 0; + for (int j = 0; j < 100; j++) { + int fromId = j % 4 + 1; + int toId = fromId % 4 + 1; + + BigDecimal amount = new BigDecimal("10.00"); + + Map form = new HashMap<>(); + form.put("fromId", fromId); + form.put("toId", toId); + form.put("amount", amount); + + String uri = transferLink.expand(form).getHref(); + + logger.debug("({}) Transfer {} from {} to {}", uri, amount, fromId, toId); + + try { + template.postForEntity(uri, null, String.class); + } catch (HttpStatusCodeException e) { + logger.warn(e.getResponseBodyAsString()); + errors++; + } + } + return errors; + }); + futures.add(future); + } + + int totalErrors = 0; + + while (!futures.isEmpty()) { + try { + int errors = futures.pop().get(); + totalErrors += errors; + logger.info("Worker finished with {} errors - {} remaining", errors, futures.size()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (ExecutionException e) { + logger.warn("Worker failed", e.getCause()); + } + } + + logger.info("All client workers finished with {} errors and server keeps running. Have a nice day!", + totalErrors); + + executorService.shutdownNow(); + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java new file mode 100644 index 00000000000..3e266c47f64 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java @@ -0,0 +1,101 @@ +package io.roach.data.jpa; + +import java.lang.reflect.UndeclaredThrowableException; +import java.sql.SQLException; +import java.time.Duration; +import java.time.Instant; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.NestedExceptionUtils; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.dao.TransientDataAccessException; +import org.springframework.stereotype.Component; +import org.springframework.transaction.TransactionSystemException; +import org.springframework.transaction.annotation.Transactional; + +@Component +@Aspect +@Order(Ordered.LOWEST_PRECEDENCE - 1) +public class RetryableTransactionAspect { + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + private final int retryAttempts = 30; + + private final int maxBackoff = 15000; + + @Pointcut("execution(* io.roach..*(..)) && @annotation(transactional)") + public void anyTransactionBoundaryOperation(Transactional transactional) { + } + + @Around(value = "anyTransactionBoundaryOperation(transactional)", + argNames = "pjp,transactional") + public Object doInTransaction(ProceedingJoinPoint pjp, Transactional transactional) + throws Throwable { + int numCalls = 0; + + final Instant callTime = Instant.now(); + + do { + try { + numCalls++; + Object rv = pjp.proceed(); + if (numCalls > 1) { + logger.debug( + "Transient error recovered after " + numCalls + " of " + retryAttempts + " retries (" + + Duration.between(callTime, Instant.now()).toString() + ")"); + } + return rv; + } catch (TransientDataAccessException | TransactionSystemException ex) { // TX abort on commit's + Throwable cause = NestedExceptionUtils.getMostSpecificCause(ex); + if (cause instanceof SQLException) { + SQLException sqlException = (SQLException) cause; + if ("40001".equals(sqlException.getSQLState())) { // Transient error code + handleTransientException(sqlException, numCalls, pjp.getSignature().toShortString()); + continue; + } + } + + throw ex; + } catch (UndeclaredThrowableException ex) { + Throwable t = ex.getUndeclaredThrowable(); + while (t instanceof UndeclaredThrowableException) { + t = ((UndeclaredThrowableException) t).getUndeclaredThrowable(); + } + + Throwable cause = NestedExceptionUtils.getMostSpecificCause(ex); + if (cause instanceof SQLException) { + SQLException sqlException = (SQLException) cause; + if ("40001".equals(sqlException.getSQLState())) { // Transient error code + handleTransientException(sqlException, numCalls, pjp.getSignature().toShortString()); + continue; + } + } + + throw ex; + } + } while (numCalls < retryAttempts); + + throw new ConcurrencyFailureException("Too many transient errors (" + numCalls + ") for method [" + + pjp.getSignature().toShortString() + "]. Giving up!"); + } + + private void handleTransientException(SQLException ex, int numCalls, String method) { + try { + long backoffMillis = Math.min((long) (Math.pow(2, numCalls) + Math.random() * 1000), maxBackoff); + if (numCalls <= 1 && logger.isWarnEnabled()) { + logger.warn("Transient error detected (backoff {}ms) in call {} to '{}': {}", + backoffMillis, numCalls, method, ex.getMessage()); + } + Thread.sleep(backoffMillis); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml new file mode 100644 index 00000000000..66a052f6467 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml @@ -0,0 +1,41 @@ + + + + + + + ANY + + + + + + 1 + Alice + + asset + + + 2 + Bob + + expense + + + 3 + Bobby Tables + + asset + + + 4 + Doris + + expense + + + diff --git a/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql new file mode 100644 index 00000000000..349f461aa39 --- /dev/null +++ b/src/current/_includes/example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql @@ -0,0 +1,7 @@ +create table account +( + id int not null primary key default unique_rowid(), + balance numeric(19, 2) not null, + name varchar(128) not null, + type varchar(25) not null +); diff --git a/src/current/v23.1/build-a-csharp-app-with-cockroachdb.md b/src/current/v23.1/build-a-csharp-app-with-cockroachdb.md index 115abf8febd..6e71dfb298f 100644 --- a/src/current/v23.1/build-a-csharp-app-with-cockroachdb.md +++ b/src/current/v23.1/build-a-csharp-app-with-cockroachdb.md @@ -69,7 +69,7 @@ Replace the contents of the `Program.cs` file that was automatically generated i {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/basic.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/basic.cs %} ~~~ #### Run the basic example @@ -99,7 +99,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs %} ~~~ @@ -108,7 +108,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} ~~~ diff --git a/src/current/v23.1/build-a-go-app-with-cockroachdb-gorm.md b/src/current/v23.1/build-a-go-app-with-cockroachdb-gorm.md index 23ee58cd997..aac3820127f 100644 --- a/src/current/v23.1/build-a-go-app-with-cockroachdb-gorm.md +++ b/src/current/v23.1/build-a-go-app-with-cockroachdb-gorm.md @@ -39,7 +39,7 @@ The `main.go` file defines an `Account` struct that maps to a new `accounts` tab {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-gorm/master/main.go %} +{% include example-apps/cockroachlabs/example-app-go-gorm/master/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v23.1/build-a-go-app-with-cockroachdb.md b/src/current/v23.1/build-a-go-app-with-cockroachdb.md index 8a00ed10cb4..89ef7c4669e 100644 --- a/src/current/v23.1/build-a-go-app-with-cockroachdb.md +++ b/src/current/v23.1/build-a-go-app-with-cockroachdb.md @@ -35,7 +35,7 @@ The `main.go` file contains the code for `CREATE TABLE`, `INSERT`, `SELECT`, `UP {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-pgx/main/main.go %} +{% include example-apps/cockroachlabs/example-app-go-pgx/main/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v23.1/build-a-java-app-with-cockroachdb-hibernate.md b/src/current/v23.1/build-a-java-app-with-cockroachdb-hibernate.md index f6e4c60db7f..1a7428b6f4e 100644 --- a/src/current/v23.1/build-a-java-app-with-cockroachdb-hibernate.md +++ b/src/current/v23.1/build-a-java-app-with-cockroachdb-hibernate.md @@ -54,7 +54,7 @@ The contents of `Sample.java`: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} +{% include example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} ~~~

diff --git a/src/current/v23.1/build-a-java-app-with-cockroachdb.md b/src/current/v23.1/build-a-java-app-with-cockroachdb.md index 441fb2ad148..1e05c28ea60 100644 --- a/src/current/v23.1/build-a-java-app-with-cockroachdb.md +++ b/src/current/v23.1/build-a-java-app-with-cockroachdb.md @@ -55,7 +55,7 @@ The `BasicExample.java` file contains the code for `INSERT`, `SELECT`, and `UPDA {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} +{% include example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} ~~~ The sample app uses JDBC and the [Data Access Object (DAO)](https://wikipedia.org/wiki/Data_access_object) pattern to map Java methods to SQL operations. It consists of two classes: diff --git a/src/current/v23.1/build-a-nodejs-app-with-cockroachdb-prisma.md b/src/current/v23.1/build-a-nodejs-app-with-cockroachdb-prisma.md index 8d5170b8079..cce1d6e2349 100644 --- a/src/current/v23.1/build-a-nodejs-app-with-cockroachdb-prisma.md +++ b/src/current/v23.1/build-a-nodejs-app-with-cockroachdb-prisma.md @@ -89,7 +89,7 @@ The `index.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DEL {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-prisma/main/index.js %} +{% include example-apps/cockroachlabs/example-app-node-prisma/main/index.js %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v23.1/build-a-nodejs-app-with-cockroachdb.md b/src/current/v23.1/build-a-nodejs-app-with-cockroachdb.md index b12b32fac63..be7276c65f4 100644 --- a/src/current/v23.1/build-a-nodejs-app-with-cockroachdb.md +++ b/src/current/v23.1/build-a-nodejs-app-with-cockroachdb.md @@ -37,14 +37,14 @@ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ sql -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} ~~~ The `app.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DELETE` SQL operations: {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/app.js %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/app.js %} ~~~ All of the database operations are wrapped in a helper function named `retryTxn`. This function attempts to commit statements in the context of an explicit transaction. If a [retry error]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) is thrown, the wrapper will retry committing the transaction, with [exponential backoff](https://wikipedia.org/wiki/Exponential_backoff), until the maximum number of retries is reached (by default, 15). diff --git a/src/current/v23.1/build-a-python-app-with-cockroachdb-django.md b/src/current/v23.1/build-a-python-app-with-cockroachdb-django.md index 88320dbb3fa..25af8c2fca0 100644 --- a/src/current/v23.1/build-a-python-app-with-cockroachdb-django.md +++ b/src/current/v23.1/build-a-python-app-with-cockroachdb-django.md @@ -67,7 +67,7 @@ The `requirements.txt` file at the top level of the `example-app-python-django` {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-django/master/requirements.txt %} ~~~ This tutorial uses [`virtualenv`](https://virtualenv.pypa.io) for dependency management. @@ -135,7 +135,7 @@ Start by building some [models](https://docs.djangoproject.com/en/3.1/topics/db/ {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} ~~~ In this file, we define some simple classes that map to the tables in the cluster. @@ -146,7 +146,7 @@ Next, build out some [class-based views](https://docs.djangoproject.com/en/3.1/t {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} ~~~ This file defines the application's views as classes. Each view class corresponds to one of the table classes defined in `models.py`. The methods of these classes define read and write transactions on the tables in the database. @@ -159,7 +159,7 @@ Lastly, define some [URL routes](https://docs.djangoproject.com/en/3.1/topics/ht {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} ~~~ ## Step 5. Initialize the database diff --git a/src/current/v23.1/build-a-python-app-with-cockroachdb-sqlalchemy.md b/src/current/v23.1/build-a-python-app-with-cockroachdb-sqlalchemy.md index 69ef20d0bc1..4b2a296e5f0 100644 --- a/src/current/v23.1/build-a-python-app-with-cockroachdb-sqlalchemy.md +++ b/src/current/v23.1/build-a-python-app-with-cockroachdb-sqlalchemy.md @@ -40,28 +40,28 @@ The `requirements.txt` file includes the required libraries to connect to Cockro {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} ~~~ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} ~~~ The `models.py` uses SQLAlchemy to map the `Accounts` table to a Python object: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} ~~~ The `main.py` uses SQLAlchemy to map Python methods to SQL operations: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} ~~~ `main.py` also executes the `main` method of the program. diff --git a/src/current/v23.1/build-a-rust-app-with-cockroachdb.md b/src/current/v23.1/build-a-rust-app-with-cockroachdb.md index 4ca08938824..46b9cdea10c 100644 --- a/src/current/v23.1/build-a-rust-app-with-cockroachdb.md +++ b/src/current/v23.1/build-a-rust-app-with-cockroachdb.md @@ -39,7 +39,7 @@ The `Cargo.toml` file is the configuration file for the example, and sets the de {% include_cached copy-clipboard.html %} ~~~ toml -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} ~~~ The `main` function is the entry point for the application, with the code for connecting to the cluster, creating the `accounts` table, creating accounts in that table, and transferring money between two accounts. @@ -52,14 +52,14 @@ CockroachDB may require the [client to retry a transaction]({% link {{ page.vers {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN execute_txn || END execute_txn %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs %} ~~~ The `transfer_funds` function calls `execute_txn` to perform the actual transfer of funds from one account to the other. {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN transfer_funds || END transfer_funds %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs %} ~~~ ## Step 3. Run the code diff --git a/src/current/v23.1/build-a-spring-app-with-cockroachdb-jdbc.md b/src/current/v23.1/build-a-spring-app-with-cockroachdb-jdbc.md index 812c6981ece..a5e5d122dbb 100644 --- a/src/current/v23.1/build-a-spring-app-with-cockroachdb-jdbc.md +++ b/src/current/v23.1/build-a-spring-app-with-cockroachdb-jdbc.md @@ -604,7 +604,7 @@ Here are the contents of [`JdbcApplication.java`](https://github.com/cockroachla {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} ~~~ The annotations listed at the top of the `JdbcApplication` class definition declare some important configuration properties for the entire application: @@ -629,14 +629,14 @@ Liquibase uses [changelog files](https://docs.liquibase.com/concepts/basic/chang {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -694,7 +694,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} ~~~ ### Hypermedia representation @@ -705,7 +705,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -718,7 +718,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for generic [CRUD operations](https://wikipedia.org/wiki/Create,_read,_update_and_delete) called `CrudRepository`. To support [pagination queries]({% link {{ page.version.version }}/pagination.md %}), repositories in other Spring Data modules, like those in Spring Data JPA, usually extend a subinterface of `CrudRepository`, called `PagingAndSortingRepository`, that includes pagination and sorting methods. At the time this sample application was created, Spring Data JDBC did not support pagination. As a result, `AccountRepository` extends a custom repository, called `PagedAccountRepository`, to provide basic [`LIMIT`/`OFFSET` pagination]({% link {{ page.version.version }}/pagination.md %}) on queries against the `accounts` table. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/#jdbc.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -735,7 +735,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -771,7 +771,7 @@ The `TransactionHintsAspect` class, declared as an aspect with the [`@Aspect` an {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. @@ -788,7 +788,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` pointcut definition is identical to the one declared in `TransactionHintsAspect`. The `execution` designator matches all methods in the `io.roach.` namespace, and the `@annotation` designator limits the matches to methods with the `@Transactional` annotation. diff --git a/src/current/v23.1/build-a-spring-app-with-cockroachdb-jpa.md b/src/current/v23.1/build-a-spring-app-with-cockroachdb-jpa.md index 27b676716b5..91203592d92 100644 --- a/src/current/v23.1/build-a-spring-app-with-cockroachdb-jpa.md +++ b/src/current/v23.1/build-a-spring-app-with-cockroachdb-jpa.md @@ -517,7 +517,7 @@ Here are the contents of [`JpaApplication.java`](https://github.com/cockroachlab {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} ~~~ The annotations listed at the top of the `JpaApplication` class definition declare some important configuration properties for the entire application: @@ -540,14 +540,14 @@ Liquibase uses files called [changelogs](https://docs.liquibase.com/concepts/bas {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -596,7 +596,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} ~~~ Spring Data JPA supports standard Java Persistence API (JPA) annotations for domain entity class definitions. The `Account` class definition uses these annotations to create the `accounts` table entity: @@ -616,7 +616,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -629,7 +629,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for JPA data access called `JpaRepository`. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -646,7 +646,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -677,7 +677,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. diff --git a/src/current/v23.1/movr-flask-application.md b/src/current/v23.1/movr-flask-application.md index 34ed44f87a0..c150452b775 100644 --- a/src/current/v23.1/movr-flask-application.md +++ b/src/current/v23.1/movr-flask-application.md @@ -88,7 +88,7 @@ After completing the [Create a Multi-Region Database Schema]({% link {{ page.ver Open [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), and look at the first 10 lines of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__front.py %} ~~~ The first data structure that the file imports is `declarative_base`, a constructor for the [declarative base class](https://docs.sqlalchemy.org/orm/extensions/declarative/api.html#sqlalchemy.ext.declarative.declarative_base), built on SQLAlchemy's Declarative extension. All mapped objects inherit from this object. We assign a declarative base object to the `Base` variable right below the imports. @@ -104,7 +104,7 @@ Recall that each instance of a table class represents a row in the table, so we Take a look at the `User` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START User ||# END User %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__user.py %} ~~~ The `User` class has the following attributes: @@ -119,7 +119,7 @@ The `User` class has the following attributes: Next, look at the `Vehicle` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Vehicle ||# END Vehicle %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__vehicle.py %} ~~~ Recall that the `vehicles` table contains more columns and data types than the `users` table. It also contains a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) (on the `users` table), and a default value. These differences are reflected in the `Vehicle` class. @@ -129,7 +129,7 @@ Recall that the `vehicles` table contains more columns and data types than the ` Lastly, there's the `Ride` class: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Ride ||# END Ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__ride.py %} ~~~ The `rides` table has three foreign key constraints, one on the `users` table and two on the `vehicles` table. @@ -184,7 +184,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` `transactions.py` imports all of the table classes that we defined in [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), in addition to some standard Python data structures needed to generate correctly-typed row values that the ORM can write to the database. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__front.py %} ~~~ ##### Reading @@ -192,7 +192,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` A common query that a client might want to run is a read of the `rides` table. The transaction callback function for this query is defined here as `get_rides_txn()`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_rides_txn ||# END get_rides_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-rides-txn.py %} ~~~ The `get_rides_txn()` function takes a `Session` object and a `rider_id` string as its inputs, and it outputs a list of dictionaries containing the columns-value pairs of a row in the `rides` table. To retrieve the data from the database bound to a particular `Session` object, we use `Session.query()`, a method of the `Session` class. This method returns a `Query` object, with methods for filtering and ordering query results. @@ -202,7 +202,7 @@ Note that `get_rides_txn()` gets all rides for a specific rider, which might be Another common query would be to read the registered vehicles in a particular city, to see which vehicles are available for riding. Unlike `get_rides_txn()`, the `get_vehicles_txn()` function takes the `city` string as an input. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_vehicles_txn ||# END get_vehicles_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-vehicles-txn.py %} ~~~ This function filters the query on the `city` column. `vehicle` rows with the same value for `city` are inserted from the same region, making `city` values implicitly correspond to a specific region. Because the `vehicles` table has a `REGIONAL BY ROW` locality, CockroachDB can locality-optimize queries from nodes with a locality matching the [hidden `crdb_region` column]({% link {{ page.version.version }}/movr-flask-database.md %}#table-locality). This limits latency, as the query only needs to travel to database deployments in a single region. @@ -214,7 +214,7 @@ There are two basic types of write operations: creating new rows and updating ex For example, `start_ride_txn()`, which is called when a user starts a ride, adds a new row to the `rides` table, and then updates a row in the `vehicles` table. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START start_ride_txn ||# END start_ride_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__start-ride-txn.py %} ~~~ The function takes the `city` string, `rider_id` UUID, `rider_city` string, and `vehicle_id` UUID as inputs. It queries the `vehicles` table for all vehicles of a specific ID. It also creates a `Ride` object, representing a row of the `rides` table. To add the ride to the table in the database bound to the `Session`, the function calls `Session.add()`. To update a row in the `vehicles` table, it modifies the object attribute. `start_ride_txn()` is called by `run_transaction()`, which commits the transaction to the database. @@ -230,7 +230,7 @@ The `MovR` class, defined in [`movr/movr.py`](https://github.com/cockroachlabs/m Let's start with the beginning of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__front.py %} ~~~ `movr.py` first imports the transaction callback functions that we defined in [`movr/transactions.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/transactions.py). It then imports the `run_transaction()` function. The `MovR` class methods call `run_transaction()` to execute the transaction callback functions as transactions. @@ -248,7 +248,7 @@ We've already defined the transaction logic in the transaction callback function For example, look at the `start_ride()` method, the method to which frontend requests to start a ride are routed: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START start_ride ||# END start_ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__start-ride.py %} ~~~ This method takes some keyword arguments, and then returns a `run_transaction()` call. It passes `sessionmaker(bind=self.engine)` as the first argument to `run_transaction()`, which creates a new `Session` object that binds to the `Engine` instance initialized by the `MovR` constructor. It also passes `city`, `rider_id`, `rider_city`, and `vehicle_id`, values passed from the frontend request, as inputs. These are the same keyword arguments, and should be of the same types, as the inputs for the [transaction callback function](#writing) `start_ride_txn()`. @@ -266,7 +266,7 @@ Most of the web application components are found in the `web` and `templates` fo We store the Flask configuration settings in [a `Config` class](https://flask.palletsprojects.com/config/#development-production), defined in [`web/config.py`](https://github.com/cockroachlabs/movr-flask/blob/master/web/config.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} ~~~ This file imports the `os` library, which is used to read from environment variables. When debugging a local deployment, these environment variables are set by the `.env` file that `Pipenv` reads. In a multi-region deployment, the environment variables are set by the `Dockerfile`, and by the [managed cloud deployment service]({% link {{ page.version.version }}/movr-flask-deployment.md %}). @@ -282,7 +282,7 @@ We will not go into much detail about these forms. The important thing to know i The `CredentialForm` class, for example, defines the fields of the login form that users interface with to send a login request to the server: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START CredentialForm ||# END CredentialForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__credentialform.py %} ~~~ Most of the forms defined on this page take the inputs for database reads and writes. @@ -290,7 +290,7 @@ Most of the forms defined on this page take the inputs for database reads and wr `VehicleForm`, for example, defines the fields of the vehicle registration form. Users enter information about a vehicle they would like to register, and the data is routed to the `add_vehicle()` method defined in [`movr/movr.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/movr.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START VehicleForm ||# END VehicleForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__vehicleform.py %} ~~~ ### Initialization @@ -300,7 +300,7 @@ Most of the forms defined on this page take the inputs for database reads and wr Let's look at the first ten lines of `server.py`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__front.py %} ~~~ The first line imports standard Flask libraries for connecting, routing, and rendering web pages. The next three lines import some libraries from the Flask ecosystem, for [bootstrapping](https://pythonhosted.org/Flask-Bootstrap/), [authentication](https://flask-login.readthedocs.io/), and [security](https://github.com/pallets/werkzeug/blob/master/src/werkzeug/security.py). @@ -316,7 +316,7 @@ Finally, we import the `DBAPIError` type from `sqlalchemy`, for error handling. The next five or so lines initialize the application: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START init ||# END init %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__init.py %} ~~~ Calling the `Flask()` constructor initializes our Flask web server. By assigning this to a variable (`app`), we can then configure the application, store variables in its attributes, and call it with functions from other libraries, to add features and functionality to the application. @@ -328,7 +328,7 @@ Note that we also define a `protocol` variable that the application later uses t After initializing the application, we can connect to the database: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START connect ||# END connect %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__connect.py %} ~~~ These two lines connect the application to the database. First the application retrieves the connection string that is stored as a configuration variable of the `app`. Then it calls the `MovR()` constructor to establish a connection to the database at the location we provided to the `Config` object. @@ -340,7 +340,7 @@ User authentication is handled with the [`Flask-Login`](https://flask-login.read To control whether certain routes are accessible to a client session, we define a [`user_loader()` function](https://flask-login.readthedocs.io/#flask_login.LoginManager.user_loader): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START user_loader ||# END user_loader %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__user-loader.py %} ~~~ To restrict access to a certain page to users that are logged in with the [`LoginManager`](https://flask-login.readthedocs.io/#flask_login.LoginManager), we add the `@login_required` decorator function to the route. We'll go over some examples in the [Routing](#routing) section below. @@ -362,7 +362,7 @@ In addition to calling these functions, and some other standard Flask and Python For example, look at the `login()` route: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START login_page ||# END login_page %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__login-page.py %} ~~~ ### Client Location diff --git a/src/current/v23.1/movr-flask-database.md b/src/current/v23.1/movr-flask-database.md index c77c24a0ab4..69ebbd4b013 100644 --- a/src/current/v23.1/movr-flask-database.md +++ b/src/current/v23.1/movr-flask-database.md @@ -49,7 +49,7 @@ Here is the [`CREATE DATABASE`]({% link {{ page.version.version }}/create-databa {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START database ||-- END database %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__database.sql %} ~~~ Note that `movr` has the following [database regions]({% link {{ page.version.version }}/multiregion-overview.md %}#database-regions), which correspond to regions in Google Cloud: @@ -78,14 +78,14 @@ Here is the `CREATE TABLE` statement for the `users` table: {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START users ||-- END users %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__users.sql %} ~~~ ## The `vehicles` table {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START vehicles ||-- END vehicles %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__vehicles.sql %} ~~~ Note that the `vehicles` table has a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) on the `users` table, for the `city` and `owner_id` columns. This guarantees that a vehicle is registered to a particular user (i.e., an "owner") in the city where that user is registered. @@ -94,7 +94,7 @@ Note that the `vehicles` table has a [foreign key constraint]({% link {{ page.ve {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START rides ||-- END rides %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__rides.sql %} ~~~ Note that, like the `vehicles` table, the `rides` table has foreign key constraints. These constraints are on the `users` and the `vehicles` tables. diff --git a/src/current/v23.2/build-a-csharp-app-with-cockroachdb.md b/src/current/v23.2/build-a-csharp-app-with-cockroachdb.md index 115abf8febd..6e71dfb298f 100644 --- a/src/current/v23.2/build-a-csharp-app-with-cockroachdb.md +++ b/src/current/v23.2/build-a-csharp-app-with-cockroachdb.md @@ -69,7 +69,7 @@ Replace the contents of the `Program.cs` file that was automatically generated i {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/basic.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/basic.cs %} ~~~ #### Run the basic example @@ -99,7 +99,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs %} ~~~
@@ -108,7 +108,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} ~~~ diff --git a/src/current/v23.2/build-a-go-app-with-cockroachdb-gorm.md b/src/current/v23.2/build-a-go-app-with-cockroachdb-gorm.md index 23ee58cd997..aac3820127f 100644 --- a/src/current/v23.2/build-a-go-app-with-cockroachdb-gorm.md +++ b/src/current/v23.2/build-a-go-app-with-cockroachdb-gorm.md @@ -39,7 +39,7 @@ The `main.go` file defines an `Account` struct that maps to a new `accounts` tab {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-gorm/master/main.go %} +{% include example-apps/cockroachlabs/example-app-go-gorm/master/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v23.2/build-a-go-app-with-cockroachdb.md b/src/current/v23.2/build-a-go-app-with-cockroachdb.md index 8a00ed10cb4..89ef7c4669e 100644 --- a/src/current/v23.2/build-a-go-app-with-cockroachdb.md +++ b/src/current/v23.2/build-a-go-app-with-cockroachdb.md @@ -35,7 +35,7 @@ The `main.go` file contains the code for `CREATE TABLE`, `INSERT`, `SELECT`, `UP {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-pgx/main/main.go %} +{% include example-apps/cockroachlabs/example-app-go-pgx/main/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v23.2/build-a-java-app-with-cockroachdb-hibernate.md b/src/current/v23.2/build-a-java-app-with-cockroachdb-hibernate.md index f6e4c60db7f..1a7428b6f4e 100644 --- a/src/current/v23.2/build-a-java-app-with-cockroachdb-hibernate.md +++ b/src/current/v23.2/build-a-java-app-with-cockroachdb-hibernate.md @@ -54,7 +54,7 @@ The contents of `Sample.java`: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} +{% include example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} ~~~
diff --git a/src/current/v23.2/build-a-java-app-with-cockroachdb.md b/src/current/v23.2/build-a-java-app-with-cockroachdb.md index 441fb2ad148..1e05c28ea60 100644 --- a/src/current/v23.2/build-a-java-app-with-cockroachdb.md +++ b/src/current/v23.2/build-a-java-app-with-cockroachdb.md @@ -55,7 +55,7 @@ The `BasicExample.java` file contains the code for `INSERT`, `SELECT`, and `UPDA {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} +{% include example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} ~~~ The sample app uses JDBC and the [Data Access Object (DAO)](https://wikipedia.org/wiki/Data_access_object) pattern to map Java methods to SQL operations. It consists of two classes: diff --git a/src/current/v23.2/build-a-nodejs-app-with-cockroachdb-prisma.md b/src/current/v23.2/build-a-nodejs-app-with-cockroachdb-prisma.md index 560acba96bb..eb8c6d53244 100644 --- a/src/current/v23.2/build-a-nodejs-app-with-cockroachdb-prisma.md +++ b/src/current/v23.2/build-a-nodejs-app-with-cockroachdb-prisma.md @@ -89,7 +89,7 @@ The `index.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DEL {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-prisma/main/index.js %} +{% include example-apps/cockroachlabs/example-app-node-prisma/main/index.js %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v23.2/build-a-nodejs-app-with-cockroachdb.md b/src/current/v23.2/build-a-nodejs-app-with-cockroachdb.md index b12b32fac63..be7276c65f4 100644 --- a/src/current/v23.2/build-a-nodejs-app-with-cockroachdb.md +++ b/src/current/v23.2/build-a-nodejs-app-with-cockroachdb.md @@ -37,14 +37,14 @@ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ sql -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} ~~~ The `app.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DELETE` SQL operations: {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/app.js %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/app.js %} ~~~ All of the database operations are wrapped in a helper function named `retryTxn`. This function attempts to commit statements in the context of an explicit transaction. If a [retry error]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) is thrown, the wrapper will retry committing the transaction, with [exponential backoff](https://wikipedia.org/wiki/Exponential_backoff), until the maximum number of retries is reached (by default, 15). diff --git a/src/current/v23.2/build-a-python-app-with-cockroachdb-django.md b/src/current/v23.2/build-a-python-app-with-cockroachdb-django.md index 88320dbb3fa..25af8c2fca0 100644 --- a/src/current/v23.2/build-a-python-app-with-cockroachdb-django.md +++ b/src/current/v23.2/build-a-python-app-with-cockroachdb-django.md @@ -67,7 +67,7 @@ The `requirements.txt` file at the top level of the `example-app-python-django` {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-django/master/requirements.txt %} ~~~ This tutorial uses [`virtualenv`](https://virtualenv.pypa.io) for dependency management. @@ -135,7 +135,7 @@ Start by building some [models](https://docs.djangoproject.com/en/3.1/topics/db/ {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} ~~~ In this file, we define some simple classes that map to the tables in the cluster. @@ -146,7 +146,7 @@ Next, build out some [class-based views](https://docs.djangoproject.com/en/3.1/t {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} ~~~ This file defines the application's views as classes. Each view class corresponds to one of the table classes defined in `models.py`. The methods of these classes define read and write transactions on the tables in the database. @@ -159,7 +159,7 @@ Lastly, define some [URL routes](https://docs.djangoproject.com/en/3.1/topics/ht {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} ~~~ ## Step 5. Initialize the database diff --git a/src/current/v23.2/build-a-python-app-with-cockroachdb-sqlalchemy.md b/src/current/v23.2/build-a-python-app-with-cockroachdb-sqlalchemy.md index 69ef20d0bc1..4b2a296e5f0 100644 --- a/src/current/v23.2/build-a-python-app-with-cockroachdb-sqlalchemy.md +++ b/src/current/v23.2/build-a-python-app-with-cockroachdb-sqlalchemy.md @@ -40,28 +40,28 @@ The `requirements.txt` file includes the required libraries to connect to Cockro {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} ~~~ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} ~~~ The `models.py` uses SQLAlchemy to map the `Accounts` table to a Python object: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} ~~~ The `main.py` uses SQLAlchemy to map Python methods to SQL operations: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} ~~~ `main.py` also executes the `main` method of the program. diff --git a/src/current/v23.2/build-a-rust-app-with-cockroachdb.md b/src/current/v23.2/build-a-rust-app-with-cockroachdb.md index 4ca08938824..46b9cdea10c 100644 --- a/src/current/v23.2/build-a-rust-app-with-cockroachdb.md +++ b/src/current/v23.2/build-a-rust-app-with-cockroachdb.md @@ -39,7 +39,7 @@ The `Cargo.toml` file is the configuration file for the example, and sets the de {% include_cached copy-clipboard.html %} ~~~ toml -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} ~~~ The `main` function is the entry point for the application, with the code for connecting to the cluster, creating the `accounts` table, creating accounts in that table, and transferring money between two accounts. @@ -52,14 +52,14 @@ CockroachDB may require the [client to retry a transaction]({% link {{ page.vers {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN execute_txn || END execute_txn %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs %} ~~~ The `transfer_funds` function calls `execute_txn` to perform the actual transfer of funds from one account to the other. {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN transfer_funds || END transfer_funds %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs %} ~~~ ## Step 3. Run the code diff --git a/src/current/v23.2/build-a-spring-app-with-cockroachdb-jdbc.md b/src/current/v23.2/build-a-spring-app-with-cockroachdb-jdbc.md index 812c6981ece..a5e5d122dbb 100644 --- a/src/current/v23.2/build-a-spring-app-with-cockroachdb-jdbc.md +++ b/src/current/v23.2/build-a-spring-app-with-cockroachdb-jdbc.md @@ -604,7 +604,7 @@ Here are the contents of [`JdbcApplication.java`](https://github.com/cockroachla {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} ~~~ The annotations listed at the top of the `JdbcApplication` class definition declare some important configuration properties for the entire application: @@ -629,14 +629,14 @@ Liquibase uses [changelog files](https://docs.liquibase.com/concepts/basic/chang {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -694,7 +694,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} ~~~ ### Hypermedia representation @@ -705,7 +705,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -718,7 +718,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for generic [CRUD operations](https://wikipedia.org/wiki/Create,_read,_update_and_delete) called `CrudRepository`. To support [pagination queries]({% link {{ page.version.version }}/pagination.md %}), repositories in other Spring Data modules, like those in Spring Data JPA, usually extend a subinterface of `CrudRepository`, called `PagingAndSortingRepository`, that includes pagination and sorting methods. At the time this sample application was created, Spring Data JDBC did not support pagination. As a result, `AccountRepository` extends a custom repository, called `PagedAccountRepository`, to provide basic [`LIMIT`/`OFFSET` pagination]({% link {{ page.version.version }}/pagination.md %}) on queries against the `accounts` table. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/#jdbc.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -735,7 +735,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -771,7 +771,7 @@ The `TransactionHintsAspect` class, declared as an aspect with the [`@Aspect` an {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. @@ -788,7 +788,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` pointcut definition is identical to the one declared in `TransactionHintsAspect`. The `execution` designator matches all methods in the `io.roach.` namespace, and the `@annotation` designator limits the matches to methods with the `@Transactional` annotation. diff --git a/src/current/v23.2/build-a-spring-app-with-cockroachdb-jpa.md b/src/current/v23.2/build-a-spring-app-with-cockroachdb-jpa.md index 27b676716b5..91203592d92 100644 --- a/src/current/v23.2/build-a-spring-app-with-cockroachdb-jpa.md +++ b/src/current/v23.2/build-a-spring-app-with-cockroachdb-jpa.md @@ -517,7 +517,7 @@ Here are the contents of [`JpaApplication.java`](https://github.com/cockroachlab {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} ~~~ The annotations listed at the top of the `JpaApplication` class definition declare some important configuration properties for the entire application: @@ -540,14 +540,14 @@ Liquibase uses files called [changelogs](https://docs.liquibase.com/concepts/bas {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -596,7 +596,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} ~~~ Spring Data JPA supports standard Java Persistence API (JPA) annotations for domain entity class definitions. The `Account` class definition uses these annotations to create the `accounts` table entity: @@ -616,7 +616,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -629,7 +629,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for JPA data access called `JpaRepository`. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -646,7 +646,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -677,7 +677,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. diff --git a/src/current/v23.2/movr-flask-application.md b/src/current/v23.2/movr-flask-application.md index 34ed44f87a0..c150452b775 100644 --- a/src/current/v23.2/movr-flask-application.md +++ b/src/current/v23.2/movr-flask-application.md @@ -88,7 +88,7 @@ After completing the [Create a Multi-Region Database Schema]({% link {{ page.ver Open [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), and look at the first 10 lines of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__front.py %} ~~~ The first data structure that the file imports is `declarative_base`, a constructor for the [declarative base class](https://docs.sqlalchemy.org/orm/extensions/declarative/api.html#sqlalchemy.ext.declarative.declarative_base), built on SQLAlchemy's Declarative extension. All mapped objects inherit from this object. We assign a declarative base object to the `Base` variable right below the imports. @@ -104,7 +104,7 @@ Recall that each instance of a table class represents a row in the table, so we Take a look at the `User` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START User ||# END User %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__user.py %} ~~~ The `User` class has the following attributes: @@ -119,7 +119,7 @@ The `User` class has the following attributes: Next, look at the `Vehicle` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Vehicle ||# END Vehicle %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__vehicle.py %} ~~~ Recall that the `vehicles` table contains more columns and data types than the `users` table. It also contains a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) (on the `users` table), and a default value. These differences are reflected in the `Vehicle` class. @@ -129,7 +129,7 @@ Recall that the `vehicles` table contains more columns and data types than the ` Lastly, there's the `Ride` class: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Ride ||# END Ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__ride.py %} ~~~ The `rides` table has three foreign key constraints, one on the `users` table and two on the `vehicles` table. @@ -184,7 +184,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` `transactions.py` imports all of the table classes that we defined in [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), in addition to some standard Python data structures needed to generate correctly-typed row values that the ORM can write to the database. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__front.py %} ~~~ ##### Reading @@ -192,7 +192,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` A common query that a client might want to run is a read of the `rides` table. The transaction callback function for this query is defined here as `get_rides_txn()`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_rides_txn ||# END get_rides_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-rides-txn.py %} ~~~ The `get_rides_txn()` function takes a `Session` object and a `rider_id` string as its inputs, and it outputs a list of dictionaries containing the columns-value pairs of a row in the `rides` table. To retrieve the data from the database bound to a particular `Session` object, we use `Session.query()`, a method of the `Session` class. This method returns a `Query` object, with methods for filtering and ordering query results. @@ -202,7 +202,7 @@ Note that `get_rides_txn()` gets all rides for a specific rider, which might be Another common query would be to read the registered vehicles in a particular city, to see which vehicles are available for riding. Unlike `get_rides_txn()`, the `get_vehicles_txn()` function takes the `city` string as an input. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_vehicles_txn ||# END get_vehicles_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-vehicles-txn.py %} ~~~ This function filters the query on the `city` column. `vehicle` rows with the same value for `city` are inserted from the same region, making `city` values implicitly correspond to a specific region. Because the `vehicles` table has a `REGIONAL BY ROW` locality, CockroachDB can locality-optimize queries from nodes with a locality matching the [hidden `crdb_region` column]({% link {{ page.version.version }}/movr-flask-database.md %}#table-locality). This limits latency, as the query only needs to travel to database deployments in a single region. @@ -214,7 +214,7 @@ There are two basic types of write operations: creating new rows and updating ex For example, `start_ride_txn()`, which is called when a user starts a ride, adds a new row to the `rides` table, and then updates a row in the `vehicles` table. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START start_ride_txn ||# END start_ride_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__start-ride-txn.py %} ~~~ The function takes the `city` string, `rider_id` UUID, `rider_city` string, and `vehicle_id` UUID as inputs. It queries the `vehicles` table for all vehicles of a specific ID. It also creates a `Ride` object, representing a row of the `rides` table. To add the ride to the table in the database bound to the `Session`, the function calls `Session.add()`. To update a row in the `vehicles` table, it modifies the object attribute. `start_ride_txn()` is called by `run_transaction()`, which commits the transaction to the database. @@ -230,7 +230,7 @@ The `MovR` class, defined in [`movr/movr.py`](https://github.com/cockroachlabs/m Let's start with the beginning of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__front.py %} ~~~ `movr.py` first imports the transaction callback functions that we defined in [`movr/transactions.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/transactions.py). It then imports the `run_transaction()` function. The `MovR` class methods call `run_transaction()` to execute the transaction callback functions as transactions. @@ -248,7 +248,7 @@ We've already defined the transaction logic in the transaction callback function For example, look at the `start_ride()` method, the method to which frontend requests to start a ride are routed: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START start_ride ||# END start_ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__start-ride.py %} ~~~ This method takes some keyword arguments, and then returns a `run_transaction()` call. It passes `sessionmaker(bind=self.engine)` as the first argument to `run_transaction()`, which creates a new `Session` object that binds to the `Engine` instance initialized by the `MovR` constructor. It also passes `city`, `rider_id`, `rider_city`, and `vehicle_id`, values passed from the frontend request, as inputs. These are the same keyword arguments, and should be of the same types, as the inputs for the [transaction callback function](#writing) `start_ride_txn()`. @@ -266,7 +266,7 @@ Most of the web application components are found in the `web` and `templates` fo We store the Flask configuration settings in [a `Config` class](https://flask.palletsprojects.com/config/#development-production), defined in [`web/config.py`](https://github.com/cockroachlabs/movr-flask/blob/master/web/config.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} ~~~ This file imports the `os` library, which is used to read from environment variables. When debugging a local deployment, these environment variables are set by the `.env` file that `Pipenv` reads. In a multi-region deployment, the environment variables are set by the `Dockerfile`, and by the [managed cloud deployment service]({% link {{ page.version.version }}/movr-flask-deployment.md %}). @@ -282,7 +282,7 @@ We will not go into much detail about these forms. The important thing to know i The `CredentialForm` class, for example, defines the fields of the login form that users interface with to send a login request to the server: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START CredentialForm ||# END CredentialForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__credentialform.py %} ~~~ Most of the forms defined on this page take the inputs for database reads and writes. @@ -290,7 +290,7 @@ Most of the forms defined on this page take the inputs for database reads and wr `VehicleForm`, for example, defines the fields of the vehicle registration form. Users enter information about a vehicle they would like to register, and the data is routed to the `add_vehicle()` method defined in [`movr/movr.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/movr.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START VehicleForm ||# END VehicleForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__vehicleform.py %} ~~~ ### Initialization @@ -300,7 +300,7 @@ Most of the forms defined on this page take the inputs for database reads and wr Let's look at the first ten lines of `server.py`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__front.py %} ~~~ The first line imports standard Flask libraries for connecting, routing, and rendering web pages. The next three lines import some libraries from the Flask ecosystem, for [bootstrapping](https://pythonhosted.org/Flask-Bootstrap/), [authentication](https://flask-login.readthedocs.io/), and [security](https://github.com/pallets/werkzeug/blob/master/src/werkzeug/security.py). @@ -316,7 +316,7 @@ Finally, we import the `DBAPIError` type from `sqlalchemy`, for error handling. The next five or so lines initialize the application: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START init ||# END init %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__init.py %} ~~~ Calling the `Flask()` constructor initializes our Flask web server. By assigning this to a variable (`app`), we can then configure the application, store variables in its attributes, and call it with functions from other libraries, to add features and functionality to the application. @@ -328,7 +328,7 @@ Note that we also define a `protocol` variable that the application later uses t After initializing the application, we can connect to the database: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START connect ||# END connect %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__connect.py %} ~~~ These two lines connect the application to the database. First the application retrieves the connection string that is stored as a configuration variable of the `app`. Then it calls the `MovR()` constructor to establish a connection to the database at the location we provided to the `Config` object. @@ -340,7 +340,7 @@ User authentication is handled with the [`Flask-Login`](https://flask-login.read To control whether certain routes are accessible to a client session, we define a [`user_loader()` function](https://flask-login.readthedocs.io/#flask_login.LoginManager.user_loader): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START user_loader ||# END user_loader %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__user-loader.py %} ~~~ To restrict access to a certain page to users that are logged in with the [`LoginManager`](https://flask-login.readthedocs.io/#flask_login.LoginManager), we add the `@login_required` decorator function to the route. We'll go over some examples in the [Routing](#routing) section below. @@ -362,7 +362,7 @@ In addition to calling these functions, and some other standard Flask and Python For example, look at the `login()` route: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START login_page ||# END login_page %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__login-page.py %} ~~~ ### Client Location diff --git a/src/current/v23.2/movr-flask-database.md b/src/current/v23.2/movr-flask-database.md index c77c24a0ab4..69ebbd4b013 100644 --- a/src/current/v23.2/movr-flask-database.md +++ b/src/current/v23.2/movr-flask-database.md @@ -49,7 +49,7 @@ Here is the [`CREATE DATABASE`]({% link {{ page.version.version }}/create-databa {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START database ||-- END database %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__database.sql %} ~~~ Note that `movr` has the following [database regions]({% link {{ page.version.version }}/multiregion-overview.md %}#database-regions), which correspond to regions in Google Cloud: @@ -78,14 +78,14 @@ Here is the `CREATE TABLE` statement for the `users` table: {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START users ||-- END users %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__users.sql %} ~~~ ## The `vehicles` table {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START vehicles ||-- END vehicles %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__vehicles.sql %} ~~~ Note that the `vehicles` table has a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) on the `users` table, for the `city` and `owner_id` columns. This guarantees that a vehicle is registered to a particular user (i.e., an "owner") in the city where that user is registered. @@ -94,7 +94,7 @@ Note that the `vehicles` table has a [foreign key constraint]({% link {{ page.ve {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START rides ||-- END rides %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__rides.sql %} ~~~ Note that, like the `vehicles` table, the `rides` table has foreign key constraints. These constraints are on the `users` and the `vehicles` tables. diff --git a/src/current/v24.1/build-a-csharp-app-with-cockroachdb.md b/src/current/v24.1/build-a-csharp-app-with-cockroachdb.md index 115abf8febd..6e71dfb298f 100644 --- a/src/current/v24.1/build-a-csharp-app-with-cockroachdb.md +++ b/src/current/v24.1/build-a-csharp-app-with-cockroachdb.md @@ -69,7 +69,7 @@ Replace the contents of the `Program.cs` file that was automatically generated i {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/basic.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/basic.cs %} ~~~ #### Run the basic example @@ -99,7 +99,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs %} ~~~
@@ -108,7 +108,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} ~~~ diff --git a/src/current/v24.1/build-a-go-app-with-cockroachdb-gorm.md b/src/current/v24.1/build-a-go-app-with-cockroachdb-gorm.md index 23ee58cd997..aac3820127f 100644 --- a/src/current/v24.1/build-a-go-app-with-cockroachdb-gorm.md +++ b/src/current/v24.1/build-a-go-app-with-cockroachdb-gorm.md @@ -39,7 +39,7 @@ The `main.go` file defines an `Account` struct that maps to a new `accounts` tab {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-gorm/master/main.go %} +{% include example-apps/cockroachlabs/example-app-go-gorm/master/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v24.1/build-a-go-app-with-cockroachdb.md b/src/current/v24.1/build-a-go-app-with-cockroachdb.md index 8a00ed10cb4..89ef7c4669e 100644 --- a/src/current/v24.1/build-a-go-app-with-cockroachdb.md +++ b/src/current/v24.1/build-a-go-app-with-cockroachdb.md @@ -35,7 +35,7 @@ The `main.go` file contains the code for `CREATE TABLE`, `INSERT`, `SELECT`, `UP {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-pgx/main/main.go %} +{% include example-apps/cockroachlabs/example-app-go-pgx/main/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v24.1/build-a-java-app-with-cockroachdb-hibernate.md b/src/current/v24.1/build-a-java-app-with-cockroachdb-hibernate.md index f1f2ca4ec16..d81ed3054aa 100644 --- a/src/current/v24.1/build-a-java-app-with-cockroachdb-hibernate.md +++ b/src/current/v24.1/build-a-java-app-with-cockroachdb-hibernate.md @@ -54,7 +54,7 @@ The contents of `Sample.java`: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} +{% include example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} ~~~
diff --git a/src/current/v24.1/build-a-java-app-with-cockroachdb.md b/src/current/v24.1/build-a-java-app-with-cockroachdb.md index f7eca7a7245..cc384f4c5aa 100644 --- a/src/current/v24.1/build-a-java-app-with-cockroachdb.md +++ b/src/current/v24.1/build-a-java-app-with-cockroachdb.md @@ -55,7 +55,7 @@ The `BasicExample.java` file contains the code for `INSERT`, `SELECT`, and `UPDA {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} +{% include example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} ~~~ The sample app uses JDBC and the [Data Access Object (DAO)](https://wikipedia.org/wiki/Data_access_object) pattern to map Java methods to SQL operations. It consists of two classes: diff --git a/src/current/v24.1/build-a-nodejs-app-with-cockroachdb-prisma.md b/src/current/v24.1/build-a-nodejs-app-with-cockroachdb-prisma.md index 560acba96bb..eb8c6d53244 100644 --- a/src/current/v24.1/build-a-nodejs-app-with-cockroachdb-prisma.md +++ b/src/current/v24.1/build-a-nodejs-app-with-cockroachdb-prisma.md @@ -89,7 +89,7 @@ The `index.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DEL {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-prisma/main/index.js %} +{% include example-apps/cockroachlabs/example-app-node-prisma/main/index.js %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v24.1/build-a-nodejs-app-with-cockroachdb.md b/src/current/v24.1/build-a-nodejs-app-with-cockroachdb.md index 03afd891a66..77bb2eca608 100644 --- a/src/current/v24.1/build-a-nodejs-app-with-cockroachdb.md +++ b/src/current/v24.1/build-a-nodejs-app-with-cockroachdb.md @@ -39,14 +39,14 @@ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ sql -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} ~~~ The `app.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DELETE` SQL operations: {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/app.js %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/app.js %} ~~~ All of the database operations are wrapped in a helper function named `retryTxn`. This function attempts to commit statements in the context of an explicit transaction. If a [retry error]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) is thrown, the wrapper will retry committing the transaction, with [exponential backoff](https://wikipedia.org/wiki/Exponential_backoff), until the maximum number of retries is reached (by default, 15). diff --git a/src/current/v24.1/build-a-python-app-with-cockroachdb-django.md b/src/current/v24.1/build-a-python-app-with-cockroachdb-django.md index 88320dbb3fa..25af8c2fca0 100644 --- a/src/current/v24.1/build-a-python-app-with-cockroachdb-django.md +++ b/src/current/v24.1/build-a-python-app-with-cockroachdb-django.md @@ -67,7 +67,7 @@ The `requirements.txt` file at the top level of the `example-app-python-django` {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-django/master/requirements.txt %} ~~~ This tutorial uses [`virtualenv`](https://virtualenv.pypa.io) for dependency management. @@ -135,7 +135,7 @@ Start by building some [models](https://docs.djangoproject.com/en/3.1/topics/db/ {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} ~~~ In this file, we define some simple classes that map to the tables in the cluster. @@ -146,7 +146,7 @@ Next, build out some [class-based views](https://docs.djangoproject.com/en/3.1/t {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} ~~~ This file defines the application's views as classes. Each view class corresponds to one of the table classes defined in `models.py`. The methods of these classes define read and write transactions on the tables in the database. @@ -159,7 +159,7 @@ Lastly, define some [URL routes](https://docs.djangoproject.com/en/3.1/topics/ht {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} ~~~ ## Step 5. Initialize the database diff --git a/src/current/v24.1/build-a-python-app-with-cockroachdb-sqlalchemy.md b/src/current/v24.1/build-a-python-app-with-cockroachdb-sqlalchemy.md index c96ccfab463..5524cfe4ff8 100644 --- a/src/current/v24.1/build-a-python-app-with-cockroachdb-sqlalchemy.md +++ b/src/current/v24.1/build-a-python-app-with-cockroachdb-sqlalchemy.md @@ -40,28 +40,28 @@ The `requirements.txt` file includes the required libraries to connect to Cockro {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} ~~~ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} ~~~ The `models.py` uses SQLAlchemy to map the `Accounts` table to a Python object: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} ~~~ The `main.py` uses SQLAlchemy to map Python methods to SQL operations: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} ~~~ `main.py` also executes the `main` method of the program. diff --git a/src/current/v24.1/build-a-rust-app-with-cockroachdb.md b/src/current/v24.1/build-a-rust-app-with-cockroachdb.md index 4ca08938824..46b9cdea10c 100644 --- a/src/current/v24.1/build-a-rust-app-with-cockroachdb.md +++ b/src/current/v24.1/build-a-rust-app-with-cockroachdb.md @@ -39,7 +39,7 @@ The `Cargo.toml` file is the configuration file for the example, and sets the de {% include_cached copy-clipboard.html %} ~~~ toml -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} ~~~ The `main` function is the entry point for the application, with the code for connecting to the cluster, creating the `accounts` table, creating accounts in that table, and transferring money between two accounts. @@ -52,14 +52,14 @@ CockroachDB may require the [client to retry a transaction]({% link {{ page.vers {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN execute_txn || END execute_txn %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs %} ~~~ The `transfer_funds` function calls `execute_txn` to perform the actual transfer of funds from one account to the other. {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN transfer_funds || END transfer_funds %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs %} ~~~ ## Step 3. Run the code diff --git a/src/current/v24.1/build-a-spring-app-with-cockroachdb-jdbc.md b/src/current/v24.1/build-a-spring-app-with-cockroachdb-jdbc.md index ea021b5875c..08c8ad55c10 100644 --- a/src/current/v24.1/build-a-spring-app-with-cockroachdb-jdbc.md +++ b/src/current/v24.1/build-a-spring-app-with-cockroachdb-jdbc.md @@ -606,7 +606,7 @@ Here are the contents of [`JdbcApplication.java`](https://github.com/cockroachla {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} ~~~ The annotations listed at the top of the `JdbcApplication` class definition declare some important configuration properties for the entire application: @@ -631,14 +631,14 @@ Liquibase uses [changelog files](https://docs.liquibase.com/concepts/basic/chang {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -696,7 +696,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} ~~~ ### Hypermedia representation @@ -707,7 +707,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -720,7 +720,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for generic [CRUD operations](https://wikipedia.org/wiki/Create,_read,_update_and_delete) called `CrudRepository`. To support [pagination queries]({% link {{ page.version.version }}/pagination.md %}), repositories in other Spring Data modules, like those in Spring Data JPA, usually extend a subinterface of `CrudRepository`, called `PagingAndSortingRepository`, that includes pagination and sorting methods. At the time this sample application was created, Spring Data JDBC did not support pagination. As a result, `AccountRepository` extends a custom repository, called `PagedAccountRepository`, to provide basic [`LIMIT`/`OFFSET` pagination]({% link {{ page.version.version }}/pagination.md %}) on queries against the `accounts` table. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/#jdbc.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -737,7 +737,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -773,7 +773,7 @@ The `TransactionHintsAspect` class, declared as an aspect with the [`@Aspect` an {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. @@ -790,7 +790,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` pointcut definition is identical to the one declared in `TransactionHintsAspect`. The `execution` designator matches all methods in the `io.roach.` namespace, and the `@annotation` designator limits the matches to methods with the `@Transactional` annotation. diff --git a/src/current/v24.1/build-a-spring-app-with-cockroachdb-jpa.md b/src/current/v24.1/build-a-spring-app-with-cockroachdb-jpa.md index 27b676716b5..91203592d92 100644 --- a/src/current/v24.1/build-a-spring-app-with-cockroachdb-jpa.md +++ b/src/current/v24.1/build-a-spring-app-with-cockroachdb-jpa.md @@ -517,7 +517,7 @@ Here are the contents of [`JpaApplication.java`](https://github.com/cockroachlab {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} ~~~ The annotations listed at the top of the `JpaApplication` class definition declare some important configuration properties for the entire application: @@ -540,14 +540,14 @@ Liquibase uses files called [changelogs](https://docs.liquibase.com/concepts/bas {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -596,7 +596,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} ~~~ Spring Data JPA supports standard Java Persistence API (JPA) annotations for domain entity class definitions. The `Account` class definition uses these annotations to create the `accounts` table entity: @@ -616,7 +616,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -629,7 +629,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for JPA data access called `JpaRepository`. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -646,7 +646,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -677,7 +677,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. diff --git a/src/current/v24.1/movr-flask-application.md b/src/current/v24.1/movr-flask-application.md index ab1d9297e9c..9c544ad1da4 100644 --- a/src/current/v24.1/movr-flask-application.md +++ b/src/current/v24.1/movr-flask-application.md @@ -90,7 +90,7 @@ After completing the [Create a Multi-Region Database Schema]({% link {{ page.ver Open [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), and look at the first 10 lines of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__front.py %} ~~~ The first data structure that the file imports is `declarative_base`, a constructor for the [declarative base class](https://docs.sqlalchemy.org/orm/extensions/declarative/api.html#sqlalchemy.ext.declarative.declarative_base), built on SQLAlchemy's Declarative extension. All mapped objects inherit from this object. We assign a declarative base object to the `Base` variable right below the imports. @@ -106,7 +106,7 @@ Recall that each instance of a table class represents a row in the table, so we Take a look at the `User` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START User ||# END User %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__user.py %} ~~~ The `User` class has the following attributes: @@ -121,7 +121,7 @@ The `User` class has the following attributes: Next, look at the `Vehicle` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Vehicle ||# END Vehicle %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__vehicle.py %} ~~~ Recall that the `vehicles` table contains more columns and data types than the `users` table. It also contains a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) (on the `users` table), and a default value. These differences are reflected in the `Vehicle` class. @@ -131,7 +131,7 @@ Recall that the `vehicles` table contains more columns and data types than the ` Lastly, there's the `Ride` class: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Ride ||# END Ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__ride.py %} ~~~ The `rides` table has three foreign key constraints, one on the `users` table and two on the `vehicles` table. @@ -186,7 +186,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` `transactions.py` imports all of the table classes that we defined in [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), in addition to some standard Python data structures needed to generate correctly-typed row values that the ORM can write to the database. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__front.py %} ~~~ ##### Reading @@ -194,7 +194,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` A common query that a client might want to run is a read of the `rides` table. The transaction callback function for this query is defined here as `get_rides_txn()`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_rides_txn ||# END get_rides_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-rides-txn.py %} ~~~ The `get_rides_txn()` function takes a `Session` object and a `rider_id` string as its inputs, and it outputs a list of dictionaries containing the columns-value pairs of a row in the `rides` table. To retrieve the data from the database bound to a particular `Session` object, we use `Session.query()`, a method of the `Session` class. This method returns a `Query` object, with methods for filtering and ordering query results. @@ -204,7 +204,7 @@ Note that `get_rides_txn()` gets all rides for a specific rider, which might be Another common query would be to read the registered vehicles in a particular city, to see which vehicles are available for riding. Unlike `get_rides_txn()`, the `get_vehicles_txn()` function takes the `city` string as an input. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_vehicles_txn ||# END get_vehicles_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-vehicles-txn.py %} ~~~ This function filters the query on the `city` column. `vehicle` rows with the same value for `city` are inserted from the same region, making `city` values implicitly correspond to a specific region. Because the `vehicles` table has a `REGIONAL BY ROW` locality, CockroachDB can locality-optimize queries from nodes with a locality matching the [hidden `crdb_region` column]({% link {{ page.version.version }}/movr-flask-database.md %}#table-locality). This limits latency, as the query only needs to travel to database deployments in a single region. @@ -216,7 +216,7 @@ There are two basic types of write operations: creating new rows and updating ex For example, `start_ride_txn()`, which is called when a user starts a ride, adds a new row to the `rides` table, and then updates a row in the `vehicles` table. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START start_ride_txn ||# END start_ride_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__start-ride-txn.py %} ~~~ The function takes the `city` string, `rider_id` UUID, `rider_city` string, and `vehicle_id` UUID as inputs. It queries the `vehicles` table for all vehicles of a specific ID. It also creates a `Ride` object, representing a row of the `rides` table. To add the ride to the table in the database bound to the `Session`, the function calls `Session.add()`. To update a row in the `vehicles` table, it modifies the object attribute. `start_ride_txn()` is called by `run_transaction()`, which commits the transaction to the database. @@ -232,7 +232,7 @@ The `MovR` class, defined in [`movr/movr.py`](https://github.com/cockroachlabs/m Let's start with the beginning of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__front.py %} ~~~ `movr.py` first imports the transaction callback functions that we defined in [`movr/transactions.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/transactions.py). It then imports the `run_transaction()` function. The `MovR` class methods call `run_transaction()` to execute the transaction callback functions as transactions. @@ -250,7 +250,7 @@ We've already defined the transaction logic in the transaction callback function For example, look at the `start_ride()` method, the method to which frontend requests to start a ride are routed: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START start_ride ||# END start_ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__start-ride.py %} ~~~ This method takes some keyword arguments, and then returns a `run_transaction()` call. It passes `sessionmaker(bind=self.engine)` as the first argument to `run_transaction()`, which creates a new `Session` object that binds to the `Engine` instance initialized by the `MovR` constructor. It also passes `city`, `rider_id`, `rider_city`, and `vehicle_id`, values passed from the frontend request, as inputs. These are the same keyword arguments, and should be of the same types, as the inputs for the [transaction callback function](#writing) `start_ride_txn()`. @@ -268,7 +268,7 @@ Most of the web application components are found in the `web` and `templates` fo We store the Flask configuration settings in [a `Config` class](https://flask.palletsprojects.com/config/#development-production), defined in [`web/config.py`](https://github.com/cockroachlabs/movr-flask/blob/master/web/config.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} ~~~ This file imports the `os` library, which is used to read from environment variables. When debugging a local deployment, these environment variables are set by the `.env` file that `Pipenv` reads. In a multi-region deployment, the environment variables are set by the `Dockerfile`, and by the [managed cloud deployment service]({% link {{ page.version.version }}/movr-flask-deployment.md %}). @@ -284,7 +284,7 @@ We will not go into much detail about these forms. The important thing to know i The `CredentialForm` class, for example, defines the fields of the login form that users interface with to send a login request to the server: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START CredentialForm ||# END CredentialForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__credentialform.py %} ~~~ Most of the forms defined on this page take the inputs for database reads and writes. @@ -292,7 +292,7 @@ Most of the forms defined on this page take the inputs for database reads and wr `VehicleForm`, for example, defines the fields of the vehicle registration form. Users enter information about a vehicle they would like to register, and the data is routed to the `add_vehicle()` method defined in [`movr/movr.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/movr.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START VehicleForm ||# END VehicleForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__vehicleform.py %} ~~~ ### Initialization @@ -302,7 +302,7 @@ Most of the forms defined on this page take the inputs for database reads and wr Let's look at the first ten lines of `server.py`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__front.py %} ~~~ The first line imports standard Flask libraries for connecting, routing, and rendering web pages. The next three lines import some libraries from the Flask ecosystem, for [bootstrapping](https://pythonhosted.org/Flask-Bootstrap/), [authentication](https://flask-login.readthedocs.io/), and [security](https://github.com/pallets/werkzeug/blob/master/src/werkzeug/security.py). @@ -318,7 +318,7 @@ Finally, we import the `DBAPIError` type from `sqlalchemy`, for error handling. The next five or so lines initialize the application: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START init ||# END init %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__init.py %} ~~~ Calling the `Flask()` constructor initializes our Flask web server. By assigning this to a variable (`app`), we can then configure the application, store variables in its attributes, and call it with functions from other libraries, to add features and functionality to the application. @@ -330,7 +330,7 @@ Note that we also define a `protocol` variable that the application later uses t After initializing the application, we can connect to the database: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START connect ||# END connect %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__connect.py %} ~~~ These two lines connect the application to the database. First the application retrieves the connection string that is stored as a configuration variable of the `app`. Then it calls the `MovR()` constructor to establish a connection to the database at the location we provided to the `Config` object. @@ -342,7 +342,7 @@ User authentication is handled with the [`Flask-Login`](https://flask-login.read To control whether certain routes are accessible to a client session, we define a [`user_loader()` function](https://flask-login.readthedocs.io/#flask_login.LoginManager.user_loader): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START user_loader ||# END user_loader %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__user-loader.py %} ~~~ To restrict access to a certain page to users that are logged in with the [`LoginManager`](https://flask-login.readthedocs.io/#flask_login.LoginManager), we add the `@login_required` decorator function to the route. We'll go over some examples in the [Routing](#routing) section below. @@ -364,7 +364,7 @@ In addition to calling these functions, and some other standard Flask and Python For example, look at the `login()` route: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START login_page ||# END login_page %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__login-page.py %} ~~~ ### Client Location diff --git a/src/current/v24.1/movr-flask-database.md b/src/current/v24.1/movr-flask-database.md index c77c24a0ab4..69ebbd4b013 100644 --- a/src/current/v24.1/movr-flask-database.md +++ b/src/current/v24.1/movr-flask-database.md @@ -49,7 +49,7 @@ Here is the [`CREATE DATABASE`]({% link {{ page.version.version }}/create-databa {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START database ||-- END database %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__database.sql %} ~~~ Note that `movr` has the following [database regions]({% link {{ page.version.version }}/multiregion-overview.md %}#database-regions), which correspond to regions in Google Cloud: @@ -78,14 +78,14 @@ Here is the `CREATE TABLE` statement for the `users` table: {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START users ||-- END users %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__users.sql %} ~~~ ## The `vehicles` table {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START vehicles ||-- END vehicles %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__vehicles.sql %} ~~~ Note that the `vehicles` table has a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) on the `users` table, for the `city` and `owner_id` columns. This guarantees that a vehicle is registered to a particular user (i.e., an "owner") in the city where that user is registered. @@ -94,7 +94,7 @@ Note that the `vehicles` table has a [foreign key constraint]({% link {{ page.ve {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START rides ||-- END rides %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__rides.sql %} ~~~ Note that, like the `vehicles` table, the `rides` table has foreign key constraints. These constraints are on the `users` and the `vehicles` tables. diff --git a/src/current/v24.2/build-a-csharp-app-with-cockroachdb.md b/src/current/v24.2/build-a-csharp-app-with-cockroachdb.md index 115abf8febd..6e71dfb298f 100644 --- a/src/current/v24.2/build-a-csharp-app-with-cockroachdb.md +++ b/src/current/v24.2/build-a-csharp-app-with-cockroachdb.md @@ -69,7 +69,7 @@ Replace the contents of the `Program.cs` file that was automatically generated i {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/basic.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/basic.cs %} ~~~ #### Run the basic example @@ -99,7 +99,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs %} ~~~
@@ -108,7 +108,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} ~~~ diff --git a/src/current/v24.2/build-a-go-app-with-cockroachdb-gorm.md b/src/current/v24.2/build-a-go-app-with-cockroachdb-gorm.md index 23ee58cd997..aac3820127f 100644 --- a/src/current/v24.2/build-a-go-app-with-cockroachdb-gorm.md +++ b/src/current/v24.2/build-a-go-app-with-cockroachdb-gorm.md @@ -39,7 +39,7 @@ The `main.go` file defines an `Account` struct that maps to a new `accounts` tab {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-gorm/master/main.go %} +{% include example-apps/cockroachlabs/example-app-go-gorm/master/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v24.2/build-a-go-app-with-cockroachdb.md b/src/current/v24.2/build-a-go-app-with-cockroachdb.md index 8a00ed10cb4..89ef7c4669e 100644 --- a/src/current/v24.2/build-a-go-app-with-cockroachdb.md +++ b/src/current/v24.2/build-a-go-app-with-cockroachdb.md @@ -35,7 +35,7 @@ The `main.go` file contains the code for `CREATE TABLE`, `INSERT`, `SELECT`, `UP {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-pgx/main/main.go %} +{% include example-apps/cockroachlabs/example-app-go-pgx/main/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v24.2/build-a-java-app-with-cockroachdb-hibernate.md b/src/current/v24.2/build-a-java-app-with-cockroachdb-hibernate.md index c4b53d27629..e266f78bff0 100644 --- a/src/current/v24.2/build-a-java-app-with-cockroachdb-hibernate.md +++ b/src/current/v24.2/build-a-java-app-with-cockroachdb-hibernate.md @@ -54,7 +54,7 @@ The contents of `Sample.java`: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} +{% include example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} ~~~
diff --git a/src/current/v24.2/build-a-java-app-with-cockroachdb.md b/src/current/v24.2/build-a-java-app-with-cockroachdb.md index d798e9dbaee..65b936c0feb 100644 --- a/src/current/v24.2/build-a-java-app-with-cockroachdb.md +++ b/src/current/v24.2/build-a-java-app-with-cockroachdb.md @@ -55,7 +55,7 @@ The `BasicExample.java` file contains the code for `INSERT`, `SELECT`, and `UPDA {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} +{% include example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} ~~~ The sample app uses JDBC and the [Data Access Object (DAO)](https://wikipedia.org/wiki/Data_access_object) pattern to map Java methods to SQL operations. It consists of two classes: diff --git a/src/current/v24.2/build-a-nodejs-app-with-cockroachdb-prisma.md b/src/current/v24.2/build-a-nodejs-app-with-cockroachdb-prisma.md index afda47789ec..6e16095554d 100644 --- a/src/current/v24.2/build-a-nodejs-app-with-cockroachdb-prisma.md +++ b/src/current/v24.2/build-a-nodejs-app-with-cockroachdb-prisma.md @@ -89,7 +89,7 @@ The `index.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DEL {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-prisma/main/index.js %} +{% include example-apps/cockroachlabs/example-app-node-prisma/main/index.js %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v24.2/build-a-nodejs-app-with-cockroachdb.md b/src/current/v24.2/build-a-nodejs-app-with-cockroachdb.md index dba17b3fb8f..d00b2bfa180 100644 --- a/src/current/v24.2/build-a-nodejs-app-with-cockroachdb.md +++ b/src/current/v24.2/build-a-nodejs-app-with-cockroachdb.md @@ -39,14 +39,14 @@ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ sql -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} ~~~ The `app.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DELETE` SQL operations: {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/app.js %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/app.js %} ~~~ All of the database operations are wrapped in a helper function named `retryTxn`. This function attempts to commit statements in the context of an explicit transaction. If a [retry error]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) is thrown, the wrapper will retry committing the transaction, with [exponential backoff](https://wikipedia.org/wiki/Exponential_backoff), until the maximum number of retries is reached (by default, 15). diff --git a/src/current/v24.2/build-a-python-app-with-cockroachdb-django.md b/src/current/v24.2/build-a-python-app-with-cockroachdb-django.md index 85644de65ed..e3a8eef46cd 100644 --- a/src/current/v24.2/build-a-python-app-with-cockroachdb-django.md +++ b/src/current/v24.2/build-a-python-app-with-cockroachdb-django.md @@ -67,7 +67,7 @@ The `requirements.txt` file at the top level of the `example-app-python-django` {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-django/master/requirements.txt %} ~~~ This tutorial uses [`virtualenv`](https://virtualenv.pypa.io) for dependency management. @@ -135,7 +135,7 @@ Start by building some [models](https://docs.djangoproject.com/en/3.1/topics/db/ {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} ~~~ In this file, we define some simple classes that map to the tables in the cluster. @@ -146,7 +146,7 @@ Next, build out some [class-based views](https://docs.djangoproject.com/en/3.1/t {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} ~~~ This file defines the application's views as classes. Each view class corresponds to one of the table classes defined in `models.py`. The methods of these classes define read and write transactions on the tables in the database. @@ -159,7 +159,7 @@ Lastly, define some [URL routes](https://docs.djangoproject.com/en/3.1/topics/ht {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} ~~~ ## Step 5. Initialize the database diff --git a/src/current/v24.2/build-a-python-app-with-cockroachdb-sqlalchemy.md b/src/current/v24.2/build-a-python-app-with-cockroachdb-sqlalchemy.md index e56b9c136a8..70e205bbdad 100644 --- a/src/current/v24.2/build-a-python-app-with-cockroachdb-sqlalchemy.md +++ b/src/current/v24.2/build-a-python-app-with-cockroachdb-sqlalchemy.md @@ -40,28 +40,28 @@ The `requirements.txt` file includes the required libraries to connect to Cockro {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} ~~~ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} ~~~ The `models.py` uses SQLAlchemy to map the `Accounts` table to a Python object: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} ~~~ The `main.py` uses SQLAlchemy to map Python methods to SQL operations: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} ~~~ `main.py` also executes the `main` method of the program. diff --git a/src/current/v24.2/build-a-rust-app-with-cockroachdb.md b/src/current/v24.2/build-a-rust-app-with-cockroachdb.md index 4ca08938824..46b9cdea10c 100644 --- a/src/current/v24.2/build-a-rust-app-with-cockroachdb.md +++ b/src/current/v24.2/build-a-rust-app-with-cockroachdb.md @@ -39,7 +39,7 @@ The `Cargo.toml` file is the configuration file for the example, and sets the de {% include_cached copy-clipboard.html %} ~~~ toml -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} ~~~ The `main` function is the entry point for the application, with the code for connecting to the cluster, creating the `accounts` table, creating accounts in that table, and transferring money between two accounts. @@ -52,14 +52,14 @@ CockroachDB may require the [client to retry a transaction]({% link {{ page.vers {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN execute_txn || END execute_txn %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs %} ~~~ The `transfer_funds` function calls `execute_txn` to perform the actual transfer of funds from one account to the other. {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN transfer_funds || END transfer_funds %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs %} ~~~ ## Step 3. Run the code diff --git a/src/current/v24.2/build-a-spring-app-with-cockroachdb-jdbc.md b/src/current/v24.2/build-a-spring-app-with-cockroachdb-jdbc.md index c6046d645dd..71dbf62fc7b 100644 --- a/src/current/v24.2/build-a-spring-app-with-cockroachdb-jdbc.md +++ b/src/current/v24.2/build-a-spring-app-with-cockroachdb-jdbc.md @@ -606,7 +606,7 @@ Here are the contents of [`JdbcApplication.java`](https://github.com/cockroachla {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} ~~~ The annotations listed at the top of the `JdbcApplication` class definition declare some important configuration properties for the entire application: @@ -631,14 +631,14 @@ Liquibase uses [changelog files](https://docs.liquibase.com/concepts/basic/chang {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -696,7 +696,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} ~~~ ### Hypermedia representation @@ -707,7 +707,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -720,7 +720,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for generic [CRUD operations](https://wikipedia.org/wiki/Create,_read,_update_and_delete) called `CrudRepository`. To support [pagination queries]({% link {{ page.version.version }}/pagination.md %}), repositories in other Spring Data modules, like those in Spring Data JPA, usually extend a subinterface of `CrudRepository`, called `PagingAndSortingRepository`, that includes pagination and sorting methods. At the time this sample application was created, Spring Data JDBC did not support pagination. As a result, `AccountRepository` extends a custom repository, called `PagedAccountRepository`, to provide basic [`LIMIT`/`OFFSET` pagination]({% link {{ page.version.version }}/pagination.md %}) on queries against the `accounts` table. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/#jdbc.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -737,7 +737,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -773,7 +773,7 @@ The `TransactionHintsAspect` class, declared as an aspect with the [`@Aspect` an {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. @@ -790,7 +790,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` pointcut definition is identical to the one declared in `TransactionHintsAspect`. The `execution` designator matches all methods in the `io.roach.` namespace, and the `@annotation` designator limits the matches to methods with the `@Transactional` annotation. diff --git a/src/current/v24.2/build-a-spring-app-with-cockroachdb-jpa.md b/src/current/v24.2/build-a-spring-app-with-cockroachdb-jpa.md index d9e1c60c6dd..b45b8e6f1f4 100644 --- a/src/current/v24.2/build-a-spring-app-with-cockroachdb-jpa.md +++ b/src/current/v24.2/build-a-spring-app-with-cockroachdb-jpa.md @@ -517,7 +517,7 @@ Here are the contents of [`JpaApplication.java`](https://github.com/cockroachlab {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} ~~~ The annotations listed at the top of the `JpaApplication` class definition declare some important configuration properties for the entire application: @@ -540,14 +540,14 @@ Liquibase uses files called [changelogs](https://docs.liquibase.com/concepts/bas {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -596,7 +596,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} ~~~ Spring Data JPA supports standard Java Persistence API (JPA) annotations for domain entity class definitions. The `Account` class definition uses these annotations to create the `accounts` table entity: @@ -616,7 +616,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -629,7 +629,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for JPA data access called `JpaRepository`. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -646,7 +646,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -677,7 +677,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. diff --git a/src/current/v24.2/movr-flask-application.md b/src/current/v24.2/movr-flask-application.md index c3b8f437a75..57eaeb50234 100644 --- a/src/current/v24.2/movr-flask-application.md +++ b/src/current/v24.2/movr-flask-application.md @@ -87,7 +87,7 @@ After completing the [Create a Multi-Region Database Schema]({% link {{ page.ver Open [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), and look at the first 10 lines of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__front.py %} ~~~ The first data structure that the file imports is `declarative_base`, a constructor for the [declarative base class](https://docs.sqlalchemy.org/orm/extensions/declarative/api.html#sqlalchemy.ext.declarative.declarative_base), built on SQLAlchemy's Declarative extension. All mapped objects inherit from this object. We assign a declarative base object to the `Base` variable right below the imports. @@ -103,7 +103,7 @@ Recall that each instance of a table class represents a row in the table, so we Take a look at the `User` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START User ||# END User %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__user.py %} ~~~ The `User` class has the following attributes: @@ -118,7 +118,7 @@ The `User` class has the following attributes: Next, look at the `Vehicle` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Vehicle ||# END Vehicle %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__vehicle.py %} ~~~ Recall that the `vehicles` table contains more columns and data types than the `users` table. It also contains a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) (on the `users` table), and a default value. These differences are reflected in the `Vehicle` class. @@ -128,7 +128,7 @@ Recall that the `vehicles` table contains more columns and data types than the ` Take a look at the `Ride` class: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Ride ||# END Ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__ride.py %} ~~~ The `rides` table has three foreign key constraints, one on the `users` table and two on the `vehicles` table. @@ -186,7 +186,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` `transactions.py` imports all of the table classes that we defined in [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), in addition to some standard Python data structures needed to generate correctly-typed row values that the ORM can write to the database. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__front.py %} ~~~ ##### Reading @@ -194,7 +194,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` A common query that a client might want to run is a read of the `rides` table. The transaction callback function for this query is defined here as `get_rides_txn()`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_rides_txn ||# END get_rides_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-rides-txn.py %} ~~~ The `get_rides_txn()` function takes a `Session` object and a `rider_id` string as its inputs, and it outputs a list of dictionaries containing the columns-value pairs of a row in the `rides` table. To retrieve the data from the database bound to a particular `Session` object, we use `Session.query()`, a method of the `Session` class. This method returns a `Query` object, with methods for filtering and ordering query results. @@ -204,7 +204,7 @@ Note that `get_rides_txn()` gets all rides for a specific rider, which might be Another common query would be to read the registered vehicles in a particular city, to see which vehicles are available for riding. Unlike `get_rides_txn()`, the `get_vehicles_txn()` function takes the `city` string as an input. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_vehicles_txn ||# END get_vehicles_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-vehicles-txn.py %} ~~~ This function filters the query on the `city` column. `vehicle` rows with the same value for `city` are inserted from the same region, making `city` values implicitly correspond to a specific region. Because the `vehicles` table has a `REGIONAL BY ROW` locality, CockroachDB can locality-optimize queries from nodes with a locality matching the [hidden `crdb_region` column]({% link {{ page.version.version }}/movr-flask-database.md %}#table-locality). This limits latency, as the query only needs to travel to database deployments in a single region. @@ -216,7 +216,7 @@ There are two basic types of write operations: creating new rows and updating ex For example, `start_ride_txn()`, which is called when a user starts a ride, adds a new row to the `rides` table, and then updates a row in the `vehicles` table. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START start_ride_txn ||# END start_ride_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__start-ride-txn.py %} ~~~ The function takes the `city` string, `rider_id` UUID, `rider_city` string, and `vehicle_id` UUID as inputs. It queries the `vehicles` table for all vehicles of a specific ID. It also creates a `Ride` object, representing a row of the `rides` table. To add the ride to the table in the database bound to the `Session`, the function calls `Session.add()`. To update a row in the `vehicles` table, it modifies the object attribute. `start_ride_txn()` is called by `run_transaction()`, which commits the transaction to the database. @@ -232,7 +232,7 @@ The `MovR` class, defined in [`movr/movr.py`](https://github.com/cockroachlabs/m Let's start with the beginning of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__front.py %} ~~~ `movr.py` first imports the transaction callback functions that we defined in [`movr/transactions.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/transactions.py). It then imports the `run_transaction()` function. The `MovR` class methods call `run_transaction()` to execute the transaction callback functions as transactions. @@ -250,7 +250,7 @@ We've already defined the transaction logic in the transaction callback function For example, look at the `start_ride()` method, the method to which frontend requests to start a ride are routed: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START start_ride ||# END start_ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__start-ride.py %} ~~~ This method takes some keyword arguments, and then returns a `run_transaction()` call. It passes `sessionmaker(bind=self.engine)` as the first argument to `run_transaction()`, which creates a new `Session` object that binds to the `Engine` instance initialized by the `MovR` constructor. It also passes `city`, `rider_id`, `rider_city`, and `vehicle_id`, values passed from the frontend request, as inputs. These are the same keyword arguments, and should be of the same types, as the inputs for the [transaction callback function](#writing) `start_ride_txn()`. @@ -268,7 +268,7 @@ Most of the web application components are found in the `web` and `templates` fo We store the Flask configuration settings in [a `Config` class](https://flask.palletsprojects.com/config/#development-production), defined in [`web/config.py`](https://github.com/cockroachlabs/movr-flask/blob/master/web/config.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} ~~~ This file imports the `os` library, which is used to read from environment variables. When debugging a local deployment, these environment variables are set by the `.env` file that `Pipenv` reads. In a multi-region deployment, the environment variables are set by the `Dockerfile`, and by the [managed cloud deployment service]({% link {{ page.version.version }}/movr-flask-deployment.md %}). @@ -284,7 +284,7 @@ We will not go into much detail about these forms. The important thing to know i The `CredentialForm` class, for example, defines the fields of the login form that users interface with to send a login request to the server: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START CredentialForm ||# END CredentialForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__credentialform.py %} ~~~ Most of the forms defined on this page take the inputs for database reads and writes. @@ -292,7 +292,7 @@ Most of the forms defined on this page take the inputs for database reads and wr `VehicleForm`, for example, defines the fields of the vehicle registration form. Users enter information about a vehicle they would like to register, and the data is routed to the `add_vehicle()` method defined in [`movr/movr.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/movr.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START VehicleForm ||# END VehicleForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__vehicleform.py %} ~~~ ### Initialization @@ -302,7 +302,7 @@ Most of the forms defined on this page take the inputs for database reads and wr Let's look at the first ten lines of `server.py`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__front.py %} ~~~ The first line imports standard Flask libraries for connecting, routing, and rendering web pages. The next three lines import some libraries from the Flask ecosystem, for [bootstrapping](https://pythonhosted.org/Flask-Bootstrap/), [authentication](https://flask-login.readthedocs.io/), and [security](https://github.com/pallets/werkzeug/blob/master/src/werkzeug/security.py). @@ -318,7 +318,7 @@ Finally, we import the `DBAPIError` type from `sqlalchemy`, for error handling. The next five or so lines initialize the application: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START init ||# END init %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__init.py %} ~~~ Calling the `Flask()` constructor initializes our Flask web server. By assigning this to a variable (`app`), we can then configure the application, store variables in its attributes, and call it with functions from other libraries, to add features and functionality to the application. @@ -330,7 +330,7 @@ Note that we also define a `protocol` variable that the application later uses t After initializing the application, we can connect to the database: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START connect ||# END connect %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__connect.py %} ~~~ These two lines connect the application to the database. First the application retrieves the connection string that is stored as a configuration variable of the `app`. Then it calls the `MovR()` constructor to establish a connection to the database at the location we provided to the `Config` object. @@ -342,7 +342,7 @@ User authentication is handled with the [`Flask-Login`](https://flask-login.read To control whether certain routes are accessible to a client session, we define a [`user_loader()` function](https://flask-login.readthedocs.io/#flask_login.LoginManager.user_loader): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START user_loader ||# END user_loader %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__user-loader.py %} ~~~ To restrict access to a certain page to users that are logged in with the [`LoginManager`](https://flask-login.readthedocs.io/#flask_login.LoginManager), we add the `@login_required` decorator function to the route. We'll go over some examples in the [Routing](#routing) section below. @@ -364,7 +364,7 @@ In addition to calling these functions, and some other standard Flask and Python For example, look at the `login()` route: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START login_page ||# END login_page %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__login-page.py %} ~~~ ### Client Location diff --git a/src/current/v24.2/movr-flask-database.md b/src/current/v24.2/movr-flask-database.md index 4bb882c2135..e7075ae53ae 100644 --- a/src/current/v24.2/movr-flask-database.md +++ b/src/current/v24.2/movr-flask-database.md @@ -48,7 +48,7 @@ Here is the [`CREATE DATABASE`]({% link {{ page.version.version }}/create-databa {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START database ||-- END database %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__database.sql %} ~~~ In this example, `movr` has the following [database regions]({% link {{ page.version.version }}/multiregion-overview.md %}#database-regions), which correspond to regions in Google Cloud: @@ -77,14 +77,14 @@ Here is the `CREATE TABLE` statement for the `users` table: {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START users ||-- END users %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__users.sql %} ~~~ ## The `vehicles` table {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START vehicles ||-- END vehicles %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__vehicles.sql %} ~~~ The `vehicles` table has a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) on the `users` table, for the `city` and `owner_id` columns. This guarantees that a vehicle is registered to a particular user (i.e., an "owner") in the city where that user is registered. @@ -93,7 +93,7 @@ The `vehicles` table has a [foreign key constraint]({% link {{ page.version.vers {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START rides ||-- END rides %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__rides.sql %} ~~~ Like the `vehicles` table, the `rides` table has foreign key constraints. These constraints are on the `users` and the `vehicles` tables. diff --git a/src/current/v24.3/build-a-csharp-app-with-cockroachdb.md b/src/current/v24.3/build-a-csharp-app-with-cockroachdb.md index 115abf8febd..6e71dfb298f 100644 --- a/src/current/v24.3/build-a-csharp-app-with-cockroachdb.md +++ b/src/current/v24.3/build-a-csharp-app-with-cockroachdb.md @@ -69,7 +69,7 @@ Replace the contents of the `Program.cs` file that was automatically generated i {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/basic.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/basic.cs %} ~~~ #### Run the basic example @@ -99,7 +99,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs %} ~~~
@@ -108,7 +108,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} ~~~ diff --git a/src/current/v24.3/build-a-go-app-with-cockroachdb-gorm.md b/src/current/v24.3/build-a-go-app-with-cockroachdb-gorm.md index 23ee58cd997..aac3820127f 100644 --- a/src/current/v24.3/build-a-go-app-with-cockroachdb-gorm.md +++ b/src/current/v24.3/build-a-go-app-with-cockroachdb-gorm.md @@ -39,7 +39,7 @@ The `main.go` file defines an `Account` struct that maps to a new `accounts` tab {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-gorm/master/main.go %} +{% include example-apps/cockroachlabs/example-app-go-gorm/master/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v24.3/build-a-go-app-with-cockroachdb.md b/src/current/v24.3/build-a-go-app-with-cockroachdb.md index 8a00ed10cb4..89ef7c4669e 100644 --- a/src/current/v24.3/build-a-go-app-with-cockroachdb.md +++ b/src/current/v24.3/build-a-go-app-with-cockroachdb.md @@ -35,7 +35,7 @@ The `main.go` file contains the code for `CREATE TABLE`, `INSERT`, `SELECT`, `UP {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-pgx/main/main.go %} +{% include example-apps/cockroachlabs/example-app-go-pgx/main/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v24.3/build-a-java-app-with-cockroachdb-hibernate.md b/src/current/v24.3/build-a-java-app-with-cockroachdb-hibernate.md index c4b53d27629..e266f78bff0 100644 --- a/src/current/v24.3/build-a-java-app-with-cockroachdb-hibernate.md +++ b/src/current/v24.3/build-a-java-app-with-cockroachdb-hibernate.md @@ -54,7 +54,7 @@ The contents of `Sample.java`: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} +{% include example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} ~~~
diff --git a/src/current/v24.3/build-a-java-app-with-cockroachdb.md b/src/current/v24.3/build-a-java-app-with-cockroachdb.md index d798e9dbaee..65b936c0feb 100644 --- a/src/current/v24.3/build-a-java-app-with-cockroachdb.md +++ b/src/current/v24.3/build-a-java-app-with-cockroachdb.md @@ -55,7 +55,7 @@ The `BasicExample.java` file contains the code for `INSERT`, `SELECT`, and `UPDA {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} +{% include example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} ~~~ The sample app uses JDBC and the [Data Access Object (DAO)](https://wikipedia.org/wiki/Data_access_object) pattern to map Java methods to SQL operations. It consists of two classes: diff --git a/src/current/v24.3/build-a-nodejs-app-with-cockroachdb-prisma.md b/src/current/v24.3/build-a-nodejs-app-with-cockroachdb-prisma.md index afda47789ec..6e16095554d 100644 --- a/src/current/v24.3/build-a-nodejs-app-with-cockroachdb-prisma.md +++ b/src/current/v24.3/build-a-nodejs-app-with-cockroachdb-prisma.md @@ -89,7 +89,7 @@ The `index.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DEL {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-prisma/main/index.js %} +{% include example-apps/cockroachlabs/example-app-node-prisma/main/index.js %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v24.3/build-a-nodejs-app-with-cockroachdb.md b/src/current/v24.3/build-a-nodejs-app-with-cockroachdb.md index dba17b3fb8f..d00b2bfa180 100644 --- a/src/current/v24.3/build-a-nodejs-app-with-cockroachdb.md +++ b/src/current/v24.3/build-a-nodejs-app-with-cockroachdb.md @@ -39,14 +39,14 @@ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ sql -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} ~~~ The `app.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DELETE` SQL operations: {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/app.js %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/app.js %} ~~~ All of the database operations are wrapped in a helper function named `retryTxn`. This function attempts to commit statements in the context of an explicit transaction. If a [retry error]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) is thrown, the wrapper will retry committing the transaction, with [exponential backoff](https://wikipedia.org/wiki/Exponential_backoff), until the maximum number of retries is reached (by default, 15). diff --git a/src/current/v24.3/build-a-python-app-with-cockroachdb-django.md b/src/current/v24.3/build-a-python-app-with-cockroachdb-django.md index 85644de65ed..e3a8eef46cd 100644 --- a/src/current/v24.3/build-a-python-app-with-cockroachdb-django.md +++ b/src/current/v24.3/build-a-python-app-with-cockroachdb-django.md @@ -67,7 +67,7 @@ The `requirements.txt` file at the top level of the `example-app-python-django` {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-django/master/requirements.txt %} ~~~ This tutorial uses [`virtualenv`](https://virtualenv.pypa.io) for dependency management. @@ -135,7 +135,7 @@ Start by building some [models](https://docs.djangoproject.com/en/3.1/topics/db/ {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} ~~~ In this file, we define some simple classes that map to the tables in the cluster. @@ -146,7 +146,7 @@ Next, build out some [class-based views](https://docs.djangoproject.com/en/3.1/t {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} ~~~ This file defines the application's views as classes. Each view class corresponds to one of the table classes defined in `models.py`. The methods of these classes define read and write transactions on the tables in the database. @@ -159,7 +159,7 @@ Lastly, define some [URL routes](https://docs.djangoproject.com/en/3.1/topics/ht {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} ~~~ ## Step 5. Initialize the database diff --git a/src/current/v24.3/build-a-python-app-with-cockroachdb-sqlalchemy.md b/src/current/v24.3/build-a-python-app-with-cockroachdb-sqlalchemy.md index e56b9c136a8..70e205bbdad 100644 --- a/src/current/v24.3/build-a-python-app-with-cockroachdb-sqlalchemy.md +++ b/src/current/v24.3/build-a-python-app-with-cockroachdb-sqlalchemy.md @@ -40,28 +40,28 @@ The `requirements.txt` file includes the required libraries to connect to Cockro {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} ~~~ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} ~~~ The `models.py` uses SQLAlchemy to map the `Accounts` table to a Python object: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} ~~~ The `main.py` uses SQLAlchemy to map Python methods to SQL operations: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} ~~~ `main.py` also executes the `main` method of the program. diff --git a/src/current/v24.3/build-a-rust-app-with-cockroachdb.md b/src/current/v24.3/build-a-rust-app-with-cockroachdb.md index 4ca08938824..46b9cdea10c 100644 --- a/src/current/v24.3/build-a-rust-app-with-cockroachdb.md +++ b/src/current/v24.3/build-a-rust-app-with-cockroachdb.md @@ -39,7 +39,7 @@ The `Cargo.toml` file is the configuration file for the example, and sets the de {% include_cached copy-clipboard.html %} ~~~ toml -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} ~~~ The `main` function is the entry point for the application, with the code for connecting to the cluster, creating the `accounts` table, creating accounts in that table, and transferring money between two accounts. @@ -52,14 +52,14 @@ CockroachDB may require the [client to retry a transaction]({% link {{ page.vers {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN execute_txn || END execute_txn %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs %} ~~~ The `transfer_funds` function calls `execute_txn` to perform the actual transfer of funds from one account to the other. {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN transfer_funds || END transfer_funds %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs %} ~~~ ## Step 3. Run the code diff --git a/src/current/v24.3/build-a-spring-app-with-cockroachdb-jdbc.md b/src/current/v24.3/build-a-spring-app-with-cockroachdb-jdbc.md index c6046d645dd..71dbf62fc7b 100644 --- a/src/current/v24.3/build-a-spring-app-with-cockroachdb-jdbc.md +++ b/src/current/v24.3/build-a-spring-app-with-cockroachdb-jdbc.md @@ -606,7 +606,7 @@ Here are the contents of [`JdbcApplication.java`](https://github.com/cockroachla {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} ~~~ The annotations listed at the top of the `JdbcApplication` class definition declare some important configuration properties for the entire application: @@ -631,14 +631,14 @@ Liquibase uses [changelog files](https://docs.liquibase.com/concepts/basic/chang {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -696,7 +696,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} ~~~ ### Hypermedia representation @@ -707,7 +707,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -720,7 +720,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for generic [CRUD operations](https://wikipedia.org/wiki/Create,_read,_update_and_delete) called `CrudRepository`. To support [pagination queries]({% link {{ page.version.version }}/pagination.md %}), repositories in other Spring Data modules, like those in Spring Data JPA, usually extend a subinterface of `CrudRepository`, called `PagingAndSortingRepository`, that includes pagination and sorting methods. At the time this sample application was created, Spring Data JDBC did not support pagination. As a result, `AccountRepository` extends a custom repository, called `PagedAccountRepository`, to provide basic [`LIMIT`/`OFFSET` pagination]({% link {{ page.version.version }}/pagination.md %}) on queries against the `accounts` table. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/#jdbc.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -737,7 +737,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -773,7 +773,7 @@ The `TransactionHintsAspect` class, declared as an aspect with the [`@Aspect` an {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. @@ -790,7 +790,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` pointcut definition is identical to the one declared in `TransactionHintsAspect`. The `execution` designator matches all methods in the `io.roach.` namespace, and the `@annotation` designator limits the matches to methods with the `@Transactional` annotation. diff --git a/src/current/v24.3/build-a-spring-app-with-cockroachdb-jpa.md b/src/current/v24.3/build-a-spring-app-with-cockroachdb-jpa.md index d9e1c60c6dd..b45b8e6f1f4 100644 --- a/src/current/v24.3/build-a-spring-app-with-cockroachdb-jpa.md +++ b/src/current/v24.3/build-a-spring-app-with-cockroachdb-jpa.md @@ -517,7 +517,7 @@ Here are the contents of [`JpaApplication.java`](https://github.com/cockroachlab {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} ~~~ The annotations listed at the top of the `JpaApplication` class definition declare some important configuration properties for the entire application: @@ -540,14 +540,14 @@ Liquibase uses files called [changelogs](https://docs.liquibase.com/concepts/bas {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -596,7 +596,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} ~~~ Spring Data JPA supports standard Java Persistence API (JPA) annotations for domain entity class definitions. The `Account` class definition uses these annotations to create the `accounts` table entity: @@ -616,7 +616,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -629,7 +629,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for JPA data access called `JpaRepository`. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -646,7 +646,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -677,7 +677,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. diff --git a/src/current/v24.3/movr-flask-application.md b/src/current/v24.3/movr-flask-application.md index 68b2a10b900..558f365637b 100644 --- a/src/current/v24.3/movr-flask-application.md +++ b/src/current/v24.3/movr-flask-application.md @@ -87,7 +87,7 @@ After completing the [Create a Multi-Region Database Schema]({% link {{ page.ver Open [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), and look at the first 10 lines of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__front.py %} ~~~ The first data structure that the file imports is `declarative_base`, a constructor for the [declarative base class](https://docs.sqlalchemy.org/orm/extensions/declarative/api.html#sqlalchemy.ext.declarative.declarative_base), built on SQLAlchemy's Declarative extension. All mapped objects inherit from this object. We assign a declarative base object to the `Base` variable right below the imports. @@ -103,7 +103,7 @@ Recall that each instance of a table class represents a row in the table, so we Take a look at the `User` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START User ||# END User %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__user.py %} ~~~ The `User` class has the following attributes: @@ -118,7 +118,7 @@ The `User` class has the following attributes: Next, look at the `Vehicle` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Vehicle ||# END Vehicle %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__vehicle.py %} ~~~ Recall that the `vehicles` table contains more columns and data types than the `users` table. It also contains a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) (on the `users` table), and a default value. These differences are reflected in the `Vehicle` class. @@ -128,7 +128,7 @@ Recall that the `vehicles` table contains more columns and data types than the ` Take a look at the `Ride` class: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Ride ||# END Ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__ride.py %} ~~~ The `rides` table has three foreign key constraints, one on the `users` table and two on the `vehicles` table. @@ -186,7 +186,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` `transactions.py` imports all of the table classes that we defined in [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), in addition to some standard Python data structures needed to generate correctly-typed row values that the ORM can write to the database. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__front.py %} ~~~ ##### Reading @@ -194,7 +194,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` A common query that a client might want to run is a read of the `rides` table. The transaction callback function for this query is defined here as `get_rides_txn()`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_rides_txn ||# END get_rides_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-rides-txn.py %} ~~~ The `get_rides_txn()` function takes a `Session` object and a `rider_id` string as its inputs, and it outputs a list of dictionaries containing the columns-value pairs of a row in the `rides` table. To retrieve the data from the database bound to a particular `Session` object, we use `Session.query()`, a method of the `Session` class. This method returns a `Query` object, with methods for filtering and ordering query results. @@ -204,7 +204,7 @@ Note that `get_rides_txn()` gets all rides for a specific rider, which might be Another common query would be to read the registered vehicles in a particular city, to see which vehicles are available for riding. Unlike `get_rides_txn()`, the `get_vehicles_txn()` function takes the `city` string as an input. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_vehicles_txn ||# END get_vehicles_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-vehicles-txn.py %} ~~~ This function filters the query on the `city` column. `vehicle` rows with the same value for `city` are inserted from the same region, making `city` values implicitly correspond to a specific region. Because the `vehicles` table has a `REGIONAL BY ROW` locality, CockroachDB can locality-optimize queries from nodes with a locality matching the [hidden `crdb_region` column]({% link {{ page.version.version }}/movr-flask-database.md %}#table-locality). This limits latency, as the query only needs to travel to database deployments in a single region. @@ -216,7 +216,7 @@ There are two basic types of write operations: creating new rows and updating ex For example, `start_ride_txn()`, which is called when a user starts a ride, adds a new row to the `rides` table, and then updates a row in the `vehicles` table. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START start_ride_txn ||# END start_ride_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__start-ride-txn.py %} ~~~ The function takes the `city` string, `rider_id` UUID, `rider_city` string, and `vehicle_id` UUID as inputs. It queries the `vehicles` table for all vehicles of a specific ID. It also creates a `Ride` object, representing a row of the `rides` table. To add the ride to the table in the database bound to the `Session`, the function calls `Session.add()`. To update a row in the `vehicles` table, it modifies the object attribute. `start_ride_txn()` is called by `run_transaction()`, which commits the transaction to the database. @@ -232,7 +232,7 @@ The `MovR` class, defined in [`movr/movr.py`](https://github.com/cockroachlabs/m Let's start with the beginning of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__front.py %} ~~~ `movr.py` first imports the transaction callback functions that we defined in [`movr/transactions.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/transactions.py). It then imports the `run_transaction()` function. The `MovR` class methods call `run_transaction()` to execute the transaction callback functions as transactions. @@ -250,7 +250,7 @@ We've already defined the transaction logic in the transaction callback function For example, look at the `start_ride()` method, the method to which frontend requests to start a ride are routed: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START start_ride ||# END start_ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__start-ride.py %} ~~~ This method takes some keyword arguments, and then returns a `run_transaction()` call. It passes `sessionmaker(bind=self.engine)` as the first argument to `run_transaction()`, which creates a new `Session` object that binds to the `Engine` instance initialized by the `MovR` constructor. It also passes `city`, `rider_id`, `rider_city`, and `vehicle_id`, values passed from the frontend request, as inputs. These are the same keyword arguments, and should be of the same types, as the inputs for the [transaction callback function](#writing) `start_ride_txn()`. @@ -268,7 +268,7 @@ Most of the web application components are found in the `web` and `templates` fo We store the Flask configuration settings in [a `Config` class](https://flask.palletsprojects.com/config/#development-production), defined in [`web/config.py`](https://github.com/cockroachlabs/movr-flask/blob/master/web/config.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} ~~~ This file imports the `os` library, which is used to read from environment variables. When debugging a local deployment, these environment variables are set by the `.env` file that `Pipenv` reads. In a multi-region deployment, the environment variables are set by the `Dockerfile`, and by the [managed cloud deployment service]({% link {{ page.version.version }}/movr-flask-deployment.md %}). @@ -284,7 +284,7 @@ We will not go into much detail about these forms. The important thing to know i The `CredentialForm` class, for example, defines the fields of the login form that users interface with to send a login request to the server: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START CredentialForm ||# END CredentialForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__credentialform.py %} ~~~ Most of the forms defined on this page take the inputs for database reads and writes. @@ -292,7 +292,7 @@ Most of the forms defined on this page take the inputs for database reads and wr `VehicleForm`, for example, defines the fields of the vehicle registration form. Users enter information about a vehicle they would like to register, and the data is routed to the `add_vehicle()` method defined in [`movr/movr.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/movr.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START VehicleForm ||# END VehicleForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__vehicleform.py %} ~~~ ### Initialization @@ -302,7 +302,7 @@ Most of the forms defined on this page take the inputs for database reads and wr Let's look at the first ten lines of `server.py`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__front.py %} ~~~ The first line imports standard Flask libraries for connecting, routing, and rendering web pages. The next three lines import some libraries from the Flask ecosystem, for [bootstrapping](https://pythonhosted.org/Flask-Bootstrap/), [authentication](https://flask-login.readthedocs.io/), and [security](https://github.com/pallets/werkzeug/blob/master/src/werkzeug/security.py). @@ -318,7 +318,7 @@ Finally, we import the `DBAPIError` type from `sqlalchemy`, for error handling. The next five or so lines initialize the application: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START init ||# END init %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__init.py %} ~~~ Calling the `Flask()` constructor initializes our Flask web server. By assigning this to a variable (`app`), we can then configure the application, store variables in its attributes, and call it with functions from other libraries, to add features and functionality to the application. @@ -330,7 +330,7 @@ Note that we also define a `protocol` variable that the application later uses t After initializing the application, we can connect to the database: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START connect ||# END connect %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__connect.py %} ~~~ These two lines connect the application to the database. First the application retrieves the connection string that is stored as a configuration variable of the `app`. Then it calls the `MovR()` constructor to establish a connection to the database at the location we provided to the `Config` object. @@ -342,7 +342,7 @@ User authentication is handled with the [`Flask-Login`](https://flask-login.read To control whether certain routes are accessible to a client session, we define a [`user_loader()` function](https://flask-login.readthedocs.io/#flask_login.LoginManager.user_loader): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START user_loader ||# END user_loader %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__user-loader.py %} ~~~ To restrict access to a certain page to users that are logged in with the [`LoginManager`](https://flask-login.readthedocs.io/#flask_login.LoginManager), we add the `@login_required` decorator function to the route. We'll go over some examples in the [Routing](#routing) section below. @@ -364,7 +364,7 @@ In addition to calling these functions, and some other standard Flask and Python For example, look at the `login()` route: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START login_page ||# END login_page %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__login-page.py %} ~~~ ### Client Location diff --git a/src/current/v24.3/movr-flask-database.md b/src/current/v24.3/movr-flask-database.md index 4bb882c2135..e7075ae53ae 100644 --- a/src/current/v24.3/movr-flask-database.md +++ b/src/current/v24.3/movr-flask-database.md @@ -48,7 +48,7 @@ Here is the [`CREATE DATABASE`]({% link {{ page.version.version }}/create-databa {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START database ||-- END database %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__database.sql %} ~~~ In this example, `movr` has the following [database regions]({% link {{ page.version.version }}/multiregion-overview.md %}#database-regions), which correspond to regions in Google Cloud: @@ -77,14 +77,14 @@ Here is the `CREATE TABLE` statement for the `users` table: {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START users ||-- END users %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__users.sql %} ~~~ ## The `vehicles` table {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START vehicles ||-- END vehicles %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__vehicles.sql %} ~~~ The `vehicles` table has a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) on the `users` table, for the `city` and `owner_id` columns. This guarantees that a vehicle is registered to a particular user (i.e., an "owner") in the city where that user is registered. @@ -93,7 +93,7 @@ The `vehicles` table has a [foreign key constraint]({% link {{ page.version.vers {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START rides ||-- END rides %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__rides.sql %} ~~~ Like the `vehicles` table, the `rides` table has foreign key constraints. These constraints are on the `users` and the `vehicles` tables. diff --git a/src/current/v25.1/build-a-csharp-app-with-cockroachdb.md b/src/current/v25.1/build-a-csharp-app-with-cockroachdb.md index 115abf8febd..6e71dfb298f 100644 --- a/src/current/v25.1/build-a-csharp-app-with-cockroachdb.md +++ b/src/current/v25.1/build-a-csharp-app-with-cockroachdb.md @@ -69,7 +69,7 @@ Replace the contents of the `Program.cs` file that was automatically generated i {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/basic.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/basic.cs %} ~~~ #### Run the basic example @@ -99,7 +99,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs %} ~~~
@@ -108,7 +108,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} ~~~ diff --git a/src/current/v25.1/build-a-go-app-with-cockroachdb-gorm.md b/src/current/v25.1/build-a-go-app-with-cockroachdb-gorm.md index 23ee58cd997..aac3820127f 100644 --- a/src/current/v25.1/build-a-go-app-with-cockroachdb-gorm.md +++ b/src/current/v25.1/build-a-go-app-with-cockroachdb-gorm.md @@ -39,7 +39,7 @@ The `main.go` file defines an `Account` struct that maps to a new `accounts` tab {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-gorm/master/main.go %} +{% include example-apps/cockroachlabs/example-app-go-gorm/master/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v25.1/build-a-go-app-with-cockroachdb.md b/src/current/v25.1/build-a-go-app-with-cockroachdb.md index 8a00ed10cb4..89ef7c4669e 100644 --- a/src/current/v25.1/build-a-go-app-with-cockroachdb.md +++ b/src/current/v25.1/build-a-go-app-with-cockroachdb.md @@ -35,7 +35,7 @@ The `main.go` file contains the code for `CREATE TABLE`, `INSERT`, `SELECT`, `UP {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-pgx/main/main.go %} +{% include example-apps/cockroachlabs/example-app-go-pgx/main/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v25.1/build-a-java-app-with-cockroachdb-hibernate.md b/src/current/v25.1/build-a-java-app-with-cockroachdb-hibernate.md index c4b53d27629..e266f78bff0 100644 --- a/src/current/v25.1/build-a-java-app-with-cockroachdb-hibernate.md +++ b/src/current/v25.1/build-a-java-app-with-cockroachdb-hibernate.md @@ -54,7 +54,7 @@ The contents of `Sample.java`: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} +{% include example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} ~~~
diff --git a/src/current/v25.1/build-a-java-app-with-cockroachdb.md b/src/current/v25.1/build-a-java-app-with-cockroachdb.md index d798e9dbaee..65b936c0feb 100644 --- a/src/current/v25.1/build-a-java-app-with-cockroachdb.md +++ b/src/current/v25.1/build-a-java-app-with-cockroachdb.md @@ -55,7 +55,7 @@ The `BasicExample.java` file contains the code for `INSERT`, `SELECT`, and `UPDA {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} +{% include example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} ~~~ The sample app uses JDBC and the [Data Access Object (DAO)](https://wikipedia.org/wiki/Data_access_object) pattern to map Java methods to SQL operations. It consists of two classes: diff --git a/src/current/v25.1/build-a-nodejs-app-with-cockroachdb-prisma.md b/src/current/v25.1/build-a-nodejs-app-with-cockroachdb-prisma.md index afda47789ec..6e16095554d 100644 --- a/src/current/v25.1/build-a-nodejs-app-with-cockroachdb-prisma.md +++ b/src/current/v25.1/build-a-nodejs-app-with-cockroachdb-prisma.md @@ -89,7 +89,7 @@ The `index.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DEL {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-prisma/main/index.js %} +{% include example-apps/cockroachlabs/example-app-node-prisma/main/index.js %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v25.1/build-a-nodejs-app-with-cockroachdb.md b/src/current/v25.1/build-a-nodejs-app-with-cockroachdb.md index dba17b3fb8f..d00b2bfa180 100644 --- a/src/current/v25.1/build-a-nodejs-app-with-cockroachdb.md +++ b/src/current/v25.1/build-a-nodejs-app-with-cockroachdb.md @@ -39,14 +39,14 @@ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ sql -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} ~~~ The `app.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DELETE` SQL operations: {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/app.js %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/app.js %} ~~~ All of the database operations are wrapped in a helper function named `retryTxn`. This function attempts to commit statements in the context of an explicit transaction. If a [retry error]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) is thrown, the wrapper will retry committing the transaction, with [exponential backoff](https://wikipedia.org/wiki/Exponential_backoff), until the maximum number of retries is reached (by default, 15). diff --git a/src/current/v25.1/build-a-python-app-with-cockroachdb-django.md b/src/current/v25.1/build-a-python-app-with-cockroachdb-django.md index 85644de65ed..e3a8eef46cd 100644 --- a/src/current/v25.1/build-a-python-app-with-cockroachdb-django.md +++ b/src/current/v25.1/build-a-python-app-with-cockroachdb-django.md @@ -67,7 +67,7 @@ The `requirements.txt` file at the top level of the `example-app-python-django` {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-django/master/requirements.txt %} ~~~ This tutorial uses [`virtualenv`](https://virtualenv.pypa.io) for dependency management. @@ -135,7 +135,7 @@ Start by building some [models](https://docs.djangoproject.com/en/3.1/topics/db/ {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} ~~~ In this file, we define some simple classes that map to the tables in the cluster. @@ -146,7 +146,7 @@ Next, build out some [class-based views](https://docs.djangoproject.com/en/3.1/t {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} ~~~ This file defines the application's views as classes. Each view class corresponds to one of the table classes defined in `models.py`. The methods of these classes define read and write transactions on the tables in the database. @@ -159,7 +159,7 @@ Lastly, define some [URL routes](https://docs.djangoproject.com/en/3.1/topics/ht {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} ~~~ ## Step 5. Initialize the database diff --git a/src/current/v25.1/build-a-python-app-with-cockroachdb-sqlalchemy.md b/src/current/v25.1/build-a-python-app-with-cockroachdb-sqlalchemy.md index e56b9c136a8..70e205bbdad 100644 --- a/src/current/v25.1/build-a-python-app-with-cockroachdb-sqlalchemy.md +++ b/src/current/v25.1/build-a-python-app-with-cockroachdb-sqlalchemy.md @@ -40,28 +40,28 @@ The `requirements.txt` file includes the required libraries to connect to Cockro {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} ~~~ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} ~~~ The `models.py` uses SQLAlchemy to map the `Accounts` table to a Python object: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} ~~~ The `main.py` uses SQLAlchemy to map Python methods to SQL operations: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} ~~~ `main.py` also executes the `main` method of the program. diff --git a/src/current/v25.1/build-a-rust-app-with-cockroachdb.md b/src/current/v25.1/build-a-rust-app-with-cockroachdb.md index 4ca08938824..46b9cdea10c 100644 --- a/src/current/v25.1/build-a-rust-app-with-cockroachdb.md +++ b/src/current/v25.1/build-a-rust-app-with-cockroachdb.md @@ -39,7 +39,7 @@ The `Cargo.toml` file is the configuration file for the example, and sets the de {% include_cached copy-clipboard.html %} ~~~ toml -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} ~~~ The `main` function is the entry point for the application, with the code for connecting to the cluster, creating the `accounts` table, creating accounts in that table, and transferring money between two accounts. @@ -52,14 +52,14 @@ CockroachDB may require the [client to retry a transaction]({% link {{ page.vers {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN execute_txn || END execute_txn %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs %} ~~~ The `transfer_funds` function calls `execute_txn` to perform the actual transfer of funds from one account to the other. {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN transfer_funds || END transfer_funds %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs %} ~~~ ## Step 3. Run the code diff --git a/src/current/v25.1/build-a-spring-app-with-cockroachdb-jdbc.md b/src/current/v25.1/build-a-spring-app-with-cockroachdb-jdbc.md index c6046d645dd..71dbf62fc7b 100644 --- a/src/current/v25.1/build-a-spring-app-with-cockroachdb-jdbc.md +++ b/src/current/v25.1/build-a-spring-app-with-cockroachdb-jdbc.md @@ -606,7 +606,7 @@ Here are the contents of [`JdbcApplication.java`](https://github.com/cockroachla {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} ~~~ The annotations listed at the top of the `JdbcApplication` class definition declare some important configuration properties for the entire application: @@ -631,14 +631,14 @@ Liquibase uses [changelog files](https://docs.liquibase.com/concepts/basic/chang {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -696,7 +696,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} ~~~ ### Hypermedia representation @@ -707,7 +707,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -720,7 +720,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for generic [CRUD operations](https://wikipedia.org/wiki/Create,_read,_update_and_delete) called `CrudRepository`. To support [pagination queries]({% link {{ page.version.version }}/pagination.md %}), repositories in other Spring Data modules, like those in Spring Data JPA, usually extend a subinterface of `CrudRepository`, called `PagingAndSortingRepository`, that includes pagination and sorting methods. At the time this sample application was created, Spring Data JDBC did not support pagination. As a result, `AccountRepository` extends a custom repository, called `PagedAccountRepository`, to provide basic [`LIMIT`/`OFFSET` pagination]({% link {{ page.version.version }}/pagination.md %}) on queries against the `accounts` table. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/#jdbc.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -737,7 +737,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -773,7 +773,7 @@ The `TransactionHintsAspect` class, declared as an aspect with the [`@Aspect` an {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. @@ -790,7 +790,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` pointcut definition is identical to the one declared in `TransactionHintsAspect`. The `execution` designator matches all methods in the `io.roach.` namespace, and the `@annotation` designator limits the matches to methods with the `@Transactional` annotation. diff --git a/src/current/v25.1/build-a-spring-app-with-cockroachdb-jpa.md b/src/current/v25.1/build-a-spring-app-with-cockroachdb-jpa.md index d9e1c60c6dd..b45b8e6f1f4 100644 --- a/src/current/v25.1/build-a-spring-app-with-cockroachdb-jpa.md +++ b/src/current/v25.1/build-a-spring-app-with-cockroachdb-jpa.md @@ -517,7 +517,7 @@ Here are the contents of [`JpaApplication.java`](https://github.com/cockroachlab {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} ~~~ The annotations listed at the top of the `JpaApplication` class definition declare some important configuration properties for the entire application: @@ -540,14 +540,14 @@ Liquibase uses files called [changelogs](https://docs.liquibase.com/concepts/bas {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -596,7 +596,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} ~~~ Spring Data JPA supports standard Java Persistence API (JPA) annotations for domain entity class definitions. The `Account` class definition uses these annotations to create the `accounts` table entity: @@ -616,7 +616,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -629,7 +629,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for JPA data access called `JpaRepository`. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -646,7 +646,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -677,7 +677,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. diff --git a/src/current/v25.1/movr-flask-application.md b/src/current/v25.1/movr-flask-application.md index 68b2a10b900..558f365637b 100644 --- a/src/current/v25.1/movr-flask-application.md +++ b/src/current/v25.1/movr-flask-application.md @@ -87,7 +87,7 @@ After completing the [Create a Multi-Region Database Schema]({% link {{ page.ver Open [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), and look at the first 10 lines of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__front.py %} ~~~ The first data structure that the file imports is `declarative_base`, a constructor for the [declarative base class](https://docs.sqlalchemy.org/orm/extensions/declarative/api.html#sqlalchemy.ext.declarative.declarative_base), built on SQLAlchemy's Declarative extension. All mapped objects inherit from this object. We assign a declarative base object to the `Base` variable right below the imports. @@ -103,7 +103,7 @@ Recall that each instance of a table class represents a row in the table, so we Take a look at the `User` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START User ||# END User %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__user.py %} ~~~ The `User` class has the following attributes: @@ -118,7 +118,7 @@ The `User` class has the following attributes: Next, look at the `Vehicle` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Vehicle ||# END Vehicle %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__vehicle.py %} ~~~ Recall that the `vehicles` table contains more columns and data types than the `users` table. It also contains a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) (on the `users` table), and a default value. These differences are reflected in the `Vehicle` class. @@ -128,7 +128,7 @@ Recall that the `vehicles` table contains more columns and data types than the ` Take a look at the `Ride` class: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Ride ||# END Ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__ride.py %} ~~~ The `rides` table has three foreign key constraints, one on the `users` table and two on the `vehicles` table. @@ -186,7 +186,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` `transactions.py` imports all of the table classes that we defined in [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), in addition to some standard Python data structures needed to generate correctly-typed row values that the ORM can write to the database. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__front.py %} ~~~ ##### Reading @@ -194,7 +194,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` A common query that a client might want to run is a read of the `rides` table. The transaction callback function for this query is defined here as `get_rides_txn()`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_rides_txn ||# END get_rides_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-rides-txn.py %} ~~~ The `get_rides_txn()` function takes a `Session` object and a `rider_id` string as its inputs, and it outputs a list of dictionaries containing the columns-value pairs of a row in the `rides` table. To retrieve the data from the database bound to a particular `Session` object, we use `Session.query()`, a method of the `Session` class. This method returns a `Query` object, with methods for filtering and ordering query results. @@ -204,7 +204,7 @@ Note that `get_rides_txn()` gets all rides for a specific rider, which might be Another common query would be to read the registered vehicles in a particular city, to see which vehicles are available for riding. Unlike `get_rides_txn()`, the `get_vehicles_txn()` function takes the `city` string as an input. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_vehicles_txn ||# END get_vehicles_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-vehicles-txn.py %} ~~~ This function filters the query on the `city` column. `vehicle` rows with the same value for `city` are inserted from the same region, making `city` values implicitly correspond to a specific region. Because the `vehicles` table has a `REGIONAL BY ROW` locality, CockroachDB can locality-optimize queries from nodes with a locality matching the [hidden `crdb_region` column]({% link {{ page.version.version }}/movr-flask-database.md %}#table-locality). This limits latency, as the query only needs to travel to database deployments in a single region. @@ -216,7 +216,7 @@ There are two basic types of write operations: creating new rows and updating ex For example, `start_ride_txn()`, which is called when a user starts a ride, adds a new row to the `rides` table, and then updates a row in the `vehicles` table. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START start_ride_txn ||# END start_ride_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__start-ride-txn.py %} ~~~ The function takes the `city` string, `rider_id` UUID, `rider_city` string, and `vehicle_id` UUID as inputs. It queries the `vehicles` table for all vehicles of a specific ID. It also creates a `Ride` object, representing a row of the `rides` table. To add the ride to the table in the database bound to the `Session`, the function calls `Session.add()`. To update a row in the `vehicles` table, it modifies the object attribute. `start_ride_txn()` is called by `run_transaction()`, which commits the transaction to the database. @@ -232,7 +232,7 @@ The `MovR` class, defined in [`movr/movr.py`](https://github.com/cockroachlabs/m Let's start with the beginning of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__front.py %} ~~~ `movr.py` first imports the transaction callback functions that we defined in [`movr/transactions.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/transactions.py). It then imports the `run_transaction()` function. The `MovR` class methods call `run_transaction()` to execute the transaction callback functions as transactions. @@ -250,7 +250,7 @@ We've already defined the transaction logic in the transaction callback function For example, look at the `start_ride()` method, the method to which frontend requests to start a ride are routed: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START start_ride ||# END start_ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__start-ride.py %} ~~~ This method takes some keyword arguments, and then returns a `run_transaction()` call. It passes `sessionmaker(bind=self.engine)` as the first argument to `run_transaction()`, which creates a new `Session` object that binds to the `Engine` instance initialized by the `MovR` constructor. It also passes `city`, `rider_id`, `rider_city`, and `vehicle_id`, values passed from the frontend request, as inputs. These are the same keyword arguments, and should be of the same types, as the inputs for the [transaction callback function](#writing) `start_ride_txn()`. @@ -268,7 +268,7 @@ Most of the web application components are found in the `web` and `templates` fo We store the Flask configuration settings in [a `Config` class](https://flask.palletsprojects.com/config/#development-production), defined in [`web/config.py`](https://github.com/cockroachlabs/movr-flask/blob/master/web/config.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} ~~~ This file imports the `os` library, which is used to read from environment variables. When debugging a local deployment, these environment variables are set by the `.env` file that `Pipenv` reads. In a multi-region deployment, the environment variables are set by the `Dockerfile`, and by the [managed cloud deployment service]({% link {{ page.version.version }}/movr-flask-deployment.md %}). @@ -284,7 +284,7 @@ We will not go into much detail about these forms. The important thing to know i The `CredentialForm` class, for example, defines the fields of the login form that users interface with to send a login request to the server: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START CredentialForm ||# END CredentialForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__credentialform.py %} ~~~ Most of the forms defined on this page take the inputs for database reads and writes. @@ -292,7 +292,7 @@ Most of the forms defined on this page take the inputs for database reads and wr `VehicleForm`, for example, defines the fields of the vehicle registration form. Users enter information about a vehicle they would like to register, and the data is routed to the `add_vehicle()` method defined in [`movr/movr.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/movr.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START VehicleForm ||# END VehicleForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__vehicleform.py %} ~~~ ### Initialization @@ -302,7 +302,7 @@ Most of the forms defined on this page take the inputs for database reads and wr Let's look at the first ten lines of `server.py`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__front.py %} ~~~ The first line imports standard Flask libraries for connecting, routing, and rendering web pages. The next three lines import some libraries from the Flask ecosystem, for [bootstrapping](https://pythonhosted.org/Flask-Bootstrap/), [authentication](https://flask-login.readthedocs.io/), and [security](https://github.com/pallets/werkzeug/blob/master/src/werkzeug/security.py). @@ -318,7 +318,7 @@ Finally, we import the `DBAPIError` type from `sqlalchemy`, for error handling. The next five or so lines initialize the application: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START init ||# END init %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__init.py %} ~~~ Calling the `Flask()` constructor initializes our Flask web server. By assigning this to a variable (`app`), we can then configure the application, store variables in its attributes, and call it with functions from other libraries, to add features and functionality to the application. @@ -330,7 +330,7 @@ Note that we also define a `protocol` variable that the application later uses t After initializing the application, we can connect to the database: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START connect ||# END connect %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__connect.py %} ~~~ These two lines connect the application to the database. First the application retrieves the connection string that is stored as a configuration variable of the `app`. Then it calls the `MovR()` constructor to establish a connection to the database at the location we provided to the `Config` object. @@ -342,7 +342,7 @@ User authentication is handled with the [`Flask-Login`](https://flask-login.read To control whether certain routes are accessible to a client session, we define a [`user_loader()` function](https://flask-login.readthedocs.io/#flask_login.LoginManager.user_loader): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START user_loader ||# END user_loader %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__user-loader.py %} ~~~ To restrict access to a certain page to users that are logged in with the [`LoginManager`](https://flask-login.readthedocs.io/#flask_login.LoginManager), we add the `@login_required` decorator function to the route. We'll go over some examples in the [Routing](#routing) section below. @@ -364,7 +364,7 @@ In addition to calling these functions, and some other standard Flask and Python For example, look at the `login()` route: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START login_page ||# END login_page %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__login-page.py %} ~~~ ### Client Location diff --git a/src/current/v25.1/movr-flask-database.md b/src/current/v25.1/movr-flask-database.md index 4bb882c2135..e7075ae53ae 100644 --- a/src/current/v25.1/movr-flask-database.md +++ b/src/current/v25.1/movr-flask-database.md @@ -48,7 +48,7 @@ Here is the [`CREATE DATABASE`]({% link {{ page.version.version }}/create-databa {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START database ||-- END database %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__database.sql %} ~~~ In this example, `movr` has the following [database regions]({% link {{ page.version.version }}/multiregion-overview.md %}#database-regions), which correspond to regions in Google Cloud: @@ -77,14 +77,14 @@ Here is the `CREATE TABLE` statement for the `users` table: {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START users ||-- END users %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__users.sql %} ~~~ ## The `vehicles` table {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START vehicles ||-- END vehicles %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__vehicles.sql %} ~~~ The `vehicles` table has a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) on the `users` table, for the `city` and `owner_id` columns. This guarantees that a vehicle is registered to a particular user (i.e., an "owner") in the city where that user is registered. @@ -93,7 +93,7 @@ The `vehicles` table has a [foreign key constraint]({% link {{ page.version.vers {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START rides ||-- END rides %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__rides.sql %} ~~~ Like the `vehicles` table, the `rides` table has foreign key constraints. These constraints are on the `users` and the `vehicles` tables. diff --git a/src/current/v25.2/build-a-csharp-app-with-cockroachdb.md b/src/current/v25.2/build-a-csharp-app-with-cockroachdb.md index 115abf8febd..6e71dfb298f 100644 --- a/src/current/v25.2/build-a-csharp-app-with-cockroachdb.md +++ b/src/current/v25.2/build-a-csharp-app-with-cockroachdb.md @@ -69,7 +69,7 @@ Replace the contents of the `Program.cs` file that was automatically generated i {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/basic.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/basic.cs %} ~~~ #### Run the basic example @@ -99,7 +99,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs %} ~~~
@@ -108,7 +108,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} ~~~ diff --git a/src/current/v25.2/build-a-go-app-with-cockroachdb-gorm.md b/src/current/v25.2/build-a-go-app-with-cockroachdb-gorm.md index 23ee58cd997..aac3820127f 100644 --- a/src/current/v25.2/build-a-go-app-with-cockroachdb-gorm.md +++ b/src/current/v25.2/build-a-go-app-with-cockroachdb-gorm.md @@ -39,7 +39,7 @@ The `main.go` file defines an `Account` struct that maps to a new `accounts` tab {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-gorm/master/main.go %} +{% include example-apps/cockroachlabs/example-app-go-gorm/master/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v25.2/build-a-go-app-with-cockroachdb.md b/src/current/v25.2/build-a-go-app-with-cockroachdb.md index 8a00ed10cb4..89ef7c4669e 100644 --- a/src/current/v25.2/build-a-go-app-with-cockroachdb.md +++ b/src/current/v25.2/build-a-go-app-with-cockroachdb.md @@ -35,7 +35,7 @@ The `main.go` file contains the code for `CREATE TABLE`, `INSERT`, `SELECT`, `UP {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-pgx/main/main.go %} +{% include example-apps/cockroachlabs/example-app-go-pgx/main/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v25.2/build-a-java-app-with-cockroachdb-hibernate.md b/src/current/v25.2/build-a-java-app-with-cockroachdb-hibernate.md index c4b53d27629..e266f78bff0 100644 --- a/src/current/v25.2/build-a-java-app-with-cockroachdb-hibernate.md +++ b/src/current/v25.2/build-a-java-app-with-cockroachdb-hibernate.md @@ -54,7 +54,7 @@ The contents of `Sample.java`: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} +{% include example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} ~~~
diff --git a/src/current/v25.2/build-a-java-app-with-cockroachdb.md b/src/current/v25.2/build-a-java-app-with-cockroachdb.md index d798e9dbaee..65b936c0feb 100644 --- a/src/current/v25.2/build-a-java-app-with-cockroachdb.md +++ b/src/current/v25.2/build-a-java-app-with-cockroachdb.md @@ -55,7 +55,7 @@ The `BasicExample.java` file contains the code for `INSERT`, `SELECT`, and `UPDA {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} +{% include example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} ~~~ The sample app uses JDBC and the [Data Access Object (DAO)](https://wikipedia.org/wiki/Data_access_object) pattern to map Java methods to SQL operations. It consists of two classes: diff --git a/src/current/v25.2/build-a-nodejs-app-with-cockroachdb-prisma.md b/src/current/v25.2/build-a-nodejs-app-with-cockroachdb-prisma.md index afda47789ec..6e16095554d 100644 --- a/src/current/v25.2/build-a-nodejs-app-with-cockroachdb-prisma.md +++ b/src/current/v25.2/build-a-nodejs-app-with-cockroachdb-prisma.md @@ -89,7 +89,7 @@ The `index.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DEL {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-prisma/main/index.js %} +{% include example-apps/cockroachlabs/example-app-node-prisma/main/index.js %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v25.2/build-a-nodejs-app-with-cockroachdb.md b/src/current/v25.2/build-a-nodejs-app-with-cockroachdb.md index dba17b3fb8f..d00b2bfa180 100644 --- a/src/current/v25.2/build-a-nodejs-app-with-cockroachdb.md +++ b/src/current/v25.2/build-a-nodejs-app-with-cockroachdb.md @@ -39,14 +39,14 @@ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ sql -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} ~~~ The `app.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DELETE` SQL operations: {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/app.js %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/app.js %} ~~~ All of the database operations are wrapped in a helper function named `retryTxn`. This function attempts to commit statements in the context of an explicit transaction. If a [retry error]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) is thrown, the wrapper will retry committing the transaction, with [exponential backoff](https://wikipedia.org/wiki/Exponential_backoff), until the maximum number of retries is reached (by default, 15). diff --git a/src/current/v25.2/build-a-python-app-with-cockroachdb-django.md b/src/current/v25.2/build-a-python-app-with-cockroachdb-django.md index 85644de65ed..e3a8eef46cd 100644 --- a/src/current/v25.2/build-a-python-app-with-cockroachdb-django.md +++ b/src/current/v25.2/build-a-python-app-with-cockroachdb-django.md @@ -67,7 +67,7 @@ The `requirements.txt` file at the top level of the `example-app-python-django` {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-django/master/requirements.txt %} ~~~ This tutorial uses [`virtualenv`](https://virtualenv.pypa.io) for dependency management. @@ -135,7 +135,7 @@ Start by building some [models](https://docs.djangoproject.com/en/3.1/topics/db/ {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} ~~~ In this file, we define some simple classes that map to the tables in the cluster. @@ -146,7 +146,7 @@ Next, build out some [class-based views](https://docs.djangoproject.com/en/3.1/t {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} ~~~ This file defines the application's views as classes. Each view class corresponds to one of the table classes defined in `models.py`. The methods of these classes define read and write transactions on the tables in the database. @@ -159,7 +159,7 @@ Lastly, define some [URL routes](https://docs.djangoproject.com/en/3.1/topics/ht {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} ~~~ ## Step 5. Initialize the database diff --git a/src/current/v25.2/build-a-python-app-with-cockroachdb-sqlalchemy.md b/src/current/v25.2/build-a-python-app-with-cockroachdb-sqlalchemy.md index e56b9c136a8..70e205bbdad 100644 --- a/src/current/v25.2/build-a-python-app-with-cockroachdb-sqlalchemy.md +++ b/src/current/v25.2/build-a-python-app-with-cockroachdb-sqlalchemy.md @@ -40,28 +40,28 @@ The `requirements.txt` file includes the required libraries to connect to Cockro {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} ~~~ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} ~~~ The `models.py` uses SQLAlchemy to map the `Accounts` table to a Python object: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} ~~~ The `main.py` uses SQLAlchemy to map Python methods to SQL operations: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} ~~~ `main.py` also executes the `main` method of the program. diff --git a/src/current/v25.2/build-a-rust-app-with-cockroachdb.md b/src/current/v25.2/build-a-rust-app-with-cockroachdb.md index 4ca08938824..46b9cdea10c 100644 --- a/src/current/v25.2/build-a-rust-app-with-cockroachdb.md +++ b/src/current/v25.2/build-a-rust-app-with-cockroachdb.md @@ -39,7 +39,7 @@ The `Cargo.toml` file is the configuration file for the example, and sets the de {% include_cached copy-clipboard.html %} ~~~ toml -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} ~~~ The `main` function is the entry point for the application, with the code for connecting to the cluster, creating the `accounts` table, creating accounts in that table, and transferring money between two accounts. @@ -52,14 +52,14 @@ CockroachDB may require the [client to retry a transaction]({% link {{ page.vers {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN execute_txn || END execute_txn %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs %} ~~~ The `transfer_funds` function calls `execute_txn` to perform the actual transfer of funds from one account to the other. {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN transfer_funds || END transfer_funds %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs %} ~~~ ## Step 3. Run the code diff --git a/src/current/v25.2/build-a-spring-app-with-cockroachdb-jdbc.md b/src/current/v25.2/build-a-spring-app-with-cockroachdb-jdbc.md index c6046d645dd..71dbf62fc7b 100644 --- a/src/current/v25.2/build-a-spring-app-with-cockroachdb-jdbc.md +++ b/src/current/v25.2/build-a-spring-app-with-cockroachdb-jdbc.md @@ -606,7 +606,7 @@ Here are the contents of [`JdbcApplication.java`](https://github.com/cockroachla {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} ~~~ The annotations listed at the top of the `JdbcApplication` class definition declare some important configuration properties for the entire application: @@ -631,14 +631,14 @@ Liquibase uses [changelog files](https://docs.liquibase.com/concepts/basic/chang {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -696,7 +696,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} ~~~ ### Hypermedia representation @@ -707,7 +707,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -720,7 +720,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for generic [CRUD operations](https://wikipedia.org/wiki/Create,_read,_update_and_delete) called `CrudRepository`. To support [pagination queries]({% link {{ page.version.version }}/pagination.md %}), repositories in other Spring Data modules, like those in Spring Data JPA, usually extend a subinterface of `CrudRepository`, called `PagingAndSortingRepository`, that includes pagination and sorting methods. At the time this sample application was created, Spring Data JDBC did not support pagination. As a result, `AccountRepository` extends a custom repository, called `PagedAccountRepository`, to provide basic [`LIMIT`/`OFFSET` pagination]({% link {{ page.version.version }}/pagination.md %}) on queries against the `accounts` table. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/#jdbc.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -737,7 +737,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -773,7 +773,7 @@ The `TransactionHintsAspect` class, declared as an aspect with the [`@Aspect` an {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. @@ -790,7 +790,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` pointcut definition is identical to the one declared in `TransactionHintsAspect`. The `execution` designator matches all methods in the `io.roach.` namespace, and the `@annotation` designator limits the matches to methods with the `@Transactional` annotation. diff --git a/src/current/v25.2/build-a-spring-app-with-cockroachdb-jpa.md b/src/current/v25.2/build-a-spring-app-with-cockroachdb-jpa.md index d9e1c60c6dd..b45b8e6f1f4 100644 --- a/src/current/v25.2/build-a-spring-app-with-cockroachdb-jpa.md +++ b/src/current/v25.2/build-a-spring-app-with-cockroachdb-jpa.md @@ -517,7 +517,7 @@ Here are the contents of [`JpaApplication.java`](https://github.com/cockroachlab {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} ~~~ The annotations listed at the top of the `JpaApplication` class definition declare some important configuration properties for the entire application: @@ -540,14 +540,14 @@ Liquibase uses files called [changelogs](https://docs.liquibase.com/concepts/bas {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -596,7 +596,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} ~~~ Spring Data JPA supports standard Java Persistence API (JPA) annotations for domain entity class definitions. The `Account` class definition uses these annotations to create the `accounts` table entity: @@ -616,7 +616,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -629,7 +629,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for JPA data access called `JpaRepository`. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -646,7 +646,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -677,7 +677,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. diff --git a/src/current/v25.2/movr-flask-application.md b/src/current/v25.2/movr-flask-application.md index 68b2a10b900..558f365637b 100644 --- a/src/current/v25.2/movr-flask-application.md +++ b/src/current/v25.2/movr-flask-application.md @@ -87,7 +87,7 @@ After completing the [Create a Multi-Region Database Schema]({% link {{ page.ver Open [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), and look at the first 10 lines of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__front.py %} ~~~ The first data structure that the file imports is `declarative_base`, a constructor for the [declarative base class](https://docs.sqlalchemy.org/orm/extensions/declarative/api.html#sqlalchemy.ext.declarative.declarative_base), built on SQLAlchemy's Declarative extension. All mapped objects inherit from this object. We assign a declarative base object to the `Base` variable right below the imports. @@ -103,7 +103,7 @@ Recall that each instance of a table class represents a row in the table, so we Take a look at the `User` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START User ||# END User %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__user.py %} ~~~ The `User` class has the following attributes: @@ -118,7 +118,7 @@ The `User` class has the following attributes: Next, look at the `Vehicle` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Vehicle ||# END Vehicle %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__vehicle.py %} ~~~ Recall that the `vehicles` table contains more columns and data types than the `users` table. It also contains a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) (on the `users` table), and a default value. These differences are reflected in the `Vehicle` class. @@ -128,7 +128,7 @@ Recall that the `vehicles` table contains more columns and data types than the ` Take a look at the `Ride` class: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Ride ||# END Ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__ride.py %} ~~~ The `rides` table has three foreign key constraints, one on the `users` table and two on the `vehicles` table. @@ -186,7 +186,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` `transactions.py` imports all of the table classes that we defined in [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), in addition to some standard Python data structures needed to generate correctly-typed row values that the ORM can write to the database. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__front.py %} ~~~ ##### Reading @@ -194,7 +194,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` A common query that a client might want to run is a read of the `rides` table. The transaction callback function for this query is defined here as `get_rides_txn()`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_rides_txn ||# END get_rides_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-rides-txn.py %} ~~~ The `get_rides_txn()` function takes a `Session` object and a `rider_id` string as its inputs, and it outputs a list of dictionaries containing the columns-value pairs of a row in the `rides` table. To retrieve the data from the database bound to a particular `Session` object, we use `Session.query()`, a method of the `Session` class. This method returns a `Query` object, with methods for filtering and ordering query results. @@ -204,7 +204,7 @@ Note that `get_rides_txn()` gets all rides for a specific rider, which might be Another common query would be to read the registered vehicles in a particular city, to see which vehicles are available for riding. Unlike `get_rides_txn()`, the `get_vehicles_txn()` function takes the `city` string as an input. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_vehicles_txn ||# END get_vehicles_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-vehicles-txn.py %} ~~~ This function filters the query on the `city` column. `vehicle` rows with the same value for `city` are inserted from the same region, making `city` values implicitly correspond to a specific region. Because the `vehicles` table has a `REGIONAL BY ROW` locality, CockroachDB can locality-optimize queries from nodes with a locality matching the [hidden `crdb_region` column]({% link {{ page.version.version }}/movr-flask-database.md %}#table-locality). This limits latency, as the query only needs to travel to database deployments in a single region. @@ -216,7 +216,7 @@ There are two basic types of write operations: creating new rows and updating ex For example, `start_ride_txn()`, which is called when a user starts a ride, adds a new row to the `rides` table, and then updates a row in the `vehicles` table. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START start_ride_txn ||# END start_ride_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__start-ride-txn.py %} ~~~ The function takes the `city` string, `rider_id` UUID, `rider_city` string, and `vehicle_id` UUID as inputs. It queries the `vehicles` table for all vehicles of a specific ID. It also creates a `Ride` object, representing a row of the `rides` table. To add the ride to the table in the database bound to the `Session`, the function calls `Session.add()`. To update a row in the `vehicles` table, it modifies the object attribute. `start_ride_txn()` is called by `run_transaction()`, which commits the transaction to the database. @@ -232,7 +232,7 @@ The `MovR` class, defined in [`movr/movr.py`](https://github.com/cockroachlabs/m Let's start with the beginning of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__front.py %} ~~~ `movr.py` first imports the transaction callback functions that we defined in [`movr/transactions.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/transactions.py). It then imports the `run_transaction()` function. The `MovR` class methods call `run_transaction()` to execute the transaction callback functions as transactions. @@ -250,7 +250,7 @@ We've already defined the transaction logic in the transaction callback function For example, look at the `start_ride()` method, the method to which frontend requests to start a ride are routed: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START start_ride ||# END start_ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__start-ride.py %} ~~~ This method takes some keyword arguments, and then returns a `run_transaction()` call. It passes `sessionmaker(bind=self.engine)` as the first argument to `run_transaction()`, which creates a new `Session` object that binds to the `Engine` instance initialized by the `MovR` constructor. It also passes `city`, `rider_id`, `rider_city`, and `vehicle_id`, values passed from the frontend request, as inputs. These are the same keyword arguments, and should be of the same types, as the inputs for the [transaction callback function](#writing) `start_ride_txn()`. @@ -268,7 +268,7 @@ Most of the web application components are found in the `web` and `templates` fo We store the Flask configuration settings in [a `Config` class](https://flask.palletsprojects.com/config/#development-production), defined in [`web/config.py`](https://github.com/cockroachlabs/movr-flask/blob/master/web/config.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} ~~~ This file imports the `os` library, which is used to read from environment variables. When debugging a local deployment, these environment variables are set by the `.env` file that `Pipenv` reads. In a multi-region deployment, the environment variables are set by the `Dockerfile`, and by the [managed cloud deployment service]({% link {{ page.version.version }}/movr-flask-deployment.md %}). @@ -284,7 +284,7 @@ We will not go into much detail about these forms. The important thing to know i The `CredentialForm` class, for example, defines the fields of the login form that users interface with to send a login request to the server: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START CredentialForm ||# END CredentialForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__credentialform.py %} ~~~ Most of the forms defined on this page take the inputs for database reads and writes. @@ -292,7 +292,7 @@ Most of the forms defined on this page take the inputs for database reads and wr `VehicleForm`, for example, defines the fields of the vehicle registration form. Users enter information about a vehicle they would like to register, and the data is routed to the `add_vehicle()` method defined in [`movr/movr.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/movr.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START VehicleForm ||# END VehicleForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__vehicleform.py %} ~~~ ### Initialization @@ -302,7 +302,7 @@ Most of the forms defined on this page take the inputs for database reads and wr Let's look at the first ten lines of `server.py`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__front.py %} ~~~ The first line imports standard Flask libraries for connecting, routing, and rendering web pages. The next three lines import some libraries from the Flask ecosystem, for [bootstrapping](https://pythonhosted.org/Flask-Bootstrap/), [authentication](https://flask-login.readthedocs.io/), and [security](https://github.com/pallets/werkzeug/blob/master/src/werkzeug/security.py). @@ -318,7 +318,7 @@ Finally, we import the `DBAPIError` type from `sqlalchemy`, for error handling. The next five or so lines initialize the application: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START init ||# END init %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__init.py %} ~~~ Calling the `Flask()` constructor initializes our Flask web server. By assigning this to a variable (`app`), we can then configure the application, store variables in its attributes, and call it with functions from other libraries, to add features and functionality to the application. @@ -330,7 +330,7 @@ Note that we also define a `protocol` variable that the application later uses t After initializing the application, we can connect to the database: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START connect ||# END connect %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__connect.py %} ~~~ These two lines connect the application to the database. First the application retrieves the connection string that is stored as a configuration variable of the `app`. Then it calls the `MovR()` constructor to establish a connection to the database at the location we provided to the `Config` object. @@ -342,7 +342,7 @@ User authentication is handled with the [`Flask-Login`](https://flask-login.read To control whether certain routes are accessible to a client session, we define a [`user_loader()` function](https://flask-login.readthedocs.io/#flask_login.LoginManager.user_loader): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START user_loader ||# END user_loader %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__user-loader.py %} ~~~ To restrict access to a certain page to users that are logged in with the [`LoginManager`](https://flask-login.readthedocs.io/#flask_login.LoginManager), we add the `@login_required` decorator function to the route. We'll go over some examples in the [Routing](#routing) section below. @@ -364,7 +364,7 @@ In addition to calling these functions, and some other standard Flask and Python For example, look at the `login()` route: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START login_page ||# END login_page %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__login-page.py %} ~~~ ### Client Location diff --git a/src/current/v25.2/movr-flask-database.md b/src/current/v25.2/movr-flask-database.md index 4bb882c2135..e7075ae53ae 100644 --- a/src/current/v25.2/movr-flask-database.md +++ b/src/current/v25.2/movr-flask-database.md @@ -48,7 +48,7 @@ Here is the [`CREATE DATABASE`]({% link {{ page.version.version }}/create-databa {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START database ||-- END database %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__database.sql %} ~~~ In this example, `movr` has the following [database regions]({% link {{ page.version.version }}/multiregion-overview.md %}#database-regions), which correspond to regions in Google Cloud: @@ -77,14 +77,14 @@ Here is the `CREATE TABLE` statement for the `users` table: {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START users ||-- END users %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__users.sql %} ~~~ ## The `vehicles` table {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START vehicles ||-- END vehicles %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__vehicles.sql %} ~~~ The `vehicles` table has a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) on the `users` table, for the `city` and `owner_id` columns. This guarantees that a vehicle is registered to a particular user (i.e., an "owner") in the city where that user is registered. @@ -93,7 +93,7 @@ The `vehicles` table has a [foreign key constraint]({% link {{ page.version.vers {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START rides ||-- END rides %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__rides.sql %} ~~~ Like the `vehicles` table, the `rides` table has foreign key constraints. These constraints are on the `users` and the `vehicles` tables. diff --git a/src/current/v25.3/build-a-csharp-app-with-cockroachdb.md b/src/current/v25.3/build-a-csharp-app-with-cockroachdb.md index 115abf8febd..6e71dfb298f 100644 --- a/src/current/v25.3/build-a-csharp-app-with-cockroachdb.md +++ b/src/current/v25.3/build-a-csharp-app-with-cockroachdb.md @@ -69,7 +69,7 @@ Replace the contents of the `Program.cs` file that was automatically generated i {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/basic.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/basic.cs %} ~~~ #### Run the basic example @@ -99,7 +99,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs %} ~~~
@@ -108,7 +108,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} ~~~ diff --git a/src/current/v25.3/build-a-go-app-with-cockroachdb-gorm.md b/src/current/v25.3/build-a-go-app-with-cockroachdb-gorm.md index 23ee58cd997..aac3820127f 100644 --- a/src/current/v25.3/build-a-go-app-with-cockroachdb-gorm.md +++ b/src/current/v25.3/build-a-go-app-with-cockroachdb-gorm.md @@ -39,7 +39,7 @@ The `main.go` file defines an `Account` struct that maps to a new `accounts` tab {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-gorm/master/main.go %} +{% include example-apps/cockroachlabs/example-app-go-gorm/master/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v25.3/build-a-go-app-with-cockroachdb.md b/src/current/v25.3/build-a-go-app-with-cockroachdb.md index 8a00ed10cb4..89ef7c4669e 100644 --- a/src/current/v25.3/build-a-go-app-with-cockroachdb.md +++ b/src/current/v25.3/build-a-go-app-with-cockroachdb.md @@ -35,7 +35,7 @@ The `main.go` file contains the code for `CREATE TABLE`, `INSERT`, `SELECT`, `UP {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-pgx/main/main.go %} +{% include example-apps/cockroachlabs/example-app-go-pgx/main/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v25.3/build-a-java-app-with-cockroachdb-hibernate.md b/src/current/v25.3/build-a-java-app-with-cockroachdb-hibernate.md index c4b53d27629..e266f78bff0 100644 --- a/src/current/v25.3/build-a-java-app-with-cockroachdb-hibernate.md +++ b/src/current/v25.3/build-a-java-app-with-cockroachdb-hibernate.md @@ -54,7 +54,7 @@ The contents of `Sample.java`: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} +{% include example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} ~~~
diff --git a/src/current/v25.3/build-a-java-app-with-cockroachdb.md b/src/current/v25.3/build-a-java-app-with-cockroachdb.md index d798e9dbaee..65b936c0feb 100644 --- a/src/current/v25.3/build-a-java-app-with-cockroachdb.md +++ b/src/current/v25.3/build-a-java-app-with-cockroachdb.md @@ -55,7 +55,7 @@ The `BasicExample.java` file contains the code for `INSERT`, `SELECT`, and `UPDA {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} +{% include example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} ~~~ The sample app uses JDBC and the [Data Access Object (DAO)](https://wikipedia.org/wiki/Data_access_object) pattern to map Java methods to SQL operations. It consists of two classes: diff --git a/src/current/v25.3/build-a-nodejs-app-with-cockroachdb-prisma.md b/src/current/v25.3/build-a-nodejs-app-with-cockroachdb-prisma.md index afda47789ec..6e16095554d 100644 --- a/src/current/v25.3/build-a-nodejs-app-with-cockroachdb-prisma.md +++ b/src/current/v25.3/build-a-nodejs-app-with-cockroachdb-prisma.md @@ -89,7 +89,7 @@ The `index.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DEL {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-prisma/main/index.js %} +{% include example-apps/cockroachlabs/example-app-node-prisma/main/index.js %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v25.3/build-a-nodejs-app-with-cockroachdb.md b/src/current/v25.3/build-a-nodejs-app-with-cockroachdb.md index dba17b3fb8f..d00b2bfa180 100644 --- a/src/current/v25.3/build-a-nodejs-app-with-cockroachdb.md +++ b/src/current/v25.3/build-a-nodejs-app-with-cockroachdb.md @@ -39,14 +39,14 @@ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ sql -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} ~~~ The `app.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DELETE` SQL operations: {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/app.js %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/app.js %} ~~~ All of the database operations are wrapped in a helper function named `retryTxn`. This function attempts to commit statements in the context of an explicit transaction. If a [retry error]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) is thrown, the wrapper will retry committing the transaction, with [exponential backoff](https://wikipedia.org/wiki/Exponential_backoff), until the maximum number of retries is reached (by default, 15). diff --git a/src/current/v25.3/build-a-python-app-with-cockroachdb-django.md b/src/current/v25.3/build-a-python-app-with-cockroachdb-django.md index 85644de65ed..e3a8eef46cd 100644 --- a/src/current/v25.3/build-a-python-app-with-cockroachdb-django.md +++ b/src/current/v25.3/build-a-python-app-with-cockroachdb-django.md @@ -67,7 +67,7 @@ The `requirements.txt` file at the top level of the `example-app-python-django` {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-django/master/requirements.txt %} ~~~ This tutorial uses [`virtualenv`](https://virtualenv.pypa.io) for dependency management. @@ -135,7 +135,7 @@ Start by building some [models](https://docs.djangoproject.com/en/3.1/topics/db/ {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} ~~~ In this file, we define some simple classes that map to the tables in the cluster. @@ -146,7 +146,7 @@ Next, build out some [class-based views](https://docs.djangoproject.com/en/3.1/t {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} ~~~ This file defines the application's views as classes. Each view class corresponds to one of the table classes defined in `models.py`. The methods of these classes define read and write transactions on the tables in the database. @@ -159,7 +159,7 @@ Lastly, define some [URL routes](https://docs.djangoproject.com/en/3.1/topics/ht {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} ~~~ ## Step 5. Initialize the database diff --git a/src/current/v25.3/build-a-python-app-with-cockroachdb-sqlalchemy.md b/src/current/v25.3/build-a-python-app-with-cockroachdb-sqlalchemy.md index e56b9c136a8..70e205bbdad 100644 --- a/src/current/v25.3/build-a-python-app-with-cockroachdb-sqlalchemy.md +++ b/src/current/v25.3/build-a-python-app-with-cockroachdb-sqlalchemy.md @@ -40,28 +40,28 @@ The `requirements.txt` file includes the required libraries to connect to Cockro {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} ~~~ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} ~~~ The `models.py` uses SQLAlchemy to map the `Accounts` table to a Python object: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} ~~~ The `main.py` uses SQLAlchemy to map Python methods to SQL operations: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} ~~~ `main.py` also executes the `main` method of the program. diff --git a/src/current/v25.3/build-a-rust-app-with-cockroachdb.md b/src/current/v25.3/build-a-rust-app-with-cockroachdb.md index 4ca08938824..46b9cdea10c 100644 --- a/src/current/v25.3/build-a-rust-app-with-cockroachdb.md +++ b/src/current/v25.3/build-a-rust-app-with-cockroachdb.md @@ -39,7 +39,7 @@ The `Cargo.toml` file is the configuration file for the example, and sets the de {% include_cached copy-clipboard.html %} ~~~ toml -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} ~~~ The `main` function is the entry point for the application, with the code for connecting to the cluster, creating the `accounts` table, creating accounts in that table, and transferring money between two accounts. @@ -52,14 +52,14 @@ CockroachDB may require the [client to retry a transaction]({% link {{ page.vers {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN execute_txn || END execute_txn %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs %} ~~~ The `transfer_funds` function calls `execute_txn` to perform the actual transfer of funds from one account to the other. {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN transfer_funds || END transfer_funds %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs %} ~~~ ## Step 3. Run the code diff --git a/src/current/v25.3/build-a-spring-app-with-cockroachdb-jdbc.md b/src/current/v25.3/build-a-spring-app-with-cockroachdb-jdbc.md index c6046d645dd..71dbf62fc7b 100644 --- a/src/current/v25.3/build-a-spring-app-with-cockroachdb-jdbc.md +++ b/src/current/v25.3/build-a-spring-app-with-cockroachdb-jdbc.md @@ -606,7 +606,7 @@ Here are the contents of [`JdbcApplication.java`](https://github.com/cockroachla {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} ~~~ The annotations listed at the top of the `JdbcApplication` class definition declare some important configuration properties for the entire application: @@ -631,14 +631,14 @@ Liquibase uses [changelog files](https://docs.liquibase.com/concepts/basic/chang {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -696,7 +696,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} ~~~ ### Hypermedia representation @@ -707,7 +707,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -720,7 +720,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for generic [CRUD operations](https://wikipedia.org/wiki/Create,_read,_update_and_delete) called `CrudRepository`. To support [pagination queries]({% link {{ page.version.version }}/pagination.md %}), repositories in other Spring Data modules, like those in Spring Data JPA, usually extend a subinterface of `CrudRepository`, called `PagingAndSortingRepository`, that includes pagination and sorting methods. At the time this sample application was created, Spring Data JDBC did not support pagination. As a result, `AccountRepository` extends a custom repository, called `PagedAccountRepository`, to provide basic [`LIMIT`/`OFFSET` pagination]({% link {{ page.version.version }}/pagination.md %}) on queries against the `accounts` table. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/#jdbc.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -737,7 +737,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -773,7 +773,7 @@ The `TransactionHintsAspect` class, declared as an aspect with the [`@Aspect` an {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. @@ -790,7 +790,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` pointcut definition is identical to the one declared in `TransactionHintsAspect`. The `execution` designator matches all methods in the `io.roach.` namespace, and the `@annotation` designator limits the matches to methods with the `@Transactional` annotation. diff --git a/src/current/v25.3/build-a-spring-app-with-cockroachdb-jpa.md b/src/current/v25.3/build-a-spring-app-with-cockroachdb-jpa.md index d9e1c60c6dd..b45b8e6f1f4 100644 --- a/src/current/v25.3/build-a-spring-app-with-cockroachdb-jpa.md +++ b/src/current/v25.3/build-a-spring-app-with-cockroachdb-jpa.md @@ -517,7 +517,7 @@ Here are the contents of [`JpaApplication.java`](https://github.com/cockroachlab {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} ~~~ The annotations listed at the top of the `JpaApplication` class definition declare some important configuration properties for the entire application: @@ -540,14 +540,14 @@ Liquibase uses files called [changelogs](https://docs.liquibase.com/concepts/bas {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -596,7 +596,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} ~~~ Spring Data JPA supports standard Java Persistence API (JPA) annotations for domain entity class definitions. The `Account` class definition uses these annotations to create the `accounts` table entity: @@ -616,7 +616,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -629,7 +629,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for JPA data access called `JpaRepository`. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -646,7 +646,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -677,7 +677,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. diff --git a/src/current/v25.3/movr-flask-application.md b/src/current/v25.3/movr-flask-application.md index 68b2a10b900..558f365637b 100644 --- a/src/current/v25.3/movr-flask-application.md +++ b/src/current/v25.3/movr-flask-application.md @@ -87,7 +87,7 @@ After completing the [Create a Multi-Region Database Schema]({% link {{ page.ver Open [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), and look at the first 10 lines of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__front.py %} ~~~ The first data structure that the file imports is `declarative_base`, a constructor for the [declarative base class](https://docs.sqlalchemy.org/orm/extensions/declarative/api.html#sqlalchemy.ext.declarative.declarative_base), built on SQLAlchemy's Declarative extension. All mapped objects inherit from this object. We assign a declarative base object to the `Base` variable right below the imports. @@ -103,7 +103,7 @@ Recall that each instance of a table class represents a row in the table, so we Take a look at the `User` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START User ||# END User %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__user.py %} ~~~ The `User` class has the following attributes: @@ -118,7 +118,7 @@ The `User` class has the following attributes: Next, look at the `Vehicle` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Vehicle ||# END Vehicle %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__vehicle.py %} ~~~ Recall that the `vehicles` table contains more columns and data types than the `users` table. It also contains a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) (on the `users` table), and a default value. These differences are reflected in the `Vehicle` class. @@ -128,7 +128,7 @@ Recall that the `vehicles` table contains more columns and data types than the ` Take a look at the `Ride` class: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Ride ||# END Ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__ride.py %} ~~~ The `rides` table has three foreign key constraints, one on the `users` table and two on the `vehicles` table. @@ -186,7 +186,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` `transactions.py` imports all of the table classes that we defined in [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), in addition to some standard Python data structures needed to generate correctly-typed row values that the ORM can write to the database. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__front.py %} ~~~ ##### Reading @@ -194,7 +194,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` A common query that a client might want to run is a read of the `rides` table. The transaction callback function for this query is defined here as `get_rides_txn()`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_rides_txn ||# END get_rides_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-rides-txn.py %} ~~~ The `get_rides_txn()` function takes a `Session` object and a `rider_id` string as its inputs, and it outputs a list of dictionaries containing the columns-value pairs of a row in the `rides` table. To retrieve the data from the database bound to a particular `Session` object, we use `Session.query()`, a method of the `Session` class. This method returns a `Query` object, with methods for filtering and ordering query results. @@ -204,7 +204,7 @@ Note that `get_rides_txn()` gets all rides for a specific rider, which might be Another common query would be to read the registered vehicles in a particular city, to see which vehicles are available for riding. Unlike `get_rides_txn()`, the `get_vehicles_txn()` function takes the `city` string as an input. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_vehicles_txn ||# END get_vehicles_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-vehicles-txn.py %} ~~~ This function filters the query on the `city` column. `vehicle` rows with the same value for `city` are inserted from the same region, making `city` values implicitly correspond to a specific region. Because the `vehicles` table has a `REGIONAL BY ROW` locality, CockroachDB can locality-optimize queries from nodes with a locality matching the [hidden `crdb_region` column]({% link {{ page.version.version }}/movr-flask-database.md %}#table-locality). This limits latency, as the query only needs to travel to database deployments in a single region. @@ -216,7 +216,7 @@ There are two basic types of write operations: creating new rows and updating ex For example, `start_ride_txn()`, which is called when a user starts a ride, adds a new row to the `rides` table, and then updates a row in the `vehicles` table. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START start_ride_txn ||# END start_ride_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__start-ride-txn.py %} ~~~ The function takes the `city` string, `rider_id` UUID, `rider_city` string, and `vehicle_id` UUID as inputs. It queries the `vehicles` table for all vehicles of a specific ID. It also creates a `Ride` object, representing a row of the `rides` table. To add the ride to the table in the database bound to the `Session`, the function calls `Session.add()`. To update a row in the `vehicles` table, it modifies the object attribute. `start_ride_txn()` is called by `run_transaction()`, which commits the transaction to the database. @@ -232,7 +232,7 @@ The `MovR` class, defined in [`movr/movr.py`](https://github.com/cockroachlabs/m Let's start with the beginning of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__front.py %} ~~~ `movr.py` first imports the transaction callback functions that we defined in [`movr/transactions.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/transactions.py). It then imports the `run_transaction()` function. The `MovR` class methods call `run_transaction()` to execute the transaction callback functions as transactions. @@ -250,7 +250,7 @@ We've already defined the transaction logic in the transaction callback function For example, look at the `start_ride()` method, the method to which frontend requests to start a ride are routed: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START start_ride ||# END start_ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__start-ride.py %} ~~~ This method takes some keyword arguments, and then returns a `run_transaction()` call. It passes `sessionmaker(bind=self.engine)` as the first argument to `run_transaction()`, which creates a new `Session` object that binds to the `Engine` instance initialized by the `MovR` constructor. It also passes `city`, `rider_id`, `rider_city`, and `vehicle_id`, values passed from the frontend request, as inputs. These are the same keyword arguments, and should be of the same types, as the inputs for the [transaction callback function](#writing) `start_ride_txn()`. @@ -268,7 +268,7 @@ Most of the web application components are found in the `web` and `templates` fo We store the Flask configuration settings in [a `Config` class](https://flask.palletsprojects.com/config/#development-production), defined in [`web/config.py`](https://github.com/cockroachlabs/movr-flask/blob/master/web/config.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} ~~~ This file imports the `os` library, which is used to read from environment variables. When debugging a local deployment, these environment variables are set by the `.env` file that `Pipenv` reads. In a multi-region deployment, the environment variables are set by the `Dockerfile`, and by the [managed cloud deployment service]({% link {{ page.version.version }}/movr-flask-deployment.md %}). @@ -284,7 +284,7 @@ We will not go into much detail about these forms. The important thing to know i The `CredentialForm` class, for example, defines the fields of the login form that users interface with to send a login request to the server: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START CredentialForm ||# END CredentialForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__credentialform.py %} ~~~ Most of the forms defined on this page take the inputs for database reads and writes. @@ -292,7 +292,7 @@ Most of the forms defined on this page take the inputs for database reads and wr `VehicleForm`, for example, defines the fields of the vehicle registration form. Users enter information about a vehicle they would like to register, and the data is routed to the `add_vehicle()` method defined in [`movr/movr.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/movr.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START VehicleForm ||# END VehicleForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__vehicleform.py %} ~~~ ### Initialization @@ -302,7 +302,7 @@ Most of the forms defined on this page take the inputs for database reads and wr Let's look at the first ten lines of `server.py`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__front.py %} ~~~ The first line imports standard Flask libraries for connecting, routing, and rendering web pages. The next three lines import some libraries from the Flask ecosystem, for [bootstrapping](https://pythonhosted.org/Flask-Bootstrap/), [authentication](https://flask-login.readthedocs.io/), and [security](https://github.com/pallets/werkzeug/blob/master/src/werkzeug/security.py). @@ -318,7 +318,7 @@ Finally, we import the `DBAPIError` type from `sqlalchemy`, for error handling. The next five or so lines initialize the application: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START init ||# END init %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__init.py %} ~~~ Calling the `Flask()` constructor initializes our Flask web server. By assigning this to a variable (`app`), we can then configure the application, store variables in its attributes, and call it with functions from other libraries, to add features and functionality to the application. @@ -330,7 +330,7 @@ Note that we also define a `protocol` variable that the application later uses t After initializing the application, we can connect to the database: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START connect ||# END connect %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__connect.py %} ~~~ These two lines connect the application to the database. First the application retrieves the connection string that is stored as a configuration variable of the `app`. Then it calls the `MovR()` constructor to establish a connection to the database at the location we provided to the `Config` object. @@ -342,7 +342,7 @@ User authentication is handled with the [`Flask-Login`](https://flask-login.read To control whether certain routes are accessible to a client session, we define a [`user_loader()` function](https://flask-login.readthedocs.io/#flask_login.LoginManager.user_loader): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START user_loader ||# END user_loader %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__user-loader.py %} ~~~ To restrict access to a certain page to users that are logged in with the [`LoginManager`](https://flask-login.readthedocs.io/#flask_login.LoginManager), we add the `@login_required` decorator function to the route. We'll go over some examples in the [Routing](#routing) section below. @@ -364,7 +364,7 @@ In addition to calling these functions, and some other standard Flask and Python For example, look at the `login()` route: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START login_page ||# END login_page %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__login-page.py %} ~~~ ### Client Location diff --git a/src/current/v25.3/movr-flask-database.md b/src/current/v25.3/movr-flask-database.md index 4bb882c2135..e7075ae53ae 100644 --- a/src/current/v25.3/movr-flask-database.md +++ b/src/current/v25.3/movr-flask-database.md @@ -48,7 +48,7 @@ Here is the [`CREATE DATABASE`]({% link {{ page.version.version }}/create-databa {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START database ||-- END database %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__database.sql %} ~~~ In this example, `movr` has the following [database regions]({% link {{ page.version.version }}/multiregion-overview.md %}#database-regions), which correspond to regions in Google Cloud: @@ -77,14 +77,14 @@ Here is the `CREATE TABLE` statement for the `users` table: {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START users ||-- END users %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__users.sql %} ~~~ ## The `vehicles` table {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START vehicles ||-- END vehicles %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__vehicles.sql %} ~~~ The `vehicles` table has a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) on the `users` table, for the `city` and `owner_id` columns. This guarantees that a vehicle is registered to a particular user (i.e., an "owner") in the city where that user is registered. @@ -93,7 +93,7 @@ The `vehicles` table has a [foreign key constraint]({% link {{ page.version.vers {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START rides ||-- END rides %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__rides.sql %} ~~~ Like the `vehicles` table, the `rides` table has foreign key constraints. These constraints are on the `users` and the `vehicles` tables. diff --git a/src/current/v25.4/build-a-csharp-app-with-cockroachdb.md b/src/current/v25.4/build-a-csharp-app-with-cockroachdb.md index 115abf8febd..6e71dfb298f 100644 --- a/src/current/v25.4/build-a-csharp-app-with-cockroachdb.md +++ b/src/current/v25.4/build-a-csharp-app-with-cockroachdb.md @@ -69,7 +69,7 @@ Replace the contents of the `Program.cs` file that was automatically generated i {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/basic.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/basic.cs %} ~~~ #### Run the basic example @@ -99,7 +99,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs %} ~~~
@@ -108,7 +108,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} ~~~ diff --git a/src/current/v25.4/build-a-go-app-with-cockroachdb-gorm.md b/src/current/v25.4/build-a-go-app-with-cockroachdb-gorm.md index 23ee58cd997..aac3820127f 100644 --- a/src/current/v25.4/build-a-go-app-with-cockroachdb-gorm.md +++ b/src/current/v25.4/build-a-go-app-with-cockroachdb-gorm.md @@ -39,7 +39,7 @@ The `main.go` file defines an `Account` struct that maps to a new `accounts` tab {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-gorm/master/main.go %} +{% include example-apps/cockroachlabs/example-app-go-gorm/master/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v25.4/build-a-go-app-with-cockroachdb.md b/src/current/v25.4/build-a-go-app-with-cockroachdb.md index 8a00ed10cb4..89ef7c4669e 100644 --- a/src/current/v25.4/build-a-go-app-with-cockroachdb.md +++ b/src/current/v25.4/build-a-go-app-with-cockroachdb.md @@ -35,7 +35,7 @@ The `main.go` file contains the code for `CREATE TABLE`, `INSERT`, `SELECT`, `UP {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-pgx/main/main.go %} +{% include example-apps/cockroachlabs/example-app-go-pgx/main/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v25.4/build-a-java-app-with-cockroachdb-hibernate.md b/src/current/v25.4/build-a-java-app-with-cockroachdb-hibernate.md index c4b53d27629..e266f78bff0 100644 --- a/src/current/v25.4/build-a-java-app-with-cockroachdb-hibernate.md +++ b/src/current/v25.4/build-a-java-app-with-cockroachdb-hibernate.md @@ -54,7 +54,7 @@ The contents of `Sample.java`: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} +{% include example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} ~~~
diff --git a/src/current/v25.4/build-a-java-app-with-cockroachdb.md b/src/current/v25.4/build-a-java-app-with-cockroachdb.md index d798e9dbaee..65b936c0feb 100644 --- a/src/current/v25.4/build-a-java-app-with-cockroachdb.md +++ b/src/current/v25.4/build-a-java-app-with-cockroachdb.md @@ -55,7 +55,7 @@ The `BasicExample.java` file contains the code for `INSERT`, `SELECT`, and `UPDA {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} +{% include example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} ~~~ The sample app uses JDBC and the [Data Access Object (DAO)](https://wikipedia.org/wiki/Data_access_object) pattern to map Java methods to SQL operations. It consists of two classes: diff --git a/src/current/v25.4/build-a-nodejs-app-with-cockroachdb-prisma.md b/src/current/v25.4/build-a-nodejs-app-with-cockroachdb-prisma.md index afda47789ec..6e16095554d 100644 --- a/src/current/v25.4/build-a-nodejs-app-with-cockroachdb-prisma.md +++ b/src/current/v25.4/build-a-nodejs-app-with-cockroachdb-prisma.md @@ -89,7 +89,7 @@ The `index.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DEL {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-prisma/main/index.js %} +{% include example-apps/cockroachlabs/example-app-node-prisma/main/index.js %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v25.4/build-a-nodejs-app-with-cockroachdb.md b/src/current/v25.4/build-a-nodejs-app-with-cockroachdb.md index dba17b3fb8f..d00b2bfa180 100644 --- a/src/current/v25.4/build-a-nodejs-app-with-cockroachdb.md +++ b/src/current/v25.4/build-a-nodejs-app-with-cockroachdb.md @@ -39,14 +39,14 @@ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ sql -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} ~~~ The `app.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DELETE` SQL operations: {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/app.js %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/app.js %} ~~~ All of the database operations are wrapped in a helper function named `retryTxn`. This function attempts to commit statements in the context of an explicit transaction. If a [retry error]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) is thrown, the wrapper will retry committing the transaction, with [exponential backoff](https://wikipedia.org/wiki/Exponential_backoff), until the maximum number of retries is reached (by default, 15). diff --git a/src/current/v25.4/build-a-python-app-with-cockroachdb-django.md b/src/current/v25.4/build-a-python-app-with-cockroachdb-django.md index 85644de65ed..e3a8eef46cd 100644 --- a/src/current/v25.4/build-a-python-app-with-cockroachdb-django.md +++ b/src/current/v25.4/build-a-python-app-with-cockroachdb-django.md @@ -67,7 +67,7 @@ The `requirements.txt` file at the top level of the `example-app-python-django` {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-django/master/requirements.txt %} ~~~ This tutorial uses [`virtualenv`](https://virtualenv.pypa.io) for dependency management. @@ -135,7 +135,7 @@ Start by building some [models](https://docs.djangoproject.com/en/3.1/topics/db/ {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} ~~~ In this file, we define some simple classes that map to the tables in the cluster. @@ -146,7 +146,7 @@ Next, build out some [class-based views](https://docs.djangoproject.com/en/3.1/t {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} ~~~ This file defines the application's views as classes. Each view class corresponds to one of the table classes defined in `models.py`. The methods of these classes define read and write transactions on the tables in the database. @@ -159,7 +159,7 @@ Lastly, define some [URL routes](https://docs.djangoproject.com/en/3.1/topics/ht {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} ~~~ ## Step 5. Initialize the database diff --git a/src/current/v25.4/build-a-python-app-with-cockroachdb-sqlalchemy.md b/src/current/v25.4/build-a-python-app-with-cockroachdb-sqlalchemy.md index e56b9c136a8..70e205bbdad 100644 --- a/src/current/v25.4/build-a-python-app-with-cockroachdb-sqlalchemy.md +++ b/src/current/v25.4/build-a-python-app-with-cockroachdb-sqlalchemy.md @@ -40,28 +40,28 @@ The `requirements.txt` file includes the required libraries to connect to Cockro {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} ~~~ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} ~~~ The `models.py` uses SQLAlchemy to map the `Accounts` table to a Python object: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} ~~~ The `main.py` uses SQLAlchemy to map Python methods to SQL operations: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} ~~~ `main.py` also executes the `main` method of the program. diff --git a/src/current/v25.4/build-a-rust-app-with-cockroachdb.md b/src/current/v25.4/build-a-rust-app-with-cockroachdb.md index 4ca08938824..46b9cdea10c 100644 --- a/src/current/v25.4/build-a-rust-app-with-cockroachdb.md +++ b/src/current/v25.4/build-a-rust-app-with-cockroachdb.md @@ -39,7 +39,7 @@ The `Cargo.toml` file is the configuration file for the example, and sets the de {% include_cached copy-clipboard.html %} ~~~ toml -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} ~~~ The `main` function is the entry point for the application, with the code for connecting to the cluster, creating the `accounts` table, creating accounts in that table, and transferring money between two accounts. @@ -52,14 +52,14 @@ CockroachDB may require the [client to retry a transaction]({% link {{ page.vers {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN execute_txn || END execute_txn %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs %} ~~~ The `transfer_funds` function calls `execute_txn` to perform the actual transfer of funds from one account to the other. {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN transfer_funds || END transfer_funds %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs %} ~~~ ## Step 3. Run the code diff --git a/src/current/v25.4/build-a-spring-app-with-cockroachdb-jdbc.md b/src/current/v25.4/build-a-spring-app-with-cockroachdb-jdbc.md index c6046d645dd..71dbf62fc7b 100644 --- a/src/current/v25.4/build-a-spring-app-with-cockroachdb-jdbc.md +++ b/src/current/v25.4/build-a-spring-app-with-cockroachdb-jdbc.md @@ -606,7 +606,7 @@ Here are the contents of [`JdbcApplication.java`](https://github.com/cockroachla {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/JdbcApplication.java %} ~~~ The annotations listed at the top of the `JdbcApplication` class definition declare some important configuration properties for the entire application: @@ -631,14 +631,14 @@ Liquibase uses [changelog files](https://docs.liquibase.com/concepts/basic/chang {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -696,7 +696,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/Account.java %} ~~~ ### Hypermedia representation @@ -707,7 +707,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -720,7 +720,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for generic [CRUD operations](https://wikipedia.org/wiki/Create,_read,_update_and_delete) called `CrudRepository`. To support [pagination queries]({% link {{ page.version.version }}/pagination.md %}), repositories in other Spring Data modules, like those in Spring Data JPA, usually extend a subinterface of `CrudRepository`, called `PagingAndSortingRepository`, that includes pagination and sorting methods. At the time this sample application was created, Spring Data JDBC did not support pagination. As a result, `AccountRepository` extends a custom repository, called `PagedAccountRepository`, to provide basic [`LIMIT`/`OFFSET` pagination]({% link {{ page.version.version }}/pagination.md %}) on queries against the `accounts` table. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/#jdbc.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -737,7 +737,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -773,7 +773,7 @@ The `TransactionHintsAspect` class, declared as an aspect with the [`@Aspect` an {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/TransactionHintsAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. @@ -790,7 +790,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jdbc/src/main/java/io/roach/data/jdbc/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` pointcut definition is identical to the one declared in `TransactionHintsAspect`. The `execution` designator matches all methods in the `io.roach.` namespace, and the `@annotation` designator limits the matches to methods with the `@Transactional` annotation. diff --git a/src/current/v25.4/build-a-spring-app-with-cockroachdb-jpa.md b/src/current/v25.4/build-a-spring-app-with-cockroachdb-jpa.md index d9e1c60c6dd..b45b8e6f1f4 100644 --- a/src/current/v25.4/build-a-spring-app-with-cockroachdb-jpa.md +++ b/src/current/v25.4/build-a-spring-app-with-cockroachdb-jpa.md @@ -517,7 +517,7 @@ Here are the contents of [`JpaApplication.java`](https://github.com/cockroachlab {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/JpaApplication.java %} ~~~ The annotations listed at the top of the `JpaApplication` class definition declare some important configuration properties for the entire application: @@ -540,14 +540,14 @@ Liquibase uses files called [changelogs](https://docs.liquibase.com/concepts/bas {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/changelog-master.xml %} ~~~ The first changeset uses [the `sqlFile` tag](https://docs.liquibase.com/change-types/community/sql-file.html), which tells Liquibase that an external `.sql` file contains some SQL statements to execute. The file specified by the changeset, `resources/db/create.sql`, creates the `account` table: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/resources/db/create.sql %} ~~~ The second changeset in the changelog uses the [Liquibase XML syntax](https://docs.liquibase.com/concepts/basic/xml-format.html) to specify a series of sequential `INSERT` statements that initialize the `account` table with some values. @@ -596,7 +596,7 @@ Here are the contents of [`Account.java`](https://github.com/cockroachlabs/roach {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/Account.java %} ~~~ Spring Data JPA supports standard Java Persistence API (JPA) annotations for domain entity class definitions. The `Account` class definition uses these annotations to create the `accounts` table entity: @@ -616,7 +616,7 @@ The contents of [`AccountModel.java`](https://github.com/cockroachlabs/roach-dat {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountModel.java %} ~~~ We do not go into much detail about hypermedia representation in this tutorial. For more information, see the [Spring HATEOAS Reference Documentation](https://docs.spring.io/spring-hateoas/docs/current/reference/html/). @@ -629,7 +629,7 @@ To abstract the database layer, Spring applications use the [`Repository` interf {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountRepository.java %} ~~~ `AccountRepository` extends a subinterface of `Repository` that is provided by Spring for JPA data access called `JpaRepository`. The `AccountRepository` methods use the [`@Query`](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query) annotation strategy to define queries manually, as strings. @@ -646,7 +646,7 @@ There are several endpoints exposed by the application's web layer, some of whic {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/AccountController.java %} ~~~ Annotated with [`@RestController`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html), `AccountController` defines the primary [web controller](https://wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) component of the application. The `AccountController` methods define the endpoints, routes, and business logic of REST services for account querying and money transferring. Its attributes include an instantiation of [`AccountRepository`](#spring-repositories), called `accountRepository`, that establishes an interface to the `accounts` table through the data access layer. @@ -677,7 +677,7 @@ In this application, transaction retry logic is written into the methods of the {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} +{% include example-apps/cockroachlabs/roach-data/master/roach-data-jpa/src/main/java/io/roach/data/jpa/RetryableTransactionAspect.java %} ~~~ The `anyTransactionBoundaryOperation` method is declared as a pointcut with the [`@Pointcut` annotation](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts). In Spring, pointcut declarations must include an expression to determine where [join points](https://wikipedia.org/wiki/Join_point) occur in the application control flow. To help define these expressions, Spring supports a set of [designators](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators). The application uses two of them here: `execution`, which matches method execution joint points (i.e., defines a joint point when a specific method is executed, in this case, *any* method in the `io.roach.` namespace), and `@annotation`, which limits the matches to methods with a specific annotation, in this case `@Transactional`. diff --git a/src/current/v25.4/movr-flask-application.md b/src/current/v25.4/movr-flask-application.md index 68b2a10b900..558f365637b 100644 --- a/src/current/v25.4/movr-flask-application.md +++ b/src/current/v25.4/movr-flask-application.md @@ -87,7 +87,7 @@ After completing the [Create a Multi-Region Database Schema]({% link {{ page.ver Open [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), and look at the first 10 lines of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__front.py %} ~~~ The first data structure that the file imports is `declarative_base`, a constructor for the [declarative base class](https://docs.sqlalchemy.org/orm/extensions/declarative/api.html#sqlalchemy.ext.declarative.declarative_base), built on SQLAlchemy's Declarative extension. All mapped objects inherit from this object. We assign a declarative base object to the `Base` variable right below the imports. @@ -103,7 +103,7 @@ Recall that each instance of a table class represents a row in the table, so we Take a look at the `User` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START User ||# END User %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__user.py %} ~~~ The `User` class has the following attributes: @@ -118,7 +118,7 @@ The `User` class has the following attributes: Next, look at the `Vehicle` class definition: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Vehicle ||# END Vehicle %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__vehicle.py %} ~~~ Recall that the `vehicles` table contains more columns and data types than the `users` table. It also contains a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) (on the `users` table), and a default value. These differences are reflected in the `Vehicle` class. @@ -128,7 +128,7 @@ Recall that the `vehicles` table contains more columns and data types than the ` Take a look at the `Ride` class: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/models.py ||# START Ride ||# END Ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/models__ride.py %} ~~~ The `rides` table has three foreign key constraints, one on the `users` table and two on the `vehicles` table. @@ -186,7 +186,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` `transactions.py` imports all of the table classes that we defined in [`movr/models.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/models.py), in addition to some standard Python data structures needed to generate correctly-typed row values that the ORM can write to the database. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__front.py %} ~~~ ##### Reading @@ -194,7 +194,7 @@ We recommend that you use a `sessionmaker` object, bound to an existing `Engine` A common query that a client might want to run is a read of the `rides` table. The transaction callback function for this query is defined here as `get_rides_txn()`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_rides_txn ||# END get_rides_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-rides-txn.py %} ~~~ The `get_rides_txn()` function takes a `Session` object and a `rider_id` string as its inputs, and it outputs a list of dictionaries containing the columns-value pairs of a row in the `rides` table. To retrieve the data from the database bound to a particular `Session` object, we use `Session.query()`, a method of the `Session` class. This method returns a `Query` object, with methods for filtering and ordering query results. @@ -204,7 +204,7 @@ Note that `get_rides_txn()` gets all rides for a specific rider, which might be Another common query would be to read the registered vehicles in a particular city, to see which vehicles are available for riding. Unlike `get_rides_txn()`, the `get_vehicles_txn()` function takes the `city` string as an input. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START get_vehicles_txn ||# END get_vehicles_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__get-vehicles-txn.py %} ~~~ This function filters the query on the `city` column. `vehicle` rows with the same value for `city` are inserted from the same region, making `city` values implicitly correspond to a specific region. Because the `vehicles` table has a `REGIONAL BY ROW` locality, CockroachDB can locality-optimize queries from nodes with a locality matching the [hidden `crdb_region` column]({% link {{ page.version.version }}/movr-flask-database.md %}#table-locality). This limits latency, as the query only needs to travel to database deployments in a single region. @@ -216,7 +216,7 @@ There are two basic types of write operations: creating new rows and updating ex For example, `start_ride_txn()`, which is called when a user starts a ride, adds a new row to the `rides` table, and then updates a row in the `vehicles` table. ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions.py ||# START start_ride_txn ||# END start_ride_txn %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/transactions__start-ride-txn.py %} ~~~ The function takes the `city` string, `rider_id` UUID, `rider_city` string, and `vehicle_id` UUID as inputs. It queries the `vehicles` table for all vehicles of a specific ID. It also creates a `Ride` object, representing a row of the `rides` table. To add the ride to the table in the database bound to the `Session`, the function calls `Session.add()`. To update a row in the `vehicles` table, it modifies the object attribute. `start_ride_txn()` is called by `run_transaction()`, which commits the transaction to the database. @@ -232,7 +232,7 @@ The `MovR` class, defined in [`movr/movr.py`](https://github.com/cockroachlabs/m Let's start with the beginning of the file: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__front.py %} ~~~ `movr.py` first imports the transaction callback functions that we defined in [`movr/transactions.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/transactions.py). It then imports the `run_transaction()` function. The `MovR` class methods call `run_transaction()` to execute the transaction callback functions as transactions. @@ -250,7 +250,7 @@ We've already defined the transaction logic in the transaction callback function For example, look at the `start_ride()` method, the method to which frontend requests to start a ride are routed: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/movr/movr.py ||# START start_ride ||# END start_ride %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/movr/movr__start-ride.py %} ~~~ This method takes some keyword arguments, and then returns a `run_transaction()` call. It passes `sessionmaker(bind=self.engine)` as the first argument to `run_transaction()`, which creates a new `Session` object that binds to the `Engine` instance initialized by the `MovR` constructor. It also passes `city`, `rider_id`, `rider_city`, and `vehicle_id`, values passed from the frontend request, as inputs. These are the same keyword arguments, and should be of the same types, as the inputs for the [transaction callback function](#writing) `start_ride_txn()`. @@ -268,7 +268,7 @@ Most of the web application components are found in the `web` and `templates` fo We store the Flask configuration settings in [a `Config` class](https://flask.palletsprojects.com/config/#development-production), defined in [`web/config.py`](https://github.com/cockroachlabs/movr-flask/blob/master/web/config.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/config.py %} ~~~ This file imports the `os` library, which is used to read from environment variables. When debugging a local deployment, these environment variables are set by the `.env` file that `Pipenv` reads. In a multi-region deployment, the environment variables are set by the `Dockerfile`, and by the [managed cloud deployment service]({% link {{ page.version.version }}/movr-flask-deployment.md %}). @@ -284,7 +284,7 @@ We will not go into much detail about these forms. The important thing to know i The `CredentialForm` class, for example, defines the fields of the login form that users interface with to send a login request to the server: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START CredentialForm ||# END CredentialForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__credentialform.py %} ~~~ Most of the forms defined on this page take the inputs for database reads and writes. @@ -292,7 +292,7 @@ Most of the forms defined on this page take the inputs for database reads and wr `VehicleForm`, for example, defines the fields of the vehicle registration form. Users enter information about a vehicle they would like to register, and the data is routed to the `add_vehicle()` method defined in [`movr/movr.py`](https://github.com/cockroachlabs/movr-flask/blob/master/movr/movr.py): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/web/forms.py ||# START VehicleForm ||# END VehicleForm %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/web/forms__vehicleform.py %} ~~~ ### Initialization @@ -302,7 +302,7 @@ Most of the forms defined on this page take the inputs for database reads and wr Let's look at the first ten lines of `server.py`: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START front ||# END front %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__front.py %} ~~~ The first line imports standard Flask libraries for connecting, routing, and rendering web pages. The next three lines import some libraries from the Flask ecosystem, for [bootstrapping](https://pythonhosted.org/Flask-Bootstrap/), [authentication](https://flask-login.readthedocs.io/), and [security](https://github.com/pallets/werkzeug/blob/master/src/werkzeug/security.py). @@ -318,7 +318,7 @@ Finally, we import the `DBAPIError` type from `sqlalchemy`, for error handling. The next five or so lines initialize the application: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START init ||# END init %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__init.py %} ~~~ Calling the `Flask()` constructor initializes our Flask web server. By assigning this to a variable (`app`), we can then configure the application, store variables in its attributes, and call it with functions from other libraries, to add features and functionality to the application. @@ -330,7 +330,7 @@ Note that we also define a `protocol` variable that the application later uses t After initializing the application, we can connect to the database: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START connect ||# END connect %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__connect.py %} ~~~ These two lines connect the application to the database. First the application retrieves the connection string that is stored as a configuration variable of the `app`. Then it calls the `MovR()` constructor to establish a connection to the database at the location we provided to the `Config` object. @@ -342,7 +342,7 @@ User authentication is handled with the [`Flask-Login`](https://flask-login.read To control whether certain routes are accessible to a client session, we define a [`user_loader()` function](https://flask-login.readthedocs.io/#flask_login.LoginManager.user_loader): ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START user_loader ||# END user_loader %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__user-loader.py %} ~~~ To restrict access to a certain page to users that are logged in with the [`LoginManager`](https://flask-login.readthedocs.io/#flask_login.LoginManager), we add the `@login_required` decorator function to the route. We'll go over some examples in the [Routing](#routing) section below. @@ -364,7 +364,7 @@ In addition to calling these functions, and some other standard Flask and Python For example, look at the `login()` route: ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/server.py ||# START login_page ||# END login_page %} +{% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/server__login-page.py %} ~~~ ### Client Location diff --git a/src/current/v25.4/movr-flask-database.md b/src/current/v25.4/movr-flask-database.md index 4bb882c2135..e7075ae53ae 100644 --- a/src/current/v25.4/movr-flask-database.md +++ b/src/current/v25.4/movr-flask-database.md @@ -48,7 +48,7 @@ Here is the [`CREATE DATABASE`]({% link {{ page.version.version }}/create-databa {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START database ||-- END database %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__database.sql %} ~~~ In this example, `movr` has the following [database regions]({% link {{ page.version.version }}/multiregion-overview.md %}#database-regions), which correspond to regions in Google Cloud: @@ -77,14 +77,14 @@ Here is the `CREATE TABLE` statement for the `users` table: {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START users ||-- END users %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__users.sql %} ~~~ ## The `vehicles` table {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START vehicles ||-- END vehicles %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__vehicles.sql %} ~~~ The `vehicles` table has a [foreign key constraint]({% link {{ page.version.version }}/foreign-key.md %}) on the `users` table, for the `city` and `owner_id` columns. This guarantees that a vehicle is registered to a particular user (i.e., an "owner") in the city where that user is registered. @@ -93,7 +93,7 @@ The `vehicles` table has a [foreign key constraint]({% link {{ page.version.vers {% include_cached copy-clipboard.html %} ~~~ sql -> {% remote_include https://raw.githubusercontent.com/cockroachlabs/movr-flask/v2-doc-includes/dbinit.sql ||-- START rides ||-- END rides %} +> {% include example-apps/cockroachlabs/movr-flask/v2-doc-includes/dbinit__rides.sql %} ~~~ Like the `vehicles` table, the `rides` table has foreign key constraints. These constraints are on the `users` and the `vehicles` tables. diff --git a/src/current/v26.1/build-a-csharp-app-with-cockroachdb.md b/src/current/v26.1/build-a-csharp-app-with-cockroachdb.md index 115abf8febd..6e71dfb298f 100644 --- a/src/current/v26.1/build-a-csharp-app-with-cockroachdb.md +++ b/src/current/v26.1/build-a-csharp-app-with-cockroachdb.md @@ -69,7 +69,7 @@ Replace the contents of the `Program.cs` file that was automatically generated i {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/basic.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/basic.cs %} ~~~ #### Run the basic example @@ -99,7 +99,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs %} ~~~
@@ -108,7 +108,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} ~~~ diff --git a/src/current/v26.1/build-a-go-app-with-cockroachdb-gorm.md b/src/current/v26.1/build-a-go-app-with-cockroachdb-gorm.md index 23ee58cd997..aac3820127f 100644 --- a/src/current/v26.1/build-a-go-app-with-cockroachdb-gorm.md +++ b/src/current/v26.1/build-a-go-app-with-cockroachdb-gorm.md @@ -39,7 +39,7 @@ The `main.go` file defines an `Account` struct that maps to a new `accounts` tab {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-gorm/master/main.go %} +{% include example-apps/cockroachlabs/example-app-go-gorm/master/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v26.1/build-a-go-app-with-cockroachdb.md b/src/current/v26.1/build-a-go-app-with-cockroachdb.md index 8a00ed10cb4..89ef7c4669e 100644 --- a/src/current/v26.1/build-a-go-app-with-cockroachdb.md +++ b/src/current/v26.1/build-a-go-app-with-cockroachdb.md @@ -35,7 +35,7 @@ The `main.go` file contains the code for `CREATE TABLE`, `INSERT`, `SELECT`, `UP {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-pgx/main/main.go %} +{% include example-apps/cockroachlabs/example-app-go-pgx/main/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v26.1/build-a-java-app-with-cockroachdb-hibernate.md b/src/current/v26.1/build-a-java-app-with-cockroachdb-hibernate.md index 0599b2a0163..48a66dd3bd7 100644 --- a/src/current/v26.1/build-a-java-app-with-cockroachdb-hibernate.md +++ b/src/current/v26.1/build-a-java-app-with-cockroachdb-hibernate.md @@ -50,7 +50,7 @@ The contents of `Sample.java`: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} +{% include example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} ~~~
diff --git a/src/current/v26.1/build-a-java-app-with-cockroachdb.md b/src/current/v26.1/build-a-java-app-with-cockroachdb.md index 8fa47167707..95a130a53cf 100644 --- a/src/current/v26.1/build-a-java-app-with-cockroachdb.md +++ b/src/current/v26.1/build-a-java-app-with-cockroachdb.md @@ -51,7 +51,7 @@ The `BasicExample.java` file contains the code for `INSERT`, `SELECT`, and `UPDA {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} +{% include example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} ~~~ The sample app uses JDBC and the [Data Access Object (DAO)](https://wikipedia.org/wiki/Data_access_object) pattern to map Java methods to SQL operations. It consists of two classes: diff --git a/src/current/v26.1/build-a-nodejs-app-with-cockroachdb-prisma.md b/src/current/v26.1/build-a-nodejs-app-with-cockroachdb-prisma.md index afda47789ec..6e16095554d 100644 --- a/src/current/v26.1/build-a-nodejs-app-with-cockroachdb-prisma.md +++ b/src/current/v26.1/build-a-nodejs-app-with-cockroachdb-prisma.md @@ -89,7 +89,7 @@ The `index.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DEL {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-prisma/main/index.js %} +{% include example-apps/cockroachlabs/example-app-node-prisma/main/index.js %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v26.1/build-a-nodejs-app-with-cockroachdb.md b/src/current/v26.1/build-a-nodejs-app-with-cockroachdb.md index dba17b3fb8f..d00b2bfa180 100644 --- a/src/current/v26.1/build-a-nodejs-app-with-cockroachdb.md +++ b/src/current/v26.1/build-a-nodejs-app-with-cockroachdb.md @@ -39,14 +39,14 @@ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ sql -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} ~~~ The `app.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DELETE` SQL operations: {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/app.js %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/app.js %} ~~~ All of the database operations are wrapped in a helper function named `retryTxn`. This function attempts to commit statements in the context of an explicit transaction. If a [retry error]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) is thrown, the wrapper will retry committing the transaction, with [exponential backoff](https://wikipedia.org/wiki/Exponential_backoff), until the maximum number of retries is reached (by default, 15). diff --git a/src/current/v26.1/build-a-python-app-with-cockroachdb-django.md b/src/current/v26.1/build-a-python-app-with-cockroachdb-django.md index 85644de65ed..e3a8eef46cd 100644 --- a/src/current/v26.1/build-a-python-app-with-cockroachdb-django.md +++ b/src/current/v26.1/build-a-python-app-with-cockroachdb-django.md @@ -67,7 +67,7 @@ The `requirements.txt` file at the top level of the `example-app-python-django` {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-django/master/requirements.txt %} ~~~ This tutorial uses [`virtualenv`](https://virtualenv.pypa.io) for dependency management. @@ -135,7 +135,7 @@ Start by building some [models](https://docs.djangoproject.com/en/3.1/topics/db/ {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} ~~~ In this file, we define some simple classes that map to the tables in the cluster. @@ -146,7 +146,7 @@ Next, build out some [class-based views](https://docs.djangoproject.com/en/3.1/t {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} ~~~ This file defines the application's views as classes. Each view class corresponds to one of the table classes defined in `models.py`. The methods of these classes define read and write transactions on the tables in the database. @@ -159,7 +159,7 @@ Lastly, define some [URL routes](https://docs.djangoproject.com/en/3.1/topics/ht {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} ~~~ ## Step 5. Initialize the database diff --git a/src/current/v26.1/build-a-python-app-with-cockroachdb-sqlalchemy.md b/src/current/v26.1/build-a-python-app-with-cockroachdb-sqlalchemy.md index e56b9c136a8..70e205bbdad 100644 --- a/src/current/v26.1/build-a-python-app-with-cockroachdb-sqlalchemy.md +++ b/src/current/v26.1/build-a-python-app-with-cockroachdb-sqlalchemy.md @@ -40,28 +40,28 @@ The `requirements.txt` file includes the required libraries to connect to Cockro {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} ~~~ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} ~~~ The `models.py` uses SQLAlchemy to map the `Accounts` table to a Python object: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} ~~~ The `main.py` uses SQLAlchemy to map Python methods to SQL operations: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} ~~~ `main.py` also executes the `main` method of the program. diff --git a/src/current/v26.1/build-a-rust-app-with-cockroachdb.md b/src/current/v26.1/build-a-rust-app-with-cockroachdb.md index 4ca08938824..46b9cdea10c 100644 --- a/src/current/v26.1/build-a-rust-app-with-cockroachdb.md +++ b/src/current/v26.1/build-a-rust-app-with-cockroachdb.md @@ -39,7 +39,7 @@ The `Cargo.toml` file is the configuration file for the example, and sets the de {% include_cached copy-clipboard.html %} ~~~ toml -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} ~~~ The `main` function is the entry point for the application, with the code for connecting to the cluster, creating the `accounts` table, creating accounts in that table, and transferring money between two accounts. @@ -52,14 +52,14 @@ CockroachDB may require the [client to retry a transaction]({% link {{ page.vers {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN execute_txn || END execute_txn %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs %} ~~~ The `transfer_funds` function calls `execute_txn` to perform the actual transfer of funds from one account to the other. {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN transfer_funds || END transfer_funds %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs %} ~~~ ## Step 3. Run the code diff --git a/src/current/v26.2/build-a-csharp-app-with-cockroachdb.md b/src/current/v26.2/build-a-csharp-app-with-cockroachdb.md index 115abf8febd..6e71dfb298f 100644 --- a/src/current/v26.2/build-a-csharp-app-with-cockroachdb.md +++ b/src/current/v26.2/build-a-csharp-app-with-cockroachdb.md @@ -69,7 +69,7 @@ Replace the contents of the `Program.cs` file that was automatically generated i {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/basic.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/basic.cs %} ~~~ #### Run the basic example @@ -99,7 +99,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs %} ~~~
@@ -108,7 +108,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} ~~~ diff --git a/src/current/v26.2/build-a-go-app-with-cockroachdb-gorm.md b/src/current/v26.2/build-a-go-app-with-cockroachdb-gorm.md index 23ee58cd997..aac3820127f 100644 --- a/src/current/v26.2/build-a-go-app-with-cockroachdb-gorm.md +++ b/src/current/v26.2/build-a-go-app-with-cockroachdb-gorm.md @@ -39,7 +39,7 @@ The `main.go` file defines an `Account` struct that maps to a new `accounts` tab {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-gorm/master/main.go %} +{% include example-apps/cockroachlabs/example-app-go-gorm/master/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v26.2/build-a-go-app-with-cockroachdb.md b/src/current/v26.2/build-a-go-app-with-cockroachdb.md index 8a00ed10cb4..89ef7c4669e 100644 --- a/src/current/v26.2/build-a-go-app-with-cockroachdb.md +++ b/src/current/v26.2/build-a-go-app-with-cockroachdb.md @@ -35,7 +35,7 @@ The `main.go` file contains the code for `CREATE TABLE`, `INSERT`, `SELECT`, `UP {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-pgx/main/main.go %} +{% include example-apps/cockroachlabs/example-app-go-pgx/main/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v26.2/build-a-java-app-with-cockroachdb-hibernate.md b/src/current/v26.2/build-a-java-app-with-cockroachdb-hibernate.md index 0599b2a0163..48a66dd3bd7 100644 --- a/src/current/v26.2/build-a-java-app-with-cockroachdb-hibernate.md +++ b/src/current/v26.2/build-a-java-app-with-cockroachdb-hibernate.md @@ -50,7 +50,7 @@ The contents of `Sample.java`: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} +{% include example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} ~~~
diff --git a/src/current/v26.2/build-a-java-app-with-cockroachdb.md b/src/current/v26.2/build-a-java-app-with-cockroachdb.md index 8fa47167707..95a130a53cf 100644 --- a/src/current/v26.2/build-a-java-app-with-cockroachdb.md +++ b/src/current/v26.2/build-a-java-app-with-cockroachdb.md @@ -51,7 +51,7 @@ The `BasicExample.java` file contains the code for `INSERT`, `SELECT`, and `UPDA {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} +{% include example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} ~~~ The sample app uses JDBC and the [Data Access Object (DAO)](https://wikipedia.org/wiki/Data_access_object) pattern to map Java methods to SQL operations. It consists of two classes: diff --git a/src/current/v26.2/build-a-nodejs-app-with-cockroachdb-prisma.md b/src/current/v26.2/build-a-nodejs-app-with-cockroachdb-prisma.md index afda47789ec..6e16095554d 100644 --- a/src/current/v26.2/build-a-nodejs-app-with-cockroachdb-prisma.md +++ b/src/current/v26.2/build-a-nodejs-app-with-cockroachdb-prisma.md @@ -89,7 +89,7 @@ The `index.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DEL {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-prisma/main/index.js %} +{% include example-apps/cockroachlabs/example-app-node-prisma/main/index.js %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v26.2/build-a-nodejs-app-with-cockroachdb.md b/src/current/v26.2/build-a-nodejs-app-with-cockroachdb.md index dba17b3fb8f..d00b2bfa180 100644 --- a/src/current/v26.2/build-a-nodejs-app-with-cockroachdb.md +++ b/src/current/v26.2/build-a-nodejs-app-with-cockroachdb.md @@ -39,14 +39,14 @@ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ sql -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} ~~~ The `app.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DELETE` SQL operations: {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/app.js %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/app.js %} ~~~ All of the database operations are wrapped in a helper function named `retryTxn`. This function attempts to commit statements in the context of an explicit transaction. If a [retry error]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) is thrown, the wrapper will retry committing the transaction, with [exponential backoff](https://wikipedia.org/wiki/Exponential_backoff), until the maximum number of retries is reached (by default, 15). diff --git a/src/current/v26.2/build-a-python-app-with-cockroachdb-django.md b/src/current/v26.2/build-a-python-app-with-cockroachdb-django.md index 85644de65ed..e3a8eef46cd 100644 --- a/src/current/v26.2/build-a-python-app-with-cockroachdb-django.md +++ b/src/current/v26.2/build-a-python-app-with-cockroachdb-django.md @@ -67,7 +67,7 @@ The `requirements.txt` file at the top level of the `example-app-python-django` {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-django/master/requirements.txt %} ~~~ This tutorial uses [`virtualenv`](https://virtualenv.pypa.io) for dependency management. @@ -135,7 +135,7 @@ Start by building some [models](https://docs.djangoproject.com/en/3.1/topics/db/ {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} ~~~ In this file, we define some simple classes that map to the tables in the cluster. @@ -146,7 +146,7 @@ Next, build out some [class-based views](https://docs.djangoproject.com/en/3.1/t {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} ~~~ This file defines the application's views as classes. Each view class corresponds to one of the table classes defined in `models.py`. The methods of these classes define read and write transactions on the tables in the database. @@ -159,7 +159,7 @@ Lastly, define some [URL routes](https://docs.djangoproject.com/en/3.1/topics/ht {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} ~~~ ## Step 5. Initialize the database diff --git a/src/current/v26.2/build-a-python-app-with-cockroachdb-sqlalchemy.md b/src/current/v26.2/build-a-python-app-with-cockroachdb-sqlalchemy.md index e56b9c136a8..70e205bbdad 100644 --- a/src/current/v26.2/build-a-python-app-with-cockroachdb-sqlalchemy.md +++ b/src/current/v26.2/build-a-python-app-with-cockroachdb-sqlalchemy.md @@ -40,28 +40,28 @@ The `requirements.txt` file includes the required libraries to connect to Cockro {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} ~~~ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} ~~~ The `models.py` uses SQLAlchemy to map the `Accounts` table to a Python object: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} ~~~ The `main.py` uses SQLAlchemy to map Python methods to SQL operations: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} ~~~ `main.py` also executes the `main` method of the program. diff --git a/src/current/v26.2/build-a-rust-app-with-cockroachdb.md b/src/current/v26.2/build-a-rust-app-with-cockroachdb.md index 4ca08938824..46b9cdea10c 100644 --- a/src/current/v26.2/build-a-rust-app-with-cockroachdb.md +++ b/src/current/v26.2/build-a-rust-app-with-cockroachdb.md @@ -39,7 +39,7 @@ The `Cargo.toml` file is the configuration file for the example, and sets the de {% include_cached copy-clipboard.html %} ~~~ toml -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} ~~~ The `main` function is the entry point for the application, with the code for connecting to the cluster, creating the `accounts` table, creating accounts in that table, and transferring money between two accounts. @@ -52,14 +52,14 @@ CockroachDB may require the [client to retry a transaction]({% link {{ page.vers {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN execute_txn || END execute_txn %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs %} ~~~ The `transfer_funds` function calls `execute_txn` to perform the actual transfer of funds from one account to the other. {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN transfer_funds || END transfer_funds %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs %} ~~~ ## Step 3. Run the code diff --git a/src/current/v26.3/build-a-csharp-app-with-cockroachdb.md b/src/current/v26.3/build-a-csharp-app-with-cockroachdb.md index 115abf8febd..6e71dfb298f 100644 --- a/src/current/v26.3/build-a-csharp-app-with-cockroachdb.md +++ b/src/current/v26.3/build-a-csharp-app-with-cockroachdb.md @@ -69,7 +69,7 @@ Replace the contents of the `Program.cs` file that was automatically generated i {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/basic.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/basic.cs %} ~~~ #### Run the basic example @@ -99,7 +99,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/main/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/main/transaction.cs %} ~~~
@@ -108,7 +108,7 @@ Open `cockroachdb-test-app/Program.cs` again and replace the contents with the c {% include_cached copy-clipboard.html %} ~~~ c# -{% remote_include https://raw.githubusercontent.com/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} +{% include example-apps/cockroachlabs/hello-world-csharp/cockroachcloud/transaction.cs %} ~~~ diff --git a/src/current/v26.3/build-a-go-app-with-cockroachdb-gorm.md b/src/current/v26.3/build-a-go-app-with-cockroachdb-gorm.md index 23ee58cd997..aac3820127f 100644 --- a/src/current/v26.3/build-a-go-app-with-cockroachdb-gorm.md +++ b/src/current/v26.3/build-a-go-app-with-cockroachdb-gorm.md @@ -39,7 +39,7 @@ The `main.go` file defines an `Account` struct that maps to a new `accounts` tab {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-gorm/master/main.go %} +{% include example-apps/cockroachlabs/example-app-go-gorm/master/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v26.3/build-a-go-app-with-cockroachdb.md b/src/current/v26.3/build-a-go-app-with-cockroachdb.md index 8a00ed10cb4..89ef7c4669e 100644 --- a/src/current/v26.3/build-a-go-app-with-cockroachdb.md +++ b/src/current/v26.3/build-a-go-app-with-cockroachdb.md @@ -35,7 +35,7 @@ The `main.go` file contains the code for `CREATE TABLE`, `INSERT`, `SELECT`, `UP {% include_cached copy-clipboard.html %} ~~~ go -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-go-pgx/main/main.go %} +{% include example-apps/cockroachlabs/example-app-go-pgx/main/main.go %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v26.3/build-a-java-app-with-cockroachdb-hibernate.md b/src/current/v26.3/build-a-java-app-with-cockroachdb-hibernate.md index 0599b2a0163..48a66dd3bd7 100644 --- a/src/current/v26.3/build-a-java-app-with-cockroachdb-hibernate.md +++ b/src/current/v26.3/build-a-java-app-with-cockroachdb-hibernate.md @@ -50,7 +50,7 @@ The contents of `Sample.java`: {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} +{% include example-apps/cockroachlabs/example-app-java-hibernate/master/src/main/java/com/cockroachlabs/Sample.java %} ~~~
diff --git a/src/current/v26.3/build-a-java-app-with-cockroachdb.md b/src/current/v26.3/build-a-java-app-with-cockroachdb.md index 8fa47167707..95a130a53cf 100644 --- a/src/current/v26.3/build-a-java-app-with-cockroachdb.md +++ b/src/current/v26.3/build-a-java-app-with-cockroachdb.md @@ -51,7 +51,7 @@ The `BasicExample.java` file contains the code for `INSERT`, `SELECT`, and `UPDA {% include_cached copy-clipboard.html %} ~~~ java -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} +{% include example-apps/cockroachlabs/example-app-java-jdbc/master/app/src/main/java/com/cockroachlabs/BasicExample.java %} ~~~ The sample app uses JDBC and the [Data Access Object (DAO)](https://wikipedia.org/wiki/Data_access_object) pattern to map Java methods to SQL operations. It consists of two classes: diff --git a/src/current/v26.3/build-a-nodejs-app-with-cockroachdb-prisma.md b/src/current/v26.3/build-a-nodejs-app-with-cockroachdb-prisma.md index afda47789ec..6e16095554d 100644 --- a/src/current/v26.3/build-a-nodejs-app-with-cockroachdb-prisma.md +++ b/src/current/v26.3/build-a-nodejs-app-with-cockroachdb-prisma.md @@ -89,7 +89,7 @@ The `index.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DEL {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-prisma/main/index.js %} +{% include example-apps/cockroachlabs/example-app-node-prisma/main/index.js %} ~~~ {{site.data.alerts.callout_info}} diff --git a/src/current/v26.3/build-a-nodejs-app-with-cockroachdb.md b/src/current/v26.3/build-a-nodejs-app-with-cockroachdb.md index dba17b3fb8f..d00b2bfa180 100644 --- a/src/current/v26.3/build-a-nodejs-app-with-cockroachdb.md +++ b/src/current/v26.3/build-a-nodejs-app-with-cockroachdb.md @@ -39,14 +39,14 @@ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ sql -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/dbinit.sql %} ~~~ The `app.js` file contains the code for `INSERT`, `SELECT`, `UPDATE`, and `DELETE` SQL operations: {% include_cached copy-clipboard.html %} ~~~ js -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-node-postgres/main/app.js %} +{% include example-apps/cockroachlabs/example-app-node-postgres/main/app.js %} ~~~ All of the database operations are wrapped in a helper function named `retryTxn`. This function attempts to commit statements in the context of an explicit transaction. If a [retry error]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) is thrown, the wrapper will retry committing the transaction, with [exponential backoff](https://wikipedia.org/wiki/Exponential_backoff), until the maximum number of retries is reached (by default, 15). diff --git a/src/current/v26.3/build-a-python-app-with-cockroachdb-django.md b/src/current/v26.3/build-a-python-app-with-cockroachdb-django.md index 85644de65ed..e3a8eef46cd 100644 --- a/src/current/v26.3/build-a-python-app-with-cockroachdb-django.md +++ b/src/current/v26.3/build-a-python-app-with-cockroachdb-django.md @@ -67,7 +67,7 @@ The `requirements.txt` file at the top level of the `example-app-python-django` {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-django/master/requirements.txt %} ~~~ This tutorial uses [`virtualenv`](https://virtualenv.pypa.io) for dependency management. @@ -135,7 +135,7 @@ Start by building some [models](https://docs.djangoproject.com/en/3.1/topics/db/ {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/models.py %} ~~~ In this file, we define some simple classes that map to the tables in the cluster. @@ -146,7 +146,7 @@ Next, build out some [class-based views](https://docs.djangoproject.com/en/3.1/t {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/views.py %} ~~~ This file defines the application's views as classes. Each view class corresponds to one of the table classes defined in `models.py`. The methods of these classes define read and write transactions on the tables in the database. @@ -159,7 +159,7 @@ Lastly, define some [URL routes](https://docs.djangoproject.com/en/3.1/topics/ht {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} +{% include example-apps/cockroachlabs/example-app-python-django/master/cockroach_example/cockroach_example/urls.py %} ~~~ ## Step 5. Initialize the database diff --git a/src/current/v26.3/build-a-python-app-with-cockroachdb-sqlalchemy.md b/src/current/v26.3/build-a-python-app-with-cockroachdb-sqlalchemy.md index e56b9c136a8..70e205bbdad 100644 --- a/src/current/v26.3/build-a-python-app-with-cockroachdb-sqlalchemy.md +++ b/src/current/v26.3/build-a-python-app-with-cockroachdb-sqlalchemy.md @@ -40,28 +40,28 @@ The `requirements.txt` file includes the required libraries to connect to Cockro {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/requirements.txt %} ~~~ The `dbinit.sql` file initializes the database schema that the application uses: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/dbinit.sql %} ~~~ The `models.py` uses SQLAlchemy to map the `Accounts` table to a Python object: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/models.py %} ~~~ The `main.py` uses SQLAlchemy to map Python methods to SQL operations: {% include_cached copy-clipboard.html %} ~~~ python -{% remote_include https://raw.githubusercontent.com/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} +{% include example-apps/cockroachlabs/example-app-python-sqlalchemy/master/main.py %} ~~~ `main.py` also executes the `main` method of the program. diff --git a/src/current/v26.3/build-a-rust-app-with-cockroachdb.md b/src/current/v26.3/build-a-rust-app-with-cockroachdb.md index 4ca08938824..46b9cdea10c 100644 --- a/src/current/v26.3/build-a-rust-app-with-cockroachdb.md +++ b/src/current/v26.3/build-a-rust-app-with-cockroachdb.md @@ -39,7 +39,7 @@ The `Cargo.toml` file is the configuration file for the example, and sets the de {% include_cached copy-clipboard.html %} ~~~ toml -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/Cargo.toml %} ~~~ The `main` function is the entry point for the application, with the code for connecting to the cluster, creating the `accounts` table, creating accounts in that table, and transferring money between two accounts. @@ -52,14 +52,14 @@ CockroachDB may require the [client to retry a transaction]({% link {{ page.vers {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN execute_txn || END execute_txn %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__execute-txn.rs %} ~~~ The `transfer_funds` function calls `execute_txn` to perform the actual transfer of funds from one account to the other. {% include_cached copy-clipboard.html %} ~~~ rust -{% remote_include https://raw.githubusercontent.com/cockroachdb/example-app-rust-postgres/use-uuids/src/main.rs || BEGIN transfer_funds || END transfer_funds %} +{% include example-apps/cockroachdb/example-app-rust-postgres/use-uuids/src/main__transfer-funds.rs %} ~~~ ## Step 3. Run the code