Skip to content

Commit

Permalink
feat: adding rules docs
Browse files Browse the repository at this point in the history
  • Loading branch information
benfdking committed Jun 24, 2024
1 parent d7d5801 commit 58ef3ec
Show file tree
Hide file tree
Showing 19 changed files with 1,056 additions and 18 deletions.
11 changes: 10 additions & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@ jobs:
- uses: actions/checkout@v4
- uses: Swatinem/rust-cache@v2
- uses: dtolnay/rust-toolchain@nightly
- run: cargo r -F codegen-docs > options.md
- run: cargo r -F codegen-docs
- uses: stefanzweifel/git-auto-commit-action@v5
with:
push_options: '--force'
codegen-check:
name: codegen-check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: Swatinem/rust-cache@v2
- uses: dtolnay/rust-toolchain@nightly
- run: cargo r --bin sqruff -F codegen-docs
- run: git diff --quiet || exit 1
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ To get help on the available commands and options, run the following command:
sqruff --help
```

For all the details on the CLI commands and options, see the [CLI documentation](./docs/cli.md).

### Configuration

For all the details on the rules options, see the [configuration documentation](./docs/rules.md).

## Community

Join the Quary community on [Slack](https://join.slack.com/t/quarylabs/shared_invite/zt-2dlbfnztw-dMLXJVL38NcbhqRuM5gUcw) to ask questions, suggest features, or share your projects. Also feel free to raise any issues in the repository.
Expand Down
6 changes: 5 additions & 1 deletion crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,18 @@ harness = false

[features]
jemalloc = ["jemallocator"]
codegen-docs = ["clap-markdown"]
codegen-docs = ["clap-markdown", "minijinja", "serde"]

[dependencies]
sqruff-lib = { version = "0.7.0", path = "../lib" }
lsp = { version = "*", package = "sqruff-lsp", path = "../lsp" }
clap = { version = "4", features = ["derive"] }
console = "0.15.8"

# Codegen dependencies
clap-markdown = { version = "0.1.4", optional = true }
minijinja= { version="2.0.2" , optional = true }
serde = { version = "1.0.203", features = ["derive"], optional = true }

[target.'cfg(not(target_env = "msvc"))'.dependencies]
jemallocator = { version = "0.5", package = "tikv-jemallocator", optional = true }
Expand Down
54 changes: 54 additions & 0 deletions crates/cli/src/docs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use std::io::Write;
use std::path::Path;

use minijinja::{context, Environment};
use serde::Serialize;
use sqruff_lib::core::rules::base::ErasedRule;
use sqruff_lib::rules::rules;

use crate::commands::Cli;

#[cfg(feature = "codegen-docs")]
pub(crate) fn codegen_docs() {
// CLI Docs
let markdown: String = clap_markdown::help_markdown::<Cli>();
let file_cli = std::fs::File::create("docs/cli.md").unwrap();
let mut writer = std::io::BufWriter::new(file_cli);
writer.write_all(markdown.as_bytes()).unwrap();

// Rules Docs
let mut env = Environment::new();
let crate_dir = env!("CARGO_MANIFEST_DIR");
let template_path =
Path::new(crate_dir).join("src").join("docs").join("generate_rule_docs_template.md");
let template = std::fs::read_to_string(template_path).expect("Failed to read template file");
env.add_template("rules", &template).unwrap();

let tmpl = env.get_template("rules").unwrap();
let rules = rules();
let rules = rules.into_iter().map(Rule::from).collect::<Vec<_>>();
let file_rules = std::fs::File::create("docs/rules.md").unwrap();
let mut writer = std::io::BufWriter::new(file_rules);
writer.write_all(tmpl.render(context!(rules => rules)).unwrap().as_bytes()).unwrap();
}

#[derive(Debug, Clone, Serialize)]
struct Rule {
pub name: &'static str,
pub code: &'static str,
pub description: &'static str,
pub fixable: bool,
pub long_description: Option<&'static str>,
}

impl From<ErasedRule> for Rule {
fn from(value: ErasedRule) -> Self {
Rule {
name: value.name(),
code: value.code(),
fixable: value.is_fix_compatible(),
description: value.description(),
long_description: value.long_description(),
}
}
}
22 changes: 22 additions & 0 deletions crates/cli/src/docs/generate_rule_docs_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Rules

The following rules are available in this create. This list is generated from the `rules` module in the source code and can be turned on or off and configured in the config file.

## Rule Index

| Rule Code | Rule Name |
|-----------|-----------|{% for rule in rules %}
| {{ rule.code }} | [{{ rule.name }}](#{{ rule.name }}) |{% endfor %}

## Rule Details
{% for rule in rules %}
### {{ rule.name }}

{{ rule.description }}

**Code:** {{ rule.code }}

**Fixable:** {% if rule.fixable %}Yes{% else %}No{% endif %}

{% if rule.long_description %}{{ rule.long_description }}{% endif %}
{% endfor %}
11 changes: 5 additions & 6 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@ use sqruff_lib::core::config::FluffConfig;
use sqruff_lib::core::linter::linter::Linter;

use crate::commands::{Cli, Commands};
#[cfg(feature = "codegen-docs")]
use crate::docs::codegen_docs;

mod commands;
#[cfg(feature = "codegen-docs")]
mod docs;

#[cfg(all(feature = "jemalloc", not(target_env = "msvc")))]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

#[cfg(feature = "codegen-docs")]
fn codegen_docs() {
let markdown: String = clap_markdown::help_markdown::<Cli>();
println!("{markdown}");
}

#[cfg_attr(feature = "codegen-docs", allow(unreachable_code))]
fn main() {
#[cfg(feature = "codegen-docs")]
Expand Down
4 changes: 4 additions & 0 deletions crates/lib/src/core/rules/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,10 @@ pub trait Rule: CloneRule + dyn_clone::DynClone + Debug + 'static + Send + Sync

fn name(&self) -> &'static str;

fn long_description(&self) -> Option<&'static str> {
None
}

fn config_ref(&self) -> &'static str {
self.name()
}
Expand Down
25 changes: 25 additions & 0 deletions crates/lib/src/rules/aliasing/AL01.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,31 @@ impl Rule for RuleAL01 {
fn crawl_behaviour(&self) -> Crawler {
SegmentSeekerCrawler::new(["alias_expression"].into()).into()
}

fn long_description(&self) -> Option<&'static str> {
r#"
**Anti-pattern**
In this example, the alias `voo` is implicit.
```sql
SELECT
voo.a
FROM foo voo
```
**Best practice**
Add `AS` to make the alias explicit.
```sql
SELECT
voo.a
FROM foo AS voo
```
"#
.into()
}
}

#[cfg(test)]
Expand Down
25 changes: 25 additions & 0 deletions crates/lib/src/rules/aliasing/AL02.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,31 @@ impl Rule for RuleAL02 {
"aliasing.column"
}

fn long_description(&self) -> Option<&'static str> {
r#"
**Anti-pattern**
In this example, the alias for column `a` is implicit.
```sql
SELECT
a alias_col
FROM foo
```
**Best practice**
Add the `AS` keyword to make the alias explicit.
```sql
SELECT
a AS alias_col
FROM foo
```
"#
.into()
}

fn description(&self) -> &'static str {
"Implicit/explicit aliasing of columns."
}
Expand Down
27 changes: 27 additions & 0 deletions crates/lib/src/rules/aliasing/AL03.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,33 @@ impl Rule for RuleAL03 {
"aliasing.expression"
}

fn long_description(&self) -> Option<&'static str> {
r#"
**Anti-pattern**
In this example, there is no alias for both sums.
```sql
SELECT
sum(a),
sum(b)
FROM foo
```
**Best practice**
Add aliases.
```sql
SELECT
sum(a) AS a_sum,
sum(b) AS b_sum
FROM foo
```
"#
.into()
}

fn description(&self) -> &'static str {
"Column expression without alias. Use explicit `AS` clause."
}
Expand Down
47 changes: 47 additions & 0 deletions crates/lib/src/rules/aliasing/AL04.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,53 @@ impl Rule for RuleAL04 {
"aliasing.unique.table"
}

fn long_description(&self) -> Option<&'static str> {
r#"
**Anti-pattern**
In this example, the alias t is reused for two different tables:
```sql
SELECT
t.a,
t.b
FROM foo AS t, bar AS t
-- This can also happen when using schemas where the
-- implicit alias is the table name:
SELECT
a,
b
FROM
2020.foo,
2021.foo
```
**Best practice**
Make all tables have a unique alias.
```sql
SELECT
f.a,
b.b
FROM foo AS f, bar AS b
-- Also use explicit aliases when referencing two tables
-- with the same name from two different schemas.
SELECT
f1.a,
f2.b
FROM
2020.foo AS f1,
2021.foo AS f2
```
"#
.into()
}

fn description(&self) -> &'static str {
"Table aliases should be unique within each clause."
}
Expand Down
38 changes: 34 additions & 4 deletions crates/lib/src/rules/aliasing/AL05.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,38 @@ impl Rule for RuleAL05 {
"aliasing.unused"
}

fn description(&self) -> &'static str {
"Tables should not be aliased if that alias is not used."
fn long_description(&self) -> Option<&'static str> {
r#"
**Anti-pattern**
In this example, alias `zoo` is not used.
```sql
SELECT
a
FROM foo AS zoo
```
**Best practice**
Use the alias or remove it. An unused alias makes code harder to read without changing any functionality.
```sql
SELECT
zoo.a
FROM foo AS zoo
-- Alternatively...
SELECT
a
FROM foo
```
"#.into()
}

fn is_fix_compatible(&self) -> bool {
true
fn description(&self) -> &'static str {
"Tables should not be aliased if that alias is not used."
}

fn eval(&self, context: RuleContext) -> Vec<LintResult> {
Expand Down Expand Up @@ -72,6 +98,10 @@ impl Rule for RuleAL05 {
violations
}

fn is_fix_compatible(&self) -> bool {
true
}

fn crawl_behaviour(&self) -> Crawler {
SegmentSeekerCrawler::new(["select_statement"].into()).into()
}
Expand Down
Loading

0 comments on commit 58ef3ec

Please sign in to comment.