Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/proctoru/squint

Search PostgreSQL jsonb and hstore columns
https://github.com/proctoru/squint

activerecord hstore hstore-columns jsonb postgresql proctoru ruby-on-rails sql storext-attribute

Last synced: about 14 hours ago
JSON representation

Search PostgreSQL jsonb and hstore columns

Awesome Lists containing this project

README

        





Search PostgreSQL jsonb and hstore columns.


> Full database searching inside columns containing semi-structured data like `json`,
`jsonb` and `hstore`. Compatible with the awesome
storext gem
.

## Table of contents

- [Status](#status)
- [Quick start](#quick-start)
- [Performance](#performance)
- [Storext attributes](#storext-attributes)
- [Developing](#developing)
- [Contributors](#contributors)
- [Credits](#credits)

## Status
[![All Contributors](https://img.shields.io/badge/all_contributors-9-orange.svg?style=flat-square)](#contributors)
[![CircleCI](https://circleci.com/gh/ProctorU/squint.svg?style=svg)](https://circleci.com/gh/ProctorU/squint)

## Quick Start

Add to your Gemfile:

```ruby
gem 'squint'
```

Include it in your models:

```ruby
class Post < ActiveRecord::Base
include Squint
# ...
end
```

Assuming a table with the following structure:
```
Table "public.posts"
Column | Type | Modifiers
---------------------------+-----------------------------+----------------------------------------------------
id | integer | not null default nextval('posts_id_seq'::regclass)
title | character varying |
body | character varying |
request_info | jsonb |
properties | hstore |
storext_jsonb_attributes | jsonb |
storext_hstore_attributes | jsonb |
created_at | timestamp without time zone | not null
updated_at | timestamp without time zone | not null
Indexes:
"posts_pkey" PRIMARY KEY, btree (id)
```

In your code use queries like:
```ruby
Post.where(properties: { referer: 'http://example.com/one' } )
# SELECT "posts".* FROM "posts" WHERE "posts"."properties"->'referer' = 'http://example.com/one'

Post.where(properties: { referer: nil } )
# SELECT "posts".* FROM "posts" WHERE "posts"."properties"->'referer' IS NULL

Post.where(properties: { referer: ['http://example.com/one',nil] } )
# SELECT "posts".* FROM "posts" WHERE ("posts"."properties"->'referer' = 'http://example.com/one'
# OR "posts"."properties"->'referer' IS NULL)

Post.where(request_info: { referer: ['http://example.com/one',nil] } )
# SELECT "posts".* FROM "posts" WHERE ("posts"."request_info"->>'referer' = 'http://example.com/one'
# OR "posts"."request_info"->>'referer' IS NULL)
```

Squint only operates on json, jsonb and hstore columns. ActiveRecord
will throw a StatementInvalid exception like always if the column type is unsupported by
Squint.

```ruby
Post.where(title: { not_there: "any value will do" } )
```

```
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "title"
LINE 1: SELECT COUNT(*) FROM "posts" WHERE "title"."not_there" = 'an...
^
: SELECT COUNT(*) FROM "posts" WHERE "title"."not_there" = 'any value will do'
```

## Performance
To get the most performance out searching jsonb/hstore attributes, add a GIN (preferred) or
GIST index to those columns. Find out more
[here](https://www.postgresql.org/docs/9.5/static/textsearch-indexes.html)

TL;DR:

SQL: 'CREATE INDEX name ON table USING GIN (column);'

Rails Migration: `add_index(:table, :column_name, using: 'gin')`

## Storext attributes
Assuming the database schema above and a model like so:
```ruby
class Post < ActiveRecord::Base
include Storext.model
include Squint

store_attribute :storext_jsonb_attributes, :zip_code, String, default: '90210'
store_attribute :storext_jsonb_attributes, :friend_count, Integer, default: 0
end
```

Example using StoreXT with a default value:
```ruby
Post.where(storext_jsonb_attributes: { zip_code: '90210' } )
# -- jsonb
# SELECT "posts".* FROM "posts" WHERE ("posts"."storext_jsonb_attributes"->>'zip_code' = '90210' OR
# (("posts"."storext_jsonb_attributes" ? 'zip_code') IS NULL OR
# ("posts"."storext_jsonb_attributes" ? 'zip_code') = FALSE))
# -- hstore
# SELECT "posts".* FROM "posts" WHERE ("posts"."storext_hstore_attributes"->'zip_code' = '90210' OR
# ((exist("posts"."storext_hstore_attributes", 'zip_code') = FALSE) OR
# exist("posts"."storext_hstore_attributes", 'zip_code') IS NULL))
#
#
```
If (as in the example above) the default value for the StoreXT attribute is specified, then extra
checks for missing column ( `("posts"."storext_jsonb_attributes" ? 'zip_code') IS NULL` ) or
missing key ( `("posts"."storext_jsonb_attributes" ? 'zip_code') = FALSE)` ) are added

When non-default storext values are specified, these extra checks won't be added.

The Postgres SQL for jsonb and hstore is different. No support for checking for missing `json`
columns exists, so don't use those with StoreXT + Squint

## Developing

1. Thank you!
1. Clone the repository
1. `bundle`
1. `bundle exec rake --rakefile test/dummy/Rakefile db:setup` # create the db for tests
1. `bundle exec rake` # run the tests
1. make your changes in a thoughtfully named branch
1. ensure good test coverage
1. submit a Pull Request

## Contributors

Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):

| [
Kevin Brown](https://github.com/chevinbrown)
[🎨](#design-chevinbrown "Design") [👀](#review-chevinbrown "Reviewed Pull Requests") | [
Andrew Fomera](http://andrewfomera.com)
[👀](#review-king601 "Reviewed Pull Requests") [💻](https://github.com/ProctorU/squint/commits?author=king601 "Code") | [
Ryan T. Hosford](https://github.com/rthbound)
[💻](https://github.com/ProctorU/squint/commits?author=rthbound "Code") | [
Matthew Jaeh](https://github.com/Jaehdawg)
[🎨](#design-Jaehdawg "Design") [👀](#review-Jaehdawg "Reviewed Pull Requests") | [
Justin Licata](https://twitter.com/justinlicata)
[💻](https://github.com/ProctorU/squint/commits?author=licatajustin "Code") [🎨](#design-licatajustin "Design") [📖](https://github.com/ProctorU/squint/commits?author=licatajustin "Documentation") [👀](#review-licatajustin "Reviewed Pull Requests") | [
Kyle Miracle](https://github.com/kmiracle86)
[🐛](https://github.com/ProctorU/squint/issues?q=author%3Akmiracle86 "Bug reports") [👀](#review-kmiracle86 "Reviewed Pull Requests") | [
David H. Wilkins](http://conecuh.com)
[💬](#question-dwilkins "Answering Questions") [🐛](https://github.com/ProctorU/squint/issues?q=author%3Adwilkins "Bug reports") [💻](https://github.com/ProctorU/squint/commits?author=dwilkins "Code") [🎨](#design-dwilkins "Design") [📖](https://github.com/ProctorU/squint/commits?author=dwilkins "Documentation") [💡](#example-dwilkins "Examples") [👀](#review-dwilkins "Reviewed Pull Requests") [⚠️](https://github.com/ProctorU/squint/commits?author=dwilkins "Tests") |
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| [
Jay Wright](https://github.com/TheJayWright)
[👀](#review-TheJayWright "Reviewed Pull Requests") | [
James Cook](https://github.com/jamescook)
[💻](https://github.com/ProctorU/squint/commits?author=jamescook "Code") [⚠️](https://github.com/ProctorU/squint/commits?author=jamescook "Tests") [👀](#review-jamescook "Reviewed Pull Requests") |

This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!

## Credits

Squint is maintained and funded by [ProctorU](https://twitter.com/ProctorUEng).






ProctorU Engineering & Design


A simple online proctoring service that allows you to take exams or certification tests at home.