{
  "manifest_version": 1,
  "community_extension": {
    "extension": {
      "name": "duckhts",
      "description": "DuckDB extension for reading HTS file formats via htslib",
      "language": "C",
      "build": "cmake",
      "license": "MIT",
      "requires_toolchains": "python3",
      "excluded_platforms": "windows_amd64;windows_arm64",
      "maintainers": [
        "sounkou-bioinfo"
      ]
    },
    "repo": {
      "github": "RGenomicsETL/duckhts",
      "ref_source": "git_head"
    },
    "docs": {
      "hello_world_lines": [
        "-- Load the extension",
        "LOAD duckhts;",
        "",
        "-- Read a VCF/BCF file (tidy FORMAT columns)",
        "SELECT CHROM, POS, REF, ALT, SAMPLE_ID",
        "FROM read_bcf('test/data/formatcols.vcf.gz', tidy_format := true)",
        "LIMIT 5;",
        "",
        "-- Read a BAM/SAM file",
        "SELECT QNAME, RNAME, POS, READ_GROUP_ID, SAMPLE_ID",
        "FROM read_bam('test/data/rg.sam.gz')",
        "LIMIT 5;"
      ],
      "extended_intro": [
        "DuckHTS provides DuckDB table functions for common high-throughput sequencing (HTS) formats using htslib. Query VCF, BCF, BAM, CRAM, FASTA, FASTQ, GTF, GFF, and tabix-indexed files directly in SQL.",
        "The extension also includes sequence utility UDFs, SAM flag predicate helpers, and HTS metadata helpers."
      ],
      "feature_notes": [
        "Paired FASTQ is supported via `mate_path` or `interleaved := true`.",
        "CRAM reads are supported with an explicit reference file.",
        "GTF/GFF attributes can be returned as a parsed `MAP` with `attributes_map := true` via `read_gff` or `read_gtf`.",
        "Optional SAM tag columns and an auxiliary tag map are available through `standard_tags` and `auxiliary_tags`.",
        "Tabix readers support `header`, `header_names`, type inference with `auto_detect`, and explicit `column_types`.",
        "MSVC builds (`windows_amd64`/`windows_arm64`) are not supported; use MinGW/RTools on Windows."
      ]
    }
  },
  "functions": [
    {
      "name": "read_bcf",
      "kind": "table",
      "category": "Readers",
      "signature": "read_bcf(path, region := NULL, index_path := NULL, tidy_format := FALSE, additional_csq_column_types := NULL)",
      "returns": "table",
      "r_wrapper": "rduckhts_bcf",
      "description": "Read VCF and BCF variant data with typed INFO, FORMAT, typed CSQ/ANN/BCSQ subfields, optional tidy sample output, and optional bcftools-style CSQ type overrides.",
      "examples": [
        "SELECT CHROM, POS, REF, ALT FROM read_bcf('vcf_file.bcf') LIMIT 5;"
      ]
    },
    {
      "name": "read_bam",
      "kind": "table",
      "category": "Readers",
      "signature": "read_bam(path, standard_tags := FALSE, auxiliary_tags := FALSE, region := NULL, index_path := NULL, reference := NULL, sequence_encoding := 'string', quality_representation := 'string')",
      "returns": "table",
      "r_wrapper": "rduckhts_bam",
      "description": "Read SAM, BAM, and CRAM alignments with optional typed SAMtags and auxiliary tag maps. Use sequence_encoding := 'nt16' to return SEQ as UTINYINT[] and quality_representation := 'phred' to return QUAL as UTINYINT[] instead of VARCHAR.",
      "examples": [
        "SELECT QNAME, FLAG, RNAME, POS FROM read_bam('range.bam') LIMIT 5;"
      ]
    },
    {
      "name": "read_fasta",
      "kind": "table",
      "category": "Readers",
      "signature": "read_fasta(path, region := NULL, index_path := NULL, sequence_encoding := 'string')",
      "returns": "table",
      "r_wrapper": "rduckhts_fasta",
      "description": "Read FASTA records or indexed FASTA regions as sequence rows. Use sequence_encoding := 'nt16' to return SEQUENCE as UTINYINT[] (htslib nt16 4-bit codes) instead of VARCHAR.",
      "examples": [
        "SELECT NAME, length(SEQUENCE) FROM read_fasta('ce.fa');"
      ]
    },
    {
      "name": "read_bed",
      "kind": "table",
      "category": "Readers",
      "signature": "read_bed(path, region := NULL, index_path := NULL)",
      "returns": "table",
      "r_wrapper": "rduckhts_bed",
      "description": "Read BED3-BED12 interval files with canonical typed columns and optional tabix-backed region filtering.",
      "examples": [
        "SELECT chrom, start, \"end\", name FROM read_bed('targets.bed') LIMIT 5;"
      ]
    },
    {
      "name": "fasta_nuc",
      "kind": "table",
      "category": "Readers",
      "signature": "fasta_nuc(path, bed_path := NULL, bin_width := NULL, region := NULL, index_path := NULL, bed_index_path := NULL, include_seq := FALSE)",
      "returns": "table",
      "r_wrapper": "rduckhts_fasta_nuc",
      "description": "Compute bedtools nuc-style nucleotide composition for supplied BED intervals or generated fixed-width bins over a FASTA reference.",
      "examples": [
        "SELECT chrom, start, \"end\", pct_gc FROM fasta_nuc('ce.fa', bin_width := 1000) LIMIT 5;"
      ]
    },
    {
      "name": "read_fastq",
      "kind": "table",
      "category": "Readers",
      "signature": "read_fastq(path, interleaved := FALSE, mate_path := NULL, sequence_encoding := 'string', quality_representation := 'string', input_quality_encoding := 'phred33')",
      "returns": "table",
      "r_wrapper": "rduckhts_fastq",
      "description": "Read single-end, paired-end, or interleaved FASTQ files with optional legacy quality decoding. By default, FASTQ qualities are interpreted as modern Phred+33 input. Use sequence_encoding := 'nt16' to return SEQUENCE as UTINYINT[] and quality_representation := 'phred' to return QUALITY as UTINYINT[] instead of VARCHAR. input_quality_encoding accepts 'phred33', 'auto', 'phred64', or 'solexa64'.",
      "examples": [
        "SELECT NAME, MATE FROM read_fastq('r1.fq', mate_path := 'r2.fq') LIMIT 5;"
      ]
    },
    {
      "name": "detect_quality_encoding",
      "kind": "table",
      "category": "Metadata",
      "signature": "detect_quality_encoding(path, max_records := 10000)",
      "returns": "table",
      "r_wrapper": "rduckhts_detect_quality_encoding",
      "description": "Inspect a FASTQ file's observed quality ASCII range and report compatible legacy encodings with a heuristic guessed encoding.",
      "examples": [
        "SELECT * FROM detect_quality_encoding('reads.fq.gz');"
      ]
    },
    {
      "name": "read_gff",
      "kind": "table",
      "category": "Readers",
      "signature": "read_gff(path, header_names := NULL, header := FALSE, column_types := NULL, auto_detect := FALSE, attributes_map := FALSE, region := NULL, index_path := NULL)",
      "returns": "table",
      "r_wrapper": "rduckhts_gff",
      "description": "Read GFF annotations with optional parsed attribute maps and indexed region filtering.",
      "examples": [
        "SELECT seqname, feature, start, \"end\" FROM read_gff('gff_file.gff.gz') LIMIT 5;"
      ]
    },
    {
      "name": "read_gtf",
      "kind": "table",
      "category": "Readers",
      "signature": "read_gtf(path, header_names := NULL, header := FALSE, column_types := NULL, auto_detect := FALSE, attributes_map := FALSE, region := NULL, index_path := NULL)",
      "returns": "table",
      "r_wrapper": "rduckhts_gtf",
      "description": "Read GTF annotations with optional parsed attribute maps and indexed region filtering.",
      "examples": [
        "SELECT seqname, feature, start, \"end\" FROM read_gtf('annotations.gtf.gz') LIMIT 5;"
      ]
    },
    {
      "name": "read_tabix",
      "kind": "table",
      "category": "Readers",
      "signature": "read_tabix(path, header_names := NULL, header := FALSE, column_types := NULL, auto_detect := FALSE, region := NULL, index_path := NULL)",
      "returns": "table",
      "r_wrapper": "rduckhts_tabix",
      "description": "Read generic tabix-indexed text data with optional header handling and type inference.",
      "examples": [
        "SELECT * FROM read_tabix('meta_tabix.tsv.gz') LIMIT 5;"
      ]
    },
    {
      "name": "fasta_index",
      "kind": "table",
      "category": "Readers",
      "signature": "fasta_index(path, index_path := NULL)",
      "returns": "table",
      "r_wrapper": "rduckhts_fasta_index",
      "description": "Build a FASTA index (.fai) and return a single row with columns success (BOOLEAN) and index_path (VARCHAR).",
      "examples": [
        "SELECT * FROM fasta_index('ce.fa');"
      ]
    },
    {
      "name": "bgzip",
      "kind": "table",
      "category": "Compression",
      "signature": "bgzip(path, output_path := NULL, threads := 4, level := -1, keep := TRUE, overwrite := FALSE)",
      "returns": "table",
      "r_wrapper": "rduckhts_bgzip",
      "description": "Compress a plain file to BGZF and return the created output path and byte counts.",
      "examples": [
        "SELECT * FROM bgzip('regions.bed');"
      ]
    },
    {
      "name": "bgunzip",
      "kind": "table",
      "category": "Compression",
      "signature": "bgunzip(path, output_path := NULL, threads := 4, keep := TRUE, overwrite := FALSE)",
      "returns": "table",
      "r_wrapper": "rduckhts_bgunzip",
      "description": "Decompress a BGZF-compressed file and return the created output path and byte counts.",
      "examples": [
        "SELECT * FROM bgunzip('regions.bed.gz');"
      ]
    },
    {
      "name": "bam_index",
      "kind": "table",
      "category": "Indexing",
      "signature": "bam_index(path, index_path := NULL, min_shift := 0, threads := 4)",
      "returns": "table",
      "r_wrapper": "rduckhts_bam_index",
      "description": "Build a BAM or CRAM index and report the written index path and format.",
      "examples": [
        "SELECT * FROM bam_index('range.bam');"
      ]
    },
    {
      "name": "bcf_index",
      "kind": "table",
      "category": "Indexing",
      "signature": "bcf_index(path, index_path := NULL, min_shift := NULL, threads := 4)",
      "returns": "table",
      "r_wrapper": "rduckhts_bcf_index",
      "description": "Build a TBI or CSI index for a VCF or BCF file and report the written index path and format.",
      "examples": [
        "SELECT * FROM bcf_index('formatcols.vcf.gz');"
      ]
    },
    {
      "name": "tabix_index",
      "kind": "table",
      "category": "Indexing",
      "signature": "tabix_index(path, preset := 'vcf', index_path := NULL, min_shift := 0, threads := 4, seq_col := NULL, start_col := NULL, end_col := NULL, comment_char := NULL, skip_lines := NULL)",
      "returns": "table",
      "r_wrapper": "rduckhts_tabix_index",
      "description": "Build a tabix index for a BGZF-compressed text file using a preset or explicit coordinate columns.",
      "examples": [
        "SELECT * FROM tabix_index('gff_file.gff.gz', preset := 'gff');"
      ]
    },
    {
      "name": "read_hts_header",
      "kind": "table",
      "category": "Metadata",
      "signature": "read_hts_header(path, format := NULL, mode := NULL)",
      "returns": "table",
      "r_wrapper": "rduckhts_hts_header",
      "description": "Inspect HTS headers in parsed, raw, or combined form across supported formats.",
      "examples": [
        "SELECT record_type, id FROM read_hts_header('formatcols.vcf.gz') LIMIT 10;"
      ]
    },
    {
      "name": "read_hts_index",
      "kind": "table",
      "category": "Metadata",
      "signature": "read_hts_index(path, format := NULL, index_path := NULL)",
      "returns": "table",
      "r_wrapper": "rduckhts_hts_index",
      "description": "Inspect high-level HTS index metadata such as sequence names and mapped counts.",
      "examples": [
        "SELECT seqname, index_type FROM read_hts_index('vcf_file.bcf');"
      ]
    },
    {
      "name": "read_hts_index_spans",
      "kind": "table",
      "category": "Metadata",
      "signature": "read_hts_index_spans(path, format := NULL, index_path := NULL)",
      "returns": "table",
      "r_wrapper": "rduckhts_hts_index_spans",
      "description": "Expand index metadata into span and chunk rows suitable for low-level index inspection.",
      "examples": [
        "SELECT seqname, chunk_beg_vo, chunk_end_vo FROM read_hts_index_spans('vcf_file.bcf') LIMIT 5;"
      ]
    },
    {
      "name": "read_hts_index_raw",
      "kind": "table_macro",
      "category": "Metadata",
      "signature": "read_hts_index_raw(path, format := NULL, index_path := NULL)",
      "returns": "table",
      "r_wrapper": "rduckhts_hts_index_raw",
      "description": "Return the raw on-disk HTS index blob together with basic identifying metadata.",
      "examples": [
        "SELECT length(raw) FROM read_hts_index_raw('formatcols.vcf.gz');"
      ]
    },
    {
      "name": "bcftools_liftover",
      "kind": "scalar",
      "category": "Variants",
      "signature": "bcftools_liftover(chrom, pos, ref, alt, chain_path, dst_fasta_ref, src_fasta_ref, max_snp_gap, max_indel_inc, lift_mt, end_pos, no_left_align)",
      "returns": "STRUCT",
      "r_wrapper": "rduckhts_liftover",
      "description": "Row-oriented liftover kernel intended to mirror bcftools +liftover semantics as closely as possible while returning one STRUCT per input row with fields: src_chrom, src_pos, src_ref, src_alt, dest_chrom, dest_pos, dest_end, dest_ref, dest_alt, mapped, reverse_complemented, swap, reject_reason, and note. Set no_left_align := true to skip post-liftover left-alignment of lifted indels (mirrors --no-left-align in bcftools +liftover).",
      "examples": [
        "SELECT (bcftools_liftover(chrom, pos, ref, alt, 'hg19ToHg38.over.chain.gz', 'hg38.fa', 'hg19.fa', 1, 250, false, NULL::BIGINT, false)).dest_pos FROM variants;"
      ]
    },
    {
      "name": "duckdb_liftover",
      "kind": "table_macro",
      "category": "Variants",
      "signature": "duckdb_liftover(table_name, chrom_col, pos_col, ref_col := NULL, alt_col := NULL, chain_path := NULL, dst_fasta_ref := NULL, src_fasta_ref := NULL, max_snp_gap := 1, max_indel_inc := 250, lift_mt := false, end_pos_col := NULL, no_left_align := false)",
      "returns": "table",
      "r_wrapper": "rduckhts_liftover",
      "description": "DuckDB-specific wrapper over bcftools_liftover that takes either a table name or a derived-table expression plus column-name strings for chrom/pos/ref/alt and returns the lifted table. The no_left_align parameter mirrors --no-left-align in bcftools +liftover.",
      "examples": [
        "SELECT * FROM duckdb_liftover('variants', 'chrom', 'pos', ref_col := 'ref', alt_col := 'alt', chain_path := 'hg19ToHg38.over.chain.gz', dst_fasta_ref := 'hg38.fa');",
        "SELECT * FROM duckdb_liftover('(SELECT chrom, pos, ref, alt FROM variants) AS v', 'chrom', 'pos', ref_col := 'ref', alt_col := 'alt', chain_path := 'hg19ToHg38.over.chain.gz', dst_fasta_ref := 'hg38.fa');"
      ]
    },
    {
      "name": "bcftools_score",
      "kind": "table",
      "category": "Variants",
      "signature": "bcftools_score(bcf_path, summary_path, use := NULL, columns := 'PLINK', columns_file := NULL, q_score_thr := NULL, use_variant_id := FALSE, counts := FALSE, samples := NULL, force_samples := FALSE, regions := NULL, regions_file := NULL, regions_overlap := 1, targets := NULL, targets_file := NULL, targets_overlap := 0, apply_filters := NULL, include := NULL, exclude := NULL)",
      "returns": "table",
      "r_wrapper": "rduckhts_score",
      "description": "Compute polygenic scores from one genotype BCF/VCF and one summary-statistics file with bcftools +score-compatible GT/DS/HDS/AP/GP/AS dosage semantics, sample subsetting, and region/target/FILTER-string controls.",
      "examples": [
        "SELECT * FROM bcftools_score('cohort.bcf', 'gwas.tsv.gz', columns := 'PLINK') LIMIT 5;"
      ]
    },
    {
      "name": "bcftools_munge_row",
      "kind": "scalar",
      "category": "Variants",
      "signature": "bcftools_munge_row(chrom, pos, a1, a2, id, p, z, or, beta, n, n_cas, n_con, info, frq, se, lp, ac, neff, neffdiv2, het_i2, het_p, het_lp, dire, fasta_ref, iffy_tag := 'IFFY', mismatch_tag := 'REF_MISMATCH', ns := NULL, nc := NULL, ne := NULL)",
      "returns": "STRUCT",
      "r_wrapper": "",
      "description": "Normalize one summary-statistics row into GWAS-VCF-style fields (chrom/pos/ref/alt/effect metrics), resolving REF/ALT orientation against a FASTA reference and applying swap-aware sign/frequency/count transforms. The output flag `alleles_swapped` means REF/ALT orientation was swapped to match the FASTA reference.",
      "examples": [
        "SELECT (bcftools_munge_row('chr1', 12345, 'A', 'G', 'rs1', 0.01, NULL, NULL, 0.12, 1000, NULL, NULL, NULL, 0.3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'ref.fa')).ref;"
      ]
    },
    {
      "name": "duckdb_munge",
      "kind": "table_macro",
      "category": "Variants",
      "signature": "duckdb_munge(table_name, preset := '', column_map := map([''], ['']), column_map_file := '', fasta_ref := NULL, iffy_tag := 'IFFY', mismatch_tag := 'REF_MISMATCH', ns := NULL, nc := NULL, ne := NULL)",
      "returns": "table",
      "r_wrapper": "rduckhts_munge",
      "description": "DuckDB macro wrapper over bcftools_munge_row that maps source columns (via preset or explicit map) and returns normalized GWAS-VCF-style rows with lean outputs and explicit `alleles_swapped` semantics. Output columns: chrom, pos, id, ref, alt, alleles_swapped, filter, ns, ez, nc, es, se, lp, af, ac, ne (16 columns). For METAL meta-analysis output with SI/I2/CQ/ED columns, use duckdb_munge_metal.",
      "examples": [
        "SELECT * FROM duckdb_munge('gwas_table', preset := 'PLINK', fasta_ref := 'ref.fa');",
        "SELECT * FROM duckdb_munge('(SELECT * FROM gwas_table) AS s', column_map := map(['CHR','BP','A1','A2','SNP'], ['chrom','pos','ea','nea','id']), fasta_ref := 'ref.fa');"
      ]
    },
    {
      "name": "duckdb_munge_metal",
      "kind": "table_macro",
      "category": "Variants",
      "signature": "duckdb_munge_metal(table_name, preset := '', column_map := map([''], ['']), column_map_file := '', fasta_ref := NULL, iffy_tag := 'IFFY', mismatch_tag := 'REF_MISMATCH', ns := NULL, nc := NULL, ne := NULL)",
      "returns": "table",
      "r_wrapper": "rduckhts_munge",
      "description": "Extended munge macro with METAL meta-analysis output columns. Same as duckdb_munge but additionally emits: si (imputation info, from INFO input), i2 (Cochran's I² heterogeneity, from HET_I2), cq (Cochran's Q -log10 p, from HET_LP or -log10(HET_P)), and ed (effect direction string, from DIRE; +/- flipped on allele swap). The R wrapper rduckhts_munge() auto-dispatches to this macro when metal keys (INFO, HET_I2, HET_P, HET_LP, DIRE) are present in the resolved column map.",
      "examples": [
        "SELECT * FROM duckdb_munge_metal('metal_results', preset := 'METAL', fasta_ref := 'ref.fa');",
        "SELECT * FROM duckdb_munge_metal('meta', column_map := map(['CHR','BP','A1','A2','SNP','HET_I2','DIRE'], ['chr','pos','ea','nea','snp','HetISq','Direction']), fasta_ref := 'ref.fa');"
      ]
    },
    {
      "name": "seq_revcomp",
      "kind": "scalar",
      "category": "Sequence UDFs",
      "signature": "seq_revcomp(sequence)",
      "returns": "VARCHAR",
      "r_wrapper": "",
      "description": "Compute the reverse complement of a DNA sequence using A, C, G, T, and N bases.",
      "examples": [
        "SELECT seq_revcomp('ACGTN');"
      ]
    },
    {
      "name": "seq_canonical",
      "kind": "scalar",
      "category": "Sequence UDFs",
      "signature": "seq_canonical(sequence)",
      "returns": "VARCHAR",
      "r_wrapper": "",
      "description": "Return the lexicographically smaller of a sequence and its reverse complement.",
      "examples": [
        "SELECT seq_canonical('ACGTN');"
      ]
    },
    {
      "name": "seq_hash_2bit",
      "kind": "scalar",
      "category": "Sequence UDFs",
      "signature": "seq_hash_2bit(sequence)",
      "returns": "UBIGINT",
      "r_wrapper": "",
      "description": "Encode a short DNA sequence as a 2-bit unsigned integer hash.",
      "examples": [
        "SELECT seq_hash_2bit('ACGT');"
      ]
    },
    {
      "name": "seq_encode_4bit",
      "kind": "scalar",
      "category": "Sequence UDFs",
      "signature": "seq_encode_4bit(sequence)",
      "returns": "UTINYINT[]",
      "r_wrapper": "",
      "description": "Encode an IUPAC DNA sequence as a list of 4-bit base codes, preserving ambiguity symbols including N.",
      "examples": [
        "SELECT seq_encode_4bit('ACGTRYSWKMBDHVN');"
      ]
    },
    {
      "name": "seq_decode_4bit",
      "kind": "scalar",
      "category": "Sequence UDFs",
      "signature": "seq_decode_4bit(codes)",
      "returns": "VARCHAR",
      "r_wrapper": "",
      "description": "Decode a list of 4-bit IUPAC DNA base codes back into a sequence string.",
      "examples": [
        "SELECT seq_decode_4bit(seq_encode_4bit('ACGTRYSWKMBDHVN'));"
      ]
    },
    {
      "name": "seq_gc_content",
      "kind": "scalar",
      "category": "Sequence UDFs",
      "signature": "seq_gc_content(sequence)",
      "returns": "DOUBLE",
      "r_wrapper": "",
      "description": "Compute GC fraction for a DNA sequence as a value between 0 and 1.",
      "examples": [
        "SELECT seq_gc_content('ACGT');"
      ]
    },
    {
      "name": "seq_kmers",
      "kind": "table",
      "category": "Sequence UDFs",
      "signature": "seq_kmers(sequence, k, canonical := FALSE)",
      "returns": "table",
      "r_wrapper": "",
      "description": "Expand a sequence into positional k-mers with optional canonicalization.",
      "examples": [
        "SELECT * FROM seq_kmers('ACGT', 2);"
      ]
    },
    {
      "name": "sam_flag_bits",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "sam_flag_bits(flag)",
      "returns": "STRUCT",
      "r_wrapper": "",
      "description": "Decode a SAM flag into a struct of boolean bit fields using explicit SAM-oriented names such as `is_paired`, `is_proper_pair`, `is_next_segment_unmapped`, and `is_supplementary`.",
      "examples": [
        "SELECT (sam_flag_bits(99)).is_proper_pair;"
      ]
    },
    {
      "name": "sam_flag_has",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "sam_flag_has(flag, mask)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether any bits from the provided SAM flag mask are set in a flag value.",
      "examples": [
        "SELECT sam_flag_has(99, 2);"
      ]
    },
    {
      "name": "is_forward_aligned",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "is_forward_aligned(flag)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether a mapped segment is aligned to the forward strand. Returns `NULL` for unmapped segments because SAM flag `0x10` does not define genomic strand when `0x4` is set.",
      "examples": [
        "SELECT is_forward_aligned(0);"
      ]
    },
    {
      "name": "cigar_has_soft_clip",
      "kind": "scalar",
      "category": "CIGAR Utils",
      "signature": "cigar_has_soft_clip(cigar)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether a CIGAR string contains any soft-clipped segment (`S`).",
      "examples": [
        "SELECT cigar_has_soft_clip('5S90M5S');"
      ]
    },
    {
      "name": "cigar_has_hard_clip",
      "kind": "scalar",
      "category": "CIGAR Utils",
      "signature": "cigar_has_hard_clip(cigar)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether a CIGAR string contains any hard-clipped segment (`H`).",
      "examples": [
        "SELECT cigar_has_hard_clip('5H95M');"
      ]
    },
    {
      "name": "cigar_left_soft_clip",
      "kind": "scalar",
      "category": "CIGAR Utils",
      "signature": "cigar_left_soft_clip(cigar)",
      "returns": "BIGINT",
      "r_wrapper": "",
      "description": "Return the left-end soft-clipped length from a CIGAR string, or zero if the alignment does not start with `S`.",
      "examples": [
        "SELECT cigar_left_soft_clip('5S90M5S');"
      ]
    },
    {
      "name": "cigar_right_soft_clip",
      "kind": "scalar",
      "category": "CIGAR Utils",
      "signature": "cigar_right_soft_clip(cigar)",
      "returns": "BIGINT",
      "r_wrapper": "",
      "description": "Return the right-end soft-clipped length from a CIGAR string, or zero if the alignment does not end with `S`.",
      "examples": [
        "SELECT cigar_right_soft_clip('5S90M5S');"
      ]
    },
    {
      "name": "cigar_query_length",
      "kind": "scalar",
      "category": "CIGAR Utils",
      "signature": "cigar_query_length(cigar)",
      "returns": "BIGINT",
      "r_wrapper": "",
      "description": "Return the query-consuming length from a CIGAR string, counting `M`, `I`, `S`, `=`, and `X`.",
      "examples": [
        "SELECT cigar_query_length('5S90M5I');"
      ]
    },
    {
      "name": "cigar_aligned_query_length",
      "kind": "scalar",
      "category": "CIGAR Utils",
      "signature": "cigar_aligned_query_length(cigar)",
      "returns": "BIGINT",
      "r_wrapper": "",
      "description": "Return the aligned query length from a CIGAR string, counting `M`, `=`, and `X` but excluding clips and insertions.",
      "examples": [
        "SELECT cigar_aligned_query_length('5S90M5I');"
      ]
    },
    {
      "name": "cigar_reference_length",
      "kind": "scalar",
      "category": "CIGAR Utils",
      "signature": "cigar_reference_length(cigar)",
      "returns": "BIGINT",
      "r_wrapper": "",
      "description": "Return the reference-consuming length from a CIGAR string, counting `M`, `D`, `N`, `=`, and `X`.",
      "examples": [
        "SELECT cigar_reference_length('90M5D');"
      ]
    },
    {
      "name": "cigar_has_op",
      "kind": "scalar",
      "category": "CIGAR Utils",
      "signature": "cigar_has_op(cigar, op)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether a CIGAR string contains at least one instance of the requested operator.",
      "examples": [
        "SELECT cigar_has_op('5S90M5S', 'S');"
      ]
    },
    {
      "name": "is_paired",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "is_paired(flag)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether the SAM flag indicates that the template has multiple segments in sequencing (`0x1`).",
      "examples": [
        "SELECT is_paired(99);"
      ]
    },
    {
      "name": "is_proper_pair",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "is_proper_pair(flag)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether the SAM flag indicates that each segment is properly aligned according to the aligner (`0x2`).",
      "examples": [
        "SELECT is_proper_pair(99);"
      ]
    },
    {
      "name": "is_unmapped",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "is_unmapped(flag)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether the read itself is unmapped according to the SAM flag.",
      "examples": [
        "SELECT is_unmapped(4);"
      ]
    },
    {
      "name": "is_next_segment_unmapped",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "is_next_segment_unmapped(flag)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether the next segment in the template is flagged as unmapped (`0x8`).",
      "examples": [
        "SELECT is_next_segment_unmapped(9);"
      ]
    },
    {
      "name": "is_reverse_complemented",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "is_reverse_complemented(flag)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether `SEQ` is stored reverse complemented (`0x10`); for mapped reads this corresponds to reverse-strand alignment.",
      "examples": [
        "SELECT is_reverse_complemented(16);"
      ]
    },
    {
      "name": "is_next_segment_reverse_complemented",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "is_next_segment_reverse_complemented(flag)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether `SEQ` of the next segment in the template is stored reverse complemented (`0x20`).",
      "examples": [
        "SELECT is_next_segment_reverse_complemented(32);"
      ]
    },
    {
      "name": "is_first_segment",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "is_first_segment(flag)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether the read is marked as the first segment in the template.",
      "examples": [
        "SELECT is_first_segment(64);"
      ]
    },
    {
      "name": "is_last_segment",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "is_last_segment(flag)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether the read is marked as the last segment in the template.",
      "examples": [
        "SELECT is_last_segment(128);"
      ]
    },
    {
      "name": "is_secondary",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "is_secondary(flag)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether the alignment is marked as secondary.",
      "examples": [
        "SELECT is_secondary(256);"
      ]
    },
    {
      "name": "is_qc_fail",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "is_qc_fail(flag)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether the read failed vendor or pipeline quality checks.",
      "examples": [
        "SELECT is_qc_fail(512);"
      ]
    },
    {
      "name": "is_duplicate",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "is_duplicate(flag)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether the alignment is flagged as a duplicate.",
      "examples": [
        "SELECT is_duplicate(1024);"
      ]
    },
    {
      "name": "is_supplementary",
      "kind": "scalar",
      "category": "SAM Flag UDFs",
      "signature": "is_supplementary(flag)",
      "returns": "BOOLEAN",
      "r_wrapper": "",
      "description": "Test whether the alignment is marked as supplementary.",
      "examples": [
        "SELECT is_supplementary(2048);"
      ]
    }
  ]
}
