[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-7750":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":18,"compositeScore":20,"rankGlobal":10,"rankLanguage":10,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":22,"hasPages":22,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":28,"readmeContent":29,"aiSummary":30,"trendingCount":16,"starSnapshotCount":16,"syncStatus":31,"lastSyncTime":32,"discoverSource":33},7750,"blazer","ankane\u002Fblazer","ankane","Business intelligence made simple","",null,"Ruby",4788,499,66,12,0,1,3,10,30.1,"MIT License",false,"master",[25,26,27],"business-intelligence","charts","sql","2026-06-12 02:01:44","# Blazer\n\nExplore your data with SQL. Easily create charts and dashboards, and share them with your team.\n\n[Try it out](https:\u002F\u002Fblazer.dokkuapp.com)\n\n[![Screenshot](https:\u002F\u002Fblazer.dokkuapp.com\u002Fassets\u002Fblazer-176c595c.png)](https:\u002F\u002Fblazer.dokkuapp.com)\n\nBlazer is also available as a [Docker image](https:\u002F\u002Fgithub.com\u002Fankane\u002Fblazer-docker).\n\n:tangerine: Battle-tested at [Instacart](https:\u002F\u002Fwww.instacart.com\u002Fopensource)\n\n[![Build Status](https:\u002F\u002Fgithub.com\u002Fankane\u002Fblazer\u002Factions\u002Fworkflows\u002Fbuild.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fankane\u002Fblazer\u002Factions)\n\n## Features\n\n- **Multiple data sources** - PostgreSQL, MySQL, Redshift, and [many more](#full-list)\n- **Variables** - run the same queries with different values\n- **Checks & alerts** - get emailed when bad data appears\n- **Audits** - all queries are tracked\n- **Security** - works with your authentication system\n\n## Docs\n\n- [Installation](#installation)\n- [Queries](#queries)\n- [Charts](#charts)\n- [Dashboards](#dashboards)\n- [Checks](#checks)\n- [Cohorts](#cohorts)\n- [Anomaly Detection](#anomaly-detection)\n- [Forecasting](#forecasting)\n- [Uploads](#uploads)\n- [Data Sources](#data-sources)\n- [Query Permissions](#query-permissions)\n\n## Installation\n\nAdd this line to your application’s Gemfile:\n\n```ruby\ngem \"blazer\"\n```\n\nRun:\n\n```sh\nrails generate blazer:install\nrails db:migrate\n```\n\nAnd mount the dashboard in your `config\u002Froutes.rb`:\n\n```ruby\nmount Blazer::Engine, at: \"blazer\"\n```\n\nFor production, specify your database:\n\n```ruby\nENV[\"BLAZER_DATABASE_URL\"] = \"postgres:\u002F\u002Fuser:password@hostname:5432\u002Fdatabase\"\n```\n\nWhen possible, Blazer tries to protect against queries which modify data by running each query in a transaction and rolling it back, but a safer approach is to use a read-only user. [See how to create one](#permissions).\n\n#### Checks (optional)\n\nBe sure to set a host in `config\u002Fenvironments\u002Fproduction.rb` for emails to work.\n\n```ruby\nconfig.action_mailer.default_url_options = {host: \"blazer.dokkuapp.com\"}\n```\n\nSchedule checks to run (with cron, Solid Queue, [Heroku Scheduler](https:\u002F\u002Felements.heroku.com\u002Faddons\u002Fscheduler), etc). The default options are every 5 minutes, 1 hour, or 1 day, which you can customize. For each of these options, set up a task to run.\n\n```sh\nrake blazer:run_checks SCHEDULE=\"5 minutes\"\nrake blazer:run_checks SCHEDULE=\"1 hour\"\nrake blazer:run_checks SCHEDULE=\"1 day\"\n```\n\nYou can also set up failing checks to be sent once a day (or whatever you prefer).\n\n```sh\nrake blazer:send_failing_checks\n```\n\nHere’s what it looks like with cron.\n\n```\n*\u002F5 * * * * rake blazer:run_checks SCHEDULE=\"5 minutes\"\n0   * * * * rake blazer:run_checks SCHEDULE=\"1 hour\"\n30  7 * * * rake blazer:run_checks SCHEDULE=\"1 day\"\n0   8 * * * rake blazer:send_failing_checks\n```\n\nFor Solid Queue, update `config\u002Frecurring.yml`.\n\n```yml\nproduction:\n  blazer_run_checks_5_minutes:\n    command: \"Blazer.run_checks(schedule: '5 minutes')\"\n    schedule: every 5 minutes\n  blazer_run_checks_1_hour:\n    command: \"Blazer.run_checks(schedule: '1 hour')\"\n    schedule: every hour\n  blazer_run_checks_1_day:\n    command: \"Blazer.run_checks(schedule: '1 day')\"\n    schedule: every day at 7:30am\n  blazer_send_failing_checks:\n    command: \"Blazer.send_failing_checks\"\n    schedule: every day at 8am\n```\n\nFor Slack notifications, create an [incoming webhook](https:\u002F\u002Fslack.com\u002Fapps\u002FA0F7XDUAZ-incoming-webhooks) and set:\n\n```sh\nBLAZER_SLACK_WEBHOOK_URL=https:\u002F\u002Fhooks.slack.com\u002F...\n```\n\nName the webhook “Blazer” and add a cool icon.\n\n## Authentication\n\nDon’t forget to protect the dashboard in production.\n\n### Basic Authentication\n\nSet the following variables in your environment or an initializer.\n\n```ruby\nENV[\"BLAZER_USERNAME\"] = \"andrew\"\nENV[\"BLAZER_PASSWORD\"] = \"secret\"\n```\n\n### Devise\n\n```ruby\nauthenticate :user, ->(user) { user.admin? } do\n  mount Blazer::Engine, at: \"blazer\"\nend\n```\n\n### Other\n\nSpecify a `before_action` method to run in `config\u002Fblazer.yml`.\n\n```yml\nbefore_action_method: require_admin\n```\n\nYou can define this method in your `ApplicationController`.\n\n```ruby\ndef require_admin\n  # depending on your auth, something like...\n  redirect_to main_app.root_path unless current_user && current_user.admin?\nend\n```\n\nBe sure to render or redirect for unauthorized users.\n\n## Permissions\n\n### PostgreSQL\n\nCreate a user with read-only permissions:\n\n```sql\nBEGIN;\nCREATE ROLE blazer LOGIN PASSWORD 'secret';\nGRANT CONNECT ON DATABASE dbname TO blazer;\nGRANT USAGE ON SCHEMA public TO blazer;\nGRANT SELECT ON ALL TABLES IN SCHEMA public TO blazer;\nALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO blazer;\nCOMMIT;\n```\n\n### MySQL and MariaDB\n\nCreate a user with read-only permissions:\n\n```sql\nCREATE USER 'blazer'@'127.0.0.1' IDENTIFIED BY 'secret';\nGRANT SELECT, SHOW VIEW ON dbname.* TO 'blazer'@'127.0.0.1';\nFLUSH PRIVILEGES;\n```\n\n## Sensitive Data\n\nIf your database contains sensitive or personal data, check out [Hypershield](https:\u002F\u002Fgithub.com\u002Fankane\u002Fhypershield) to shield it.\n\n## Encrypted Data\n\nIf you need to search encrypted data, use [blind indexing](https:\u002F\u002Fgithub.com\u002Fankane\u002Fblind_index).\n\nYou can have Blazer transform specific variables with:\n\n```ruby\nBlazer.transform_variable = lambda do |name, value|\n  value = User.generate_email_bidx(value) if name == \"email_bidx\"\n  value\nend\n```\n\n## Queries\n\n### Variables\n\nCreate queries with variables.\n\n```sql\nSELECT * FROM users WHERE gender = {gender}\n```\n\nUse `{start_time}` and `{end_time}` for time ranges. [Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fqueries\u002F9-time-range-selector?start_time=1997-10-03T05%3A00%3A00%2B00%3A00&end_time=1997-10-04T04%3A59%3A59%2B00%3A00)\n\n```sql\nSELECT * FROM ratings WHERE rated_at >= {start_time} AND rated_at \u003C= {end_time}\n```\n\n### Smart Variables\n\n[Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fqueries\u002F1-smart-variable)\n\nSuppose you have the query:\n\n```sql\nSELECT * FROM users WHERE occupation_id = {occupation_id}\n```\n\nInstead of remembering each occupation’s id, users can select occupations by name.\n\nAdd a smart variable in `config\u002Fblazer.yml` with:\n\n```yml\nsmart_variables:\n  occupation_id: \"SELECT id, name FROM occupations ORDER BY name ASC\"\n```\n\nThe first column is the value of the variable, and the second column is the label.\n\nYou can also use an array or hash for static data and enums.\n\n```yml\nsmart_variables:\n  period: [\"day\", \"week\", \"month\"]\n  status: {0: \"Active\", 1: \"Archived\"}\n```\n\n### Linked Columns\n\n[Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fqueries\u002F3-linked-column) - title column\n\nLink results to other pages in your apps or around the web. Specify a column name and where it should link to. You can use the value of the result with `{value}`.\n\n```yml\nlinked_columns:\n  user_id: \"\u002Fadmin\u002Fusers\u002F{value}\"\n  ip_address: \"https:\u002F\u002Fwww.infosniper.net\u002Findex.php?ip_address={value}\"\n```\n\n### Smart Columns\n\n[Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fqueries\u002F2-smart-column) - occupation_id column\n\nSuppose you have the query:\n\n```sql\nSELECT name, city_id FROM users\n```\n\nSee which city the user belongs to without a join.\n\n```yml\nsmart_columns:\n  city_id: \"SELECT id, name FROM cities WHERE id IN {value}\"\n```\n\nYou can also use a hash for static data and enums.\n\n```yml\nsmart_columns:\n  status: {0: \"Active\", 1: \"Archived\"}\n```\n\n### Caching\n\nBlazer can automatically cache results to improve speed. It can cache slow queries:\n\n```yml\ncache:\n  mode: slow\n  expires_in: 60 # min\n  slow_threshold: 15 # sec\n```\n\nOr it can cache all queries:\n\n```yml\ncache:\n  mode: all\n  expires_in: 60 # min\n```\n\nOf course, you can force a refresh at any time.\n\n## Charts\n\nBlazer will automatically generate charts based on the types of the columns returned in your query.\n\n**Note:** The order of columns matters.\n\n### Line Chart\n\nThere are two ways to generate line charts.\n\n2+ columns - timestamp, numeric(s) - [Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fqueries\u002F4-line-chart-format-1)\n\n```sql\nSELECT date_trunc('week', created_at), COUNT(*) FROM users GROUP BY 1\n```\n\n3 columns - timestamp, string, numeric - [Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fqueries\u002F5-line-chart-format-2)\n\n\n```sql\nSELECT date_trunc('week', created_at), gender, COUNT(*) FROM users GROUP BY 1, 2\n```\n\n### Column Chart\n\nThere are also two ways to generate column charts.\n\n2+ columns - string, numeric(s) - [Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fqueries\u002F6-column-chart-format-1)\n\n```sql\nSELECT gender, COUNT(*) FROM users GROUP BY 1\n```\n\n3 columns - string, string, numeric - [Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fqueries\u002F7-column-chart-format-2)\n\n```sql\nSELECT gender, zip_code, COUNT(*) FROM users GROUP BY 1, 2\n```\n\n### Scatter Chart\n\n2 columns - both numeric - [Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fqueries\u002F16-scatter-chart)\n\n```sql\nSELECT x, y FROM table\n```\n\n### Pie Chart\n\n2 columns - string, numeric - and last column named `pie` - [Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fqueries\u002F17-pie-chart)\n\n```sql\nSELECT gender, COUNT(*) AS pie FROM users GROUP BY 1\n```\n\n### Maps\n\nColumns named `latitude` and `longitude` or `lat` and `lon` or `lat` and `lng` - [Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fqueries\u002F15-map)\n\n```sql\nSELECT name, latitude, longitude FROM cities\n```\n\nor a column named `geojson`\n\n```sql\nSELECT name, geojson FROM counties\n```\n\nTo enable, get an access token from [Mapbox](https:\u002F\u002Fwww.mapbox.com\u002F) and set `ENV[\"MAPBOX_ACCESS_TOKEN\"]`.\n\n### Targets\n\nUse the column name `target` to draw a line for goals. [Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fqueries\u002F8-target-line)\n\n```sql\nSELECT date_trunc('week', created_at), COUNT(*) AS new_users, 100000 AS target FROM users GROUP BY 1\n```\n\n## Dashboards\n\nCreate a dashboard with multiple queries. [Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fdashboards\u002F1-dashboard-demo)\n\nIf the query has a chart, the chart is shown. Otherwise, you’ll see a table.\n\nIf any queries have variables, they will show up on the dashboard.\n\n## Checks\n\nChecks give you a centralized place to see the health of your data. [Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fchecks)\n\nCreate a query to identify bad rows.\n\n```sql\nSELECT * FROM ratings WHERE user_id IS NULL \u002F* all ratings should have a user *\u002F\n```\n\nThen create check with optional emails if you want to be notified. Emails are sent when a check starts failing, and when it starts passing again.\n\n## Cohorts\n\nCreate a cohort analysis from a simple SQL query. [Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fqueries\u002F19-cohort-analysis-from-first-order)\n\nCreate a query with the comment `\u002F* cohort analysis *\u002F`. The result should have columns named `user_id` and `conversion_time` and optionally `cohort_time`.\n\nYou can generate cohorts from the first conversion time:\n\n```sql\n\u002F* cohort analysis *\u002F\nSELECT user_id, created_at AS conversion_time FROM orders\n```\n\n(the first conversion isn’t counted in the first time period with this format)\n\nOr from another time, like sign up:\n\n```sql\n\u002F* cohort analysis *\u002F\nSELECT users.id AS user_id, orders.created_at AS conversion_time, users.created_at AS cohort_time\nFROM users LEFT JOIN orders ON orders.user_id = users.id\n```\n\nThis feature requires PostgreSQL or MySQL 8.\n\n## Anomaly Detection\n\nBlazer supports three different approaches to anomaly detection.\n\n### Prophet\n\nAdd [prophet-rb](https:\u002F\u002Fgithub.com\u002Fankane\u002Fprophet) to your Gemfile:\n\n```ruby\ngem \"prophet-rb\"\n```\n\nAnd add to `config\u002Fblazer.yml`:\n\n```yml\nanomaly_checks: prophet\n```\n\n### Trend\n\nAdd [trend](https:\u002F\u002Fgithub.com\u002Fankane\u002Ftrend) to your Gemfile:\n\n```ruby\ngem \"trend\"\n```\n\nSet the URL to the [API](https:\u002F\u002Fgithub.com\u002Fankane\u002Ftrend-api) in an initializer:\n\n```ruby\nTrend.url = \"http:\u002F\u002Flocalhost:8000\"\n```\n\nAnd add to `config\u002Fblazer.yml`:\n\n```yml\nanomaly_checks: trend\n```\n\n### AnomalyDetection.rb\n\nAdd [anomaly_detection](https:\u002F\u002Fgithub.com\u002Fankane\u002FAnomalyDetection.rb) to your Gemfile:\n\n```ruby\ngem \"anomaly_detection\"\n```\n\nAnd add to `config\u002Fblazer.yml`:\n\n```yml\nanomaly_checks: anomaly_detection\n```\n\n## Forecasting\n\nBlazer supports for two different forecasting methods. [Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fqueries\u002F18-forecast?forecast=t)\n\nA forecast link will appear for queries that return 2 columns with types timestamp and numeric.\n\n### Prophet\n\nAdd [prophet-rb](https:\u002F\u002Fgithub.com\u002Fankane\u002Fprophet) to your Gemfile:\n\n```ruby\ngem \"prophet-rb\", \">= 0.2.1\"\n```\n\nAnd add to `config\u002Fblazer.yml`:\n\n```yml\nforecasting: prophet\n```\n\n### Trend\n\nAdd [trend](https:\u002F\u002Fgithub.com\u002Fankane\u002Ftrend) to your Gemfile:\n\n```ruby\ngem \"trend\"\n```\n\nSet the URL to the [API](https:\u002F\u002Fgithub.com\u002Fankane\u002Ftrend-api) in an initializer:\n\n```ruby\nTrend.url = \"http:\u002F\u002Flocalhost:8000\"\n```\n\nAnd add to `config\u002Fblazer.yml`:\n\n```yml\nforecasting: trend\n```\n\n## Uploads\n\nCreate database tables from CSV files. [Example](https:\u002F\u002Fblazer.dokkuapp.com\u002Fuploads)\n\nRun:\n\n```sh\nrails generate blazer:uploads\nrails db:migrate\n```\n\nAnd add to `config\u002Fblazer.yml`:\n\n```yml\nuploads:\n  url: postgres:\u002F\u002F...\n  schema: uploads\n  data_source: main\n```\n\nThis feature requires PostgreSQL. Create a new schema just for uploads.\n\n```sql\nCREATE SCHEMA uploads;\n```\n\n## Data Sources\n\nBlazer supports multiple data sources :tada:\n\nAdd additional data sources in `config\u002Fblazer.yml`:\n\n```yml\ndata_sources:\n  main:\n    url: \u003C%= ENV[\"BLAZER_DATABASE_URL\"] %>\n    # timeout, smart_variables, linked_columns, smart_columns\n  catalog:\n    url: \u003C%= ENV[\"CATALOG_DATABASE_URL\"] %>\n    # ...\n  redshift:\n    url: \u003C%= ENV[\"REDSHIFT_DATABASE_URL\"] %>\n    # ...\n```\n\n### Full List\n\n- [Amazon Athena](#amazon-athena)\n- [Amazon Redshift](#amazon-redshift)\n- [Apache Drill](#apache-drill)\n- [Apache Hive](#apache-hive)\n- [Apache Ignite](#apache-ignite)\n- [Apache Spark](#apache-spark)\n- [Cassandra](#cassandra)\n- [Druid](#druid)\n- [Elasticsearch](#elasticsearch)\n- [Google BigQuery](#google-bigquery)\n- [IBM DB2 and Informix](#ibm-db2-and-informix)\n- [InfluxDB](#influxdb)\n- [MySQL and MariaDB](#mysql-and-mariadb-1)\n- [Neo4j](#neo4j)\n- [OpenSearch](#opensearch)\n- [Oracle](#oracle)\n- [PostgreSQL](#postgresql-1)\n- [Presto and Trino](#presto-and-trino)\n- [Salesforce](#salesforce)\n- [Snowflake](#snowflake)\n- [Socrata Open Data API (SODA)](#socrata-open-data-api-soda)\n- [SQLite](#sqlite)\n- [SQL Server](#sql-server)\n\nYou can also [create an adapter](#creating-an-adapter) for any other data store.\n\n**Note:** In the examples below, we recommend using environment variables for urls.\n\n```yml\ndata_sources:\n  my_source:\n    url: \u003C%= ENV[\"BLAZER_MY_SOURCE_URL\"] %>\n```\n\n### Amazon Athena\n\nAdd [aws-sdk-athena](https:\u002F\u002Fgithub.com\u002Faws\u002Faws-sdk-ruby) and [aws-sdk-glue](https:\u002F\u002Fgithub.com\u002Faws\u002Faws-sdk-ruby) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    adapter: athena\n    database: database\n\n    # optional settings\n    output_location: s3:\u002F\u002Fsome-bucket\u002F\n    workgroup: primary\n    access_key_id: ...\n    secret_access_key: ...\n    region: ...\n```\n\nHere’s an example IAM policy:\n\n```json\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"athena:GetQueryExecution\",\n                \"athena:GetQueryResults\",\n                \"athena:StartQueryExecution\"\n            ],\n            \"Resource\": [\n                \"arn:aws:athena:region:account-id:workgroup\u002Fprimary\"\n            ]\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"glue:GetTable\",\n                \"glue:GetTables\"\n            ],\n            \"Resource\": [\n                \"arn:aws:glue:region:account-id:catalog\",\n                \"arn:aws:glue:region:account-id:database\u002Fdefault\",\n                \"arn:aws:glue:region:account-id:table\u002Fdefault\u002F*\"\n            ]\n        }\n    ]\n}\n```\n\nYou also need to configure [S3 permissions](https:\u002F\u002Frepost.aws\u002Fknowledge-center\u002Faccess-denied-athena).\n\n### Amazon Redshift\n\nAdd [activerecord7-redshift-adapter-pennylane](https:\u002F\u002Fgithub.com\u002Fpennylane-hq\u002Factiverecord-adapter-redshift) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    url: redshift:\u002F\u002Fuser:password@hostname:5439\u002Fdatabase\n```\n\nUse a [read-only user](https:\u002F\u002Fdocs.aws.amazon.com\u002Fredshift\u002Flatest\u002Fdg\u002Fr_GRANT.html).\n\n### Apache Drill\n\nAdd [drill-sergeant](https:\u002F\u002Fgithub.com\u002Fankane\u002Fdrill-sergeant) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    adapter: drill\n    url: http:\u002F\u002Fhostname:8047\n```\n\nUse a [read-only user](https:\u002F\u002Fdrill.apache.org\u002Fdocs\u002Froles-and-privileges\u002F).\n\n### Apache Hive\n\nAdd [hexspace](https:\u002F\u002Fgithub.com\u002Fankane\u002Fhexspace) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    adapter: hive\n    url: sasl:\u002F\u002Fuser:password@hostname:10000\u002Fdatabase\n```\n\nUse a [read-only user](https:\u002F\u002Fcwiki.apache.org\u002Fconfluence\u002Fdisplay\u002FHive\u002FLanguageManual+Authorization). Requires [HiveServer2](https:\u002F\u002Fcwiki.apache.org\u002Fconfluence\u002Fdisplay\u002FHive\u002FSetting+Up+HiveServer2).\n\n### Apache Ignite\n\nAdd [ignite-client](https:\u002F\u002Fgithub.com\u002Fankane\u002Fignite-ruby) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    url: ignite:\u002F\u002Fuser:password@hostname:10800\n```\n\nUse a [read-only user](https:\u002F\u002Fwww.gridgain.com\u002Fdocs\u002Flatest\u002Fadministrators-guide\u002Fsecurity\u002Fauthorization-permissions) (requires a third-party plugin).\n\n### Apache Spark\n\nAdd [hexspace](https:\u002F\u002Fgithub.com\u002Fankane\u002Fhexspace) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    adapter: spark\n    url: sasl:\u002F\u002Fuser:password@hostname:10000\u002Fdatabase\n```\n\nUse a read-only user. Requires the [Thrift server](https:\u002F\u002Fspark.apache.org\u002Fdocs\u002Flatest\u002Fsql-distributed-sql-engine.html).\n\n### Cassandra\n\nAdd [cassandra-driver](https:\u002F\u002Fgithub.com\u002Fdatastax\u002Fruby-driver) and [sorted_set](https:\u002F\u002Fgithub.com\u002Fknu\u002Fsorted_set) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    url: cassandra:\u002F\u002Fuser:password@hostname:9042\u002Fkeyspace\n```\n\nUse a [read-only role](https:\u002F\u002Fdocs.datastax.com\u002Fen\u002Fcql-oss\u002F3.3\u002Fcql\u002Fcql_using\u002FuseSecurePermission.html).\n\n### Druid\n\nEnable [SQL support](https:\u002F\u002Fdruid.apache.org\u002Fdocs\u002Flatest\u002Fquerying\u002Fsql) on the broker and set:\n\n```yml\ndata_sources:\n  my_source:\n    adapter: druid\n    url: http:\u002F\u002Fhostname:8082\n```\n\nUse a [read-only role](https:\u002F\u002Fdruid.apache.org\u002Fdocs\u002Flatest\u002Fdevelopment\u002Fextensions-core\u002Fdruid-basic-security.html).\n\n### Elasticsearch\n\nAdd [elasticsearch](https:\u002F\u002Fgithub.com\u002Felastic\u002Felasticsearch-ruby) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    adapter: elasticsearch\n    url: http:\u002F\u002Fuser:password@hostname:9200\n```\n\nUse a [read-only role](https:\u002F\u002Fwww.elastic.co\u002Fguide\u002Fen\u002Felasticsearch\u002Freference\u002Fcurrent\u002Fsecurity-privileges.html).\n\n### Google BigQuery\n\nAdd [google-cloud-bigquery](https:\u002F\u002Fgithub.com\u002FGoogleCloudPlatform\u002Fgoogle-cloud-ruby\u002Ftree\u002Fmain\u002Fgoogle-cloud-bigquery) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    adapter: bigquery\n    project: your-project\n    keyfile: path\u002Fto\u002Fkeyfile.json\n```\n\n### IBM DB2 and Informix\n\nAdd [ibm_db](https:\u002F\u002Fgithub.com\u002Fibmdb\u002Fruby-ibmdb) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    url: ibm-db:\u002F\u002Fuser:password@hostname:50000\u002Fdatabase\n```\n\nUse a [read-only user](https:\u002F\u002Fwww.ibm.com\u002Fsupport\u002Fpages\u002Fcreating-read-only-database-permissions-user).\n\n### InfluxDB\n\nAdd [influxdb](https:\u002F\u002Fgithub.com\u002Finfluxdata\u002Finfluxdb-ruby) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    adapter: influxdb\n    url: http:\u002F\u002Fuser:password@hostname:8086\u002Fdatabase\n```\n\nUse a [read-only user](https:\u002F\u002Fdocs.influxdata.com\u002Finfluxdb\u002Fv1.8\u002Fadministration\u002Fauthentication_and_authorization\u002F). Supports [InfluxQL](https:\u002F\u002Fdocs.influxdata.com\u002Finfluxdb\u002Fv1.8\u002Fquery_language\u002Fexplore-data\u002F).\n\n### MySQL and MariaDB\n\nAdd [mysql2](https:\u002F\u002Fgithub.com\u002Fbrianmario\u002Fmysql2) to your Gemfile (if it’s not there) and set:\n\n```yml\ndata_sources:\n  my_source:\n    url: mysql2:\u002F\u002Fuser:password@hostname:3306\u002Fdatabase\n```\n\nUse a [read-only user](#mysql-and-mariadb).\n\n### Neo4j\n\nAdd [neo4j-ruby-driver](https:\u002F\u002Fgithub.com\u002Fneo4jrb\u002Fneo4j-ruby-driver) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    adapter: neo4j\n    url: bolt:\u002F\u002Fuser:password@hostname:7687\u002Fdatabase\n```\n\nUse a [read-only user](https:\u002F\u002Fneo4j.com\u002Fdocs\u002Fcypher-manual\u002Fcurrent\u002Faccess-control\u002Fmanage-privileges\u002F).\n\n### OpenSearch\n\nAdd [opensearch-ruby](https:\u002F\u002Fgithub.com\u002Fopensearch-project\u002Fopensearch-ruby) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    adapter: opensearch\n    url: http:\u002F\u002Fuser:password@hostname:9200\n```\n\nUse a [read-only user](https:\u002F\u002Fopensearch.org\u002Fdocs\u002Flatest\u002Fsecurity-plugin\u002Faccess-control\u002Fpermissions\u002F).\n\n### Oracle\n\nAdd [activerecord-oracle_enhanced-adapter](https:\u002F\u002Fgithub.com\u002Frsim\u002Foracle-enhanced) and [ruby-oci8](https:\u002F\u002Fgithub.com\u002Fkubo\u002Fruby-oci8) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    url: oracle-enhanced:\u002F\u002Fuser:password@hostname:1521\u002Fdatabase\n```\n\nUse a [read-only user](https:\u002F\u002Fdocs.oracle.com\u002Fcd\u002FB19306_01\u002Fnetwork.102\u002Fb14266\u002Fauthoriz.htm).\n\n### PostgreSQL\n\nAdd [pg](https:\u002F\u002Fgithub.com\u002Fged\u002Fruby-pg) to your Gemfile (if it’s not there) and set:\n\n```yml\ndata_sources:\n  my_source:\n    url: postgres:\u002F\u002Fuser:password@hostname:5432\u002Fdatabase\n```\n\nUse a [read-only user](#postgresql).\n\n### Presto and Trino\n\nAdd [presto-client](https:\u002F\u002Fgithub.com\u002Ftreasure-data\u002Ftrino-client-ruby\u002Ftree\u002Fv0.6.5) or [trino-client](https:\u002F\u002Fgithub.com\u002Ftreasure-data\u002Ftrino-client-ruby) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    url: presto:\u002F\u002Fuser@hostname:8080\u002Fcatalog\n    # or\n    url: trino:\u002F\u002Fuser@hostname:8080\u002Fcatalog\n```\n\nUse a read-only user for [Presto](https:\u002F\u002Fprestodb.io\u002Fdocs\u002Fcurrent\u002Fsecurity\u002Fbuilt-in-system-access-control.html) or [Trino](https:\u002F\u002Ftrino.io\u002Fdocs\u002Fcurrent\u002Fsecurity\u002Fbuilt-in-system-access-control.html).\n\n### Salesforce\n\nAdd [restforce](https:\u002F\u002Fgithub.com\u002Frestforce\u002Frestforce) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    adapter: salesforce\n```\n\nAnd set the appropriate environment variables:\n\n```sh\nSALESFORCE_USERNAME=\"username\"\nSALESFORCE_PASSWORD=\"password\"\nSALESFORCE_SECURITY_TOKEN=\"security token\"\nSALESFORCE_CLIENT_ID=\"client id\"\nSALESFORCE_CLIENT_SECRET=\"client secret\"\nSALESFORCE_API_VERSION=\"41.0\"\n```\n\nUse a read-only user. Supports [SOQL](https:\u002F\u002Fdeveloper.salesforce.com\u002Fdocs\u002Fatlas.en-us.soql_sosl.meta\u002Fsoql_sosl\u002Fsforce_api_calls_soql.htm).\n\n### Snowflake\n\nFirst, install ODBC. For Homebrew, use:\n\n```sh\nbrew install unixodbc\n```\n\nFor Ubuntu, use:\n\n```sh\nsudo apt-get install unixodbc-dev\n```\n\nFor Heroku, use the [Apt buildpack](https:\u002F\u002Fgithub.com\u002Fheroku\u002Fheroku-buildpack-apt) and create an `Aptfile` with:\n\n```text\nunixodbc-dev\nhttps:\u002F\u002Fsfc-repo.snowflakecomputing.com\u002Fodbc\u002Flinux\u002F2.21.5\u002Fsnowflake-odbc-2.21.5.x86_64.deb\n```\n\n> This installs the driver at `\u002Fapp\u002F.apt\u002Fusr\u002Flib\u002Fsnowflake\u002Fodbc\u002Flib\u002FlibSnowflake.so`\n\nThen, download the [Snowflake ODBC driver](https:\u002F\u002Fdocs.snowflake.com\u002Fdeveloper-guide\u002Fodbc\u002Fodbc-download). Add [odbc_adapter](https:\u002F\u002Fgithub.com\u002Flocalytics\u002Fodbc_adapter) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    adapter: snowflake\n    conn_str: Driver=\u002Fpath\u002Fto\u002FlibSnowflake.so;uid=user;pwd=password;server=host.snowflakecomputing.com\n```\n\nUse a [read-only role](https:\u002F\u002Fdocs.snowflake.com\u002Fen\u002Fuser-guide\u002Fsecurity-access-control-configure.html).\n\n### Socrata Open Data API (SODA)\n\nSet:\n\n```yml\ndata_sources:\n  my_source:\n    adapter: soda\n    url: https:\u002F\u002Fsoda.demo.socrata.com\u002Fresource\u002F4tka-6guv.json\n    app_token: ...\n```\n\nSupports [SoQL](https:\u002F\u002Fdev.socrata.com\u002Fdocs\u002Ffunctions\u002F).\n\n### SQLite\n\nAdd [sqlite3](https:\u002F\u002Fgithub.com\u002Fsparklemotion\u002Fsqlite3-ruby) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    url: sqlite3:path\u002Fto\u002Fdatabase.sqlite3\n```\n\n### SQL Server\n\nAdd [tiny_tds](https:\u002F\u002Fgithub.com\u002Frails-sqlserver\u002Ftiny_tds) and [activerecord-sqlserver-adapter](https:\u002F\u002Fgithub.com\u002Frails-sqlserver\u002Factiverecord-sqlserver-adapter) to your Gemfile and set:\n\n```yml\ndata_sources:\n  my_source:\n    url: sqlserver:\u002F\u002Fuser:password@hostname:1433\u002Fdatabase\n```\n\nUse a [read-only user](https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fsql\u002Frelational-databases\u002Fsecurity\u002Fauthentication-access\u002Fgetting-started-with-database-engine-permissions?view=sql-server-ver15).\n\n## Creating an Adapter\n\nCreate an adapter for any data store with:\n\n```ruby\nclass FooAdapter \u003C Blazer::Adapters::BaseAdapter\n  # code goes here\nend\n\nBlazer.register_adapter \"foo\", FooAdapter\n```\n\nSee the [Presto adapter](https:\u002F\u002Fgithub.com\u002Fankane\u002Fblazer\u002Fblob\u002Fmaster\u002Flib\u002Fblazer\u002Fadapters\u002Fpresto_adapter.rb) for a good example. Then use:\n\n```yml\ndata_sources:\n  my_source:\n    adapter: foo\n    url: http:\u002F\u002Fuser:password@hostname:9200\u002F\n```\n\n## Query Permissions\n\nBlazer supports a basic permissions model.\n\n1. Queries without a name are unlisted\n2. Queries whose name starts with `#` are only listed to the creator\n3. Queries whose name starts with `*` can only be edited by the creator\n\n## Learn SQL\n\nHave team members who want to learn SQL? Here are a few great, free resources.\n\n- [The Data School](https:\u002F\u002Fdataschool.com\u002Flearn-sql\u002F)\n- [SQLBolt](https:\u002F\u002Fsqlbolt.com\u002F)\n\n## Useful Tools\n\nFor an easy way to group by day, week, month, and more with correct time zones, check out [Groupdate.sql](https:\u002F\u002Fgithub.com\u002Fankane\u002Fgroupdate.sql).\n\n## Performance\n\nBy default, queries take up a request while they are running. To run queries asynchronously, add to your config:\n\n```yml\nasync: true\n```\n\n**Note:** Requires caching to be enabled. If you have multiple web processes, your app must use a centralized cache store like Memcached or Redis.\n\n```ruby\nconfig.cache_store = :mem_cache_store\n```\n\n## Archiving\n\nArchive queries that haven’t been viewed in over 90 days.\n\n```sh\nrake blazer:archive_queries\n```\n\n## Content Security Policy\n\nIf views are stuck with a `Loading...` message, there might be a problem with strict CSP settings in your app. This can be checked with Firefox or Chrome dev tools. You can allow Blazer to override these settings for its controllers with:\n\n```yml\noverride_csp: true\n```\n\n## History\n\nView the [changelog](https:\u002F\u002Fgithub.com\u002Fankane\u002Fblazer\u002Fblob\u002Fmaster\u002FCHANGELOG.md)\n\n## Thanks\n\nBlazer uses a number of awesome open source projects, including [Rails](https:\u002F\u002Fgithub.com\u002Frails\u002Frails\u002F), [Vue.js](https:\u002F\u002Fgithub.com\u002Fvuejs\u002Fvue), [jQuery](https:\u002F\u002Fgithub.com\u002Fjquery\u002Fjquery), [Bootstrap](https:\u002F\u002Fgithub.com\u002Ftwbs\u002Fbootstrap), [Selectize](https:\u002F\u002Fgithub.com\u002Fbrianreavis\u002Fselectize.js), [StickyTableHeaders](https:\u002F\u002Fgithub.com\u002Fjmosbech\u002FStickyTableHeaders), [Stupid jQuery Table Sort](https:\u002F\u002Fgithub.com\u002Fjoequery\u002FStupid-Table-Plugin), and [Date Range Picker](https:\u002F\u002Fgithub.com\u002Fdangrossman\u002Fbootstrap-daterangepicker).\n\nDemo data from [MovieLens](https:\u002F\u002Fgrouplens.org\u002Fdatasets\u002Fmovielens\u002F).\n\n## Want to Make Blazer Better?\n\nThat’s awesome! Here are a few ways you can help:\n\n- [Report bugs](https:\u002F\u002Fgithub.com\u002Fankane\u002Fblazer\u002Fissues)\n- Fix bugs and [submit pull requests](https:\u002F\u002Fgithub.com\u002Fankane\u002Fblazer\u002Fpulls)\n- Write, clarify, or fix documentation\n- Suggest or add new features\n\nCheck out the [dev app](https:\u002F\u002Fgithub.com\u002Fankane\u002Fblazer-dev) to get started.\n","Blazer 是一个简化商业智能分析的工具，它允许用户通过 SQL 查询来探索数据，并轻松创建图表和仪表板以便与团队共享。该项目支持多种数据源如 PostgreSQL、MySQL 和 Redshift 等，并提供了变量功能让查询更加灵活。此外，Blazer 还具备检查与警报机制，在检测到异常数据时能够自动发送邮件通知，同时所有执行过的查询都会被记录下来以供审计使用。其安全特性兼容现有的认证系统。适用于需要快速构建数据分析视图并希望在团队内部分享结果的企业或组织。",2,"2026-06-11 03:14:11","top_language"]