---
title: "OmicsLake Practical Workflow: Integrating Phase 1-4 Functions"
author: "OmicsLake Development Team"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
    %\VignetteIndexEntry{OmicsLake Practical Workflow}
    %\VignetteEngine{knitr::rmarkdown}
    %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(
    collapse = TRUE,
    comment = "#>",
    eval = isTRUE(getOption("omicslake.vignette.eval", FALSE))
)
```

# Introduction

This vignette introduces a practical workflow that integrates the features
implemented in OmicsLake.  Using RNA-seq differential expression analysis as an
example, we demonstrate how the following features work together:

## Before you run all chunks

This vignette defaults to non-evaluated chunks during package build.
To run all code locally, enable:

```r
options(omicslake.vignette.eval = TRUE)
```

For a script-first entry point of the same analysis class (`count -> edgeR ->
limma-voom -> ORA`), run:

```bash
bash tools/run_demo_count_edger_limma_voom_ora.sh
```

For representative layer-by-layer use cases (SE/SCE/MAE/Spectra/QFeatures/
MsExperiment), see:

- `vignettes/omicslake_layer_use_cases_EN.Rmd`

- **Phase 1**: SQL query interface (`ol_query()`)
- **Phase 2**: aggregation and window functions (`ol_aggregate()`,
- `ol_add_rank()`, `ol_top_n()`, etc.)
- **Phase 3**: Parquet import/export (`ol_import_parquet()`,
- `ol_export_parquet()`)
- **Phase 4**: database views (`ol_create_view()`, `ol_drop_view()`,
- `ol_list_views()`)

## Project setup

```{r init}
library(OmicsLake)

ol_init("rnaseq_analysis")
```

## Preparing the data

First, prepare sample RNA-seq count data:

```{r prepare_data}
set.seed(123)

raw_counts <- data.frame(
    gene_id = paste0("GENE", 1:1000),
    control_1 = rpois(1000, lambda = 50),
    control_2 = rpois(1000, lambda = 50),
    control_3 = rpois(1000, lambda = 50),
    treated_1 = rpois(1000, lambda = 80),
    treated_2 = rpois(1000, lambda = 80),
    treated_3 = rpois(1000, lambda = 80)
)

ol_write("raw_counts", raw_counts)
ol_commit("Import raw count data")
ol_label("data_import")
```

## Phase 1: Filtering data with SQL queries

Use an SQL query to filter out low-expressed genes.  This is a common
preprocessing step in RNA-seq analysis.

```{r phase1_filtering}
filtered_counts <- ol_query("\
    SELECT
    gene_id,
    control_1, control_2, control_3,
    treated_1, treated_2, treated_3
    FROM raw_counts
    WHERE (
        control_1 + control_2 + control_3 +
        treated_1 + treated_2 + treated_3
    ) >= 30
")

cat("Original genes:", nrow(raw_counts), "\n")
cat("After filtering:", nrow(filtered_counts), "\n")

ol_write("filtered_counts", filtered_counts)
ol_commit("Filter low-expression genes using SQL")
```

Using an SQL query, you can also calculate the average expression and
difference between treated and control means for each gene:

```{r phase1_stats}
gene_stats <- ol_query("\
    SELECT
    gene_id,
    (control_1 + control_2 + control_3) / 3.0 AS control_mean,
    (treated_1 + treated_2 + treated_3) / 3.0 AS treated_mean,
    (
        (treated_1 + treated_2 + treated_3) / 3.0 -
        (control_1 + control_2 + control_3) / 3.0
    ) AS mean_diff
    FROM filtered_counts
    ORDER BY mean_diff DESC
")

head(gene_stats, 10)
```

## Phase 2: Statistical analysis with aggregation functions

Use the Phase 2 aggregation functions to perform more advanced statistical
analyses.

### Calculate statistics for each gene

```{r phase2_aggregate}
gene_summary <- ol_aggregate("filtered_counts",
    group_by = "gene_id",
    control_mean = list(func = "avg", col = "control_1, control_2, control_3"),
    treated_mean = list(func = "avg", col = "treated_1, treated_2, treated_3"),
    control_sd = list(func = "stddev", col = "control_1, control_2, control_3"),
    treated_sd = list(func = "stddev", col = "treated_1, treated_2, treated_3")
)

ol_write("gene_summary", gene_summary)
```

### Extract top expressed genes

```{r phase2_top_genes}
top_control <- ol_top_n("filtered_counts",
    n = 20,
    order_by = "control_1",
    descending = TRUE
)

cat("Top 20 genes in control samples:\n")
print(head(top_control, 10))
```

### Add rankings

Assign a rank to each gene based on expression:

```{r phase2_ranking}
ranked_genes <- ol_add_rank("filtered_counts",
    rank_by = "treated_1",
    as_column = "expression_rank",
    descending = TRUE
)

ol_write("ranked_genes", ranked_genes)
```

### Compute cumulative statistics

```{r phase2_cumulative}
cumulative_expr <- ol_cumulative_sum("ranked_genes",
    column = "treated_1",
    order_by = "expression_rank",
    as_column = "cumulative_expression"
)

ol_write("cumulative_expr", cumulative_expr)
```

## Phase 3: Sharing results with Parquet

Export analysis results in Parquet format so that you can share them with
collaborators or use them in other tools.

### Exporting results

```{r phase3_export}
ol_export_parquet("gene_summary",
    "gene_summary_results.parquet",
    compression = "zstd",
    compression_level = 3
)

ol_export_parquet("ranked_genes",
    "ranked_genes.parquet",
    compression = "snappy"
)

cat("Exported results to Parquet files\n")
```

### Importing external data

Example of importing data provided by collaborators:

```{r phase3_import, eval = isTRUE(getOption("omicslake.vignette.eval", FALSE))}
external_results <- data.frame(
    gene_id = paste0("GENE", sample(1:1000, 50)),
    log2fc = rnorm(50, 0, 2),
    pvalue = runif(50, 0, 0.1),
    padj = runif(50, 0, 0.1)
)
write.csv(external_results, "external_de_results.csv", row.names = FALSE)

library(arrow)
write_parquet(external_results, "external_de_results.parquet")

ol_import_parquet("external_de_results.parquet",
    "external_de_results",
    mode = "create"
)

imported <- ol_read("external_de_results")
cat("Imported", nrow(imported), "genes from external analysis\n")
```

## Phase 4: Compare multiple versions with database views

Database views are a powerful feature for comparing multiple analysis results
or reusing complex queries.

### Scenario: Compare two different analysis methods

```{r phase4_setup_methods}
set.seed(456)
deseq2_results <- data.frame(
    gene_id = paste0("GENE", 1:100),
    log2fc = rnorm(100, 0, 1.5),
    pvalue = runif(100, 0, 0.1),
    padj = runif(100, 0, 0.1),
    baseMean = runif(100, 10, 1000)
)

ol_write("de_results_deseq2", deseq2_results)
ol_tag("de_results_deseq2", "deseq2_method")

set.seed(789)
edger_results <- data.frame(
    gene_id = paste0("GENE", 1:120),
    log2fc = rnorm(120, 0, 1.8),
    pvalue = runif(120, 0, 0.1),
    padj = runif(120, 0, 0.1),
    logCPM = runif(120, 2, 10)
)

ol_write("de_results_edger", edger_results)
ol_tag("de_results_edger", "edger_method")

ol_commit("Complete DE analysis with DESeq2 and edgeR")
ol_label("de_analysis_complete")
```

### Create a view: Compare methods

```{r phase4_create_view}
ol_create_view("method_comparison",
    "SELECT
    d.gene_id,
    d.log2fc AS deseq2_lfc,
    e.log2fc AS edger_lfc,
    ABS(d.log2fc - e.log2fc) AS lfc_difference,
    d.padj AS deseq2_padj,
    e.padj AS edger_padj,
    CASE
        WHEN d.padj < 0.05 AND e.padj < 0.05 THEN 'both_significant'
        WHEN d.padj < 0.05 THEN 'deseq2_only'
        WHEN e.padj < 0.05 THEN 'edger_only'
        ELSE 'neither'
    END AS significance_status
    FROM de_results_deseq2 d
    INNER JOIN de_results_edger e ON d.gene_id = e.gene_id
    ORDER BY lfc_difference DESC",
    depends_on = c("de_results_deseq2", "de_results_edger")
)

comparison <- ol_read("method_comparison")
cat("Comparing", nrow(comparison), "genes detected by both methods\n")
```

### Using the view: Check concordance

```{r phase4_use_view}
table(comparison$significance_status)

high_discordance <- comparison[comparison$lfc_difference > 1, ]
cat("\nGenes with high log2FC discordance (>1):", nrow(high_discordance), "\n")
```

### Create multiple views

```{r phase4_multiple_views}
ol_create_view("significant_genes_deseq2",
    "SELECT * FROM de_results_deseq2 WHERE padj < 0.05 ORDER BY log2fc DESC",
    depends_on = "de_results_deseq2"
)

ol_create_view("significant_genes_edger",
    "SELECT * FROM de_results_edger WHERE padj < 0.05 ORDER BY log2fc DESC",
    depends_on = "de_results_edger"
)

ol_create_view("consensus_significant",
    "SELECT
    d.gene_id,
    (d.log2fc + e.log2fc) / 2 AS avg_log2fc,
    d.padj AS deseq2_padj,
    e.padj AS edger_padj
    FROM de_results_deseq2 d
    INNER JOIN de_results_edger e ON d.gene_id = e.gene_id
    WHERE d.padj < 0.05 AND e.padj < 0.05
    ORDER BY avg_log2fc DESC",
    depends_on = c("de_results_deseq2", "de_results_edger")
)

consensus <- ol_read("consensus_significant")
cat("Consensus significant genes:", nrow(consensus), "\n")
```

### List views

```{r phase4_list_views}
views <- ol_list_views()
print(views)
```

### Deleting views

You can delete a view when it is no longer needed:

```{r phase4_drop_view}
ol_drop_view("significant_genes_edger")

views_after <- ol_list_views()
cat("Remaining views:", nrow(views_after), "\n")
```

## Integrated workflow example: Combine all features

Here is a complete workflow example combining the features described so far:

```{r integrated_workflow}
ol_init("complete_analysis")

set.seed(999)
counts <- data.frame(
    gene_id = paste0("GENE", 1:500),
    ctrl1 = rpois(500, 40),
    ctrl2 = rpois(500, 40),
    trt1 = rpois(500, 60),
    trt2 = rpois(500, 60)
)

ol_write("raw_data", counts)

filtered <- ol_query("\
    SELECT * FROM raw_data
    WHERE (ctrl1 + ctrl2 + trt1 + trt2) >= 20
")
ol_write("filtered_data", filtered)

stats <- ol_aggregate("filtered_data",
    group_by = "gene_id",
    ctrl_mean = list(func = "avg", col = "ctrl1, ctrl2"),
    trt_mean = list(func = "avg", col = "trt1, trt2")
)
ol_write("gene_stats", stats)

ol_export_parquet("gene_stats", "analysis_stats.parquet")

set.seed(111)
de_final <- data.frame(
    gene_id = paste0("GENE", sample(1:500, 80)),
    log2fc = rnorm(80, 0, 2),
    padj = runif(80, 0, 0.05)
)
ol_write("de_final", de_final)

ol_create_view("enriched_results",
    "SELECT
    d.gene_id,
    d.log2fc,
    d.padj,
    s.ctrl_mean,
    s.trt_mean,
    s.trt_mean - s.ctrl_mean AS mean_change
    FROM de_final d
    LEFT JOIN gene_stats s ON d.gene_id = s.gene_id
    WHERE d.padj < 0.05
    ORDER BY ABS(d.log2fc) DESC",
    depends_on = c("de_final", "gene_stats")
)

enriched <- ol_read("enriched_results")
cat("Enriched analysis results:", nrow(enriched), "genes\n")

top_results <- ol_top_n(
    "enriched_results",
    n = 10,
    order_by = "log2fc",
    descending = TRUE
)
print(top_results)

ol_commit("Complete integrated analysis workflow")
ol_label("final_results")
```

## Practical tips and best practices

### Use cases for Phase 1 (SQL queries)

- Applying complex filtering conditions
- Joining multiple tables
- Shaping data before aggregation
- Classification using conditional statements (CASE expressions)

### Use cases for Phase 2 (aggregation functions)

- Calculate statistics for each group
- Moving averages and cumulative sums using window functions
- Calculate rankings or percentiles
- Simultaneous aggregation of multiple columns

### Use cases for Phase 3 (Parquet)

- Efficient storage of large datasets
- Data sharing with other tools (Python, Spark, etc.)
- Long-term archiving of analysis results
- Transferring data to cloud storage

### Use cases for Phase 4 (views)

- Comparing multiple analysis versions
- Reusing complex queries
- Logical abstraction of data
- Analysis flows with explicit dependencies

### Combination patterns

1. **Query → Aggregate → Export**: data preprocessing, statistical analysis,
1. and saving results
2. **View → Query → Aggregate**: integrated analysis of multiple data sources
3. **Import → View → Export**: integrate external data and re-export
4. **Aggregate → View → Query**: stepwise data transformation pipeline

## Summary

This vignette showed a practical RNA-seq analysis workflow using the Phase 1-4
features of OmicsLake.  Each phase’s functions can be used independently, but
combining them allows you to construct a more powerful and flexible analysis
pipeline.

In particular, the database view feature of Phase 4 is very useful when
comparing multiple analysis methods or parameter sets.  By using views, you can
make complex SQL queries reusable and explicitly manage analysis dependencies.

For detailed API specifications, please refer to the comprehensive guide
(`omicslake_comprehensive_guide.Rmd`).

## Session Information

```{r session_info}
sessionInfo()
```
