Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
Arkweid committed Nov 4, 2018
0 parents commit f890cf2
Show file tree
Hide file tree
Showing 25 changed files with 844 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .gitignore
@@ -0,0 +1,12 @@
/.bundle/
/.yardoc
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/

.rspec_status
.rspec
.byebug_history
3 changes: 3 additions & 0 deletions .rspec
@@ -0,0 +1,3 @@
--format documentation
--color
--require spec_helper
46 changes: 46 additions & 0 deletions .rubocop.yml
@@ -0,0 +1,46 @@
AllCops:
Include:
- 'lib/**/*.rb'
- 'lib/**/*.rake'
- 'spec/**/*.rb'
Exclude:
- 'bin/**/*'
- 'Rakefile'
- '*.gemspec'
DisplayCopNames: true
StyleGuideCopsOnly: false
TargetRubyVersion: 2.5.1

Rails:
Enabled: false

Style/Documentation:
Exclude:
- 'spec/**/*.rb'

Layout/SpaceInsideStringInterpolation:
EnforcedStyle: no_space

Style/BlockDelimiters:
Exclude:
- 'spec/**/*.rb'

Metrics/MethodLength:
Exclude:
- 'spec/**/*.rb'

Metrics/LineLength:
Max: 120
Exclude:
- 'spec/**/*.rb'

Metrics/AbcSize:
Exclude:
- 'spec/**/*.rb'

Metrics/BlockLength:
Exclude:
- 'spec/**/*.rb'

Lint/HandleExceptions:
Enabled: false
7 changes: 7 additions & 0 deletions .travis.yml
@@ -0,0 +1,7 @@
---
sudo: false
language: ruby
cache: bundler
rvm:
- 2.5.1
before_install: gem install bundler -v 1.16.6
Empty file added CHANGELOG.md
Empty file.
5 changes: 5 additions & 0 deletions Gemfile
@@ -0,0 +1,5 @@
source 'https://rubygems.org'

git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }

gemspec
61 changes: 61 additions & 0 deletions Gemfile.lock
@@ -0,0 +1,61 @@
PATH
remote: .
specs:
graphql-smart_select (0.1.0)
graphql

GEM
remote: https://rubygems.org/
specs:
activemodel (5.2.1)
activesupport (= 5.2.1)
activerecord (5.2.1)
activemodel (= 5.2.1)
activesupport (= 5.2.1)
arel (>= 9.0)
activesupport (5.2.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
arel (9.0.0)
byebug (10.0.2)
concurrent-ruby (1.0.5)
diff-lcs (1.3)
graphql (1.8.11)
i18n (1.1.1)
concurrent-ruby (~> 1.0)
minitest (5.11.3)
rake (10.5.0)
rspec (3.8.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
rspec-mocks (~> 3.8.0)
rspec-core (3.8.0)
rspec-support (~> 3.8.0)
rspec-expectations (3.8.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-mocks (3.8.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-support (3.8.0)
sqlite3 (1.3.13)
thread_safe (0.3.6)
tzinfo (1.2.5)
thread_safe (~> 0.1)

PLATFORMS
ruby

DEPENDENCIES
activerecord (~> 5.2)
bundler (~> 1.16)
byebug (~> 10.0)
graphql-smart_select!
rake (~> 10.0)
rspec (~> 3.0)
sqlite3 (~> 1.3, >= 1.3.13)

BUNDLED WITH
1.16.6
21 changes: 21 additions & 0 deletions LICENSE.txt
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2018 Alexander Abroskin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
106 changes: 106 additions & 0 deletions README.md
@@ -0,0 +1,106 @@
# Graphql::Smartselect

Plugin for [graphql-ruby](https://github.com/rmosolgo/graphql-ruby) which helps to select only the required fields from the database.

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'graphql-smart_select'
```

## Problem explanation

Consider the following query:
```
query {
posts {
id
title
}
}
```

Ruby interface for serve this query:
```ruby
module GraphqlAPI
module Types
class Query < GraphQL::Schema::Object
field :posts, Types::Post, null: false

def posts
Post.all
end
end
end
end
```
In the default case, this will lead to the query: ```SELECT * FROM posts```. But we need only ```id``` and ```title```.
For tables with a large number of columns, this has a negative effect on performance.

## Usage

Let's use our plugin:
```ruby
module GraphqlAPI
module Types
class Query < GraphQL::Schema::Object
# use plugin
field_class.prepend(GraphQL::SmartSelect)

# activate plugin
field :posts, Types::Post, null: false, smart_select: true

# You can also explicitly specify which fields
# will be added
field :posts, Types::Post, null: false, smart_select: [:id]

def posts
Post.all
end
end

class Post < GraphQL::Schema::Object
field_class.prepend(GraphQL::SmartSelect)

field :id, ID
field :title, String
field :raw_content, String
field :another_content, String

# We'll tell the plugin which fields are needed
# for resolve this field
field :contents, db_columns: [:raw_content, :another_content]

# For one_to_one AR assosiation we include foreign_key
field :user, Types::User

# For has_many AR assosiation we include primary_key
field :comments, [Types::Comment]

def contents
[object.id, object.title].join
end
end
end
end
```

For this example query:
```
query {
posts {
title
contents
user { name }
comments { id }
}
}
```
It perform following request:
```SELECT id, title, raw_content, another_content, user_id FROM posts```

## License

The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
6 changes: 6 additions & 0 deletions Rakefile
@@ -0,0 +1,6 @@
require 'bundler/gem_tasks'
require 'rspec/core/rake_task'

RSpec::Core::RakeTask.new(:spec)

task default: :spec
14 changes: 14 additions & 0 deletions bin/console
@@ -0,0 +1,14 @@
#!/usr/bin/env ruby

require 'bundler/setup'
require 'graphql/smart_select'

# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.

# (If you use this, don't forget to add pry to your Gemfile!)
# require "pry"
# Pry.start

require 'irb'
IRB.start(__FILE__)
8 changes: 8 additions & 0 deletions bin/setup
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx

bundle install

# Do any other automated setup that you need to do here
33 changes: 33 additions & 0 deletions graphql-smart_select.gemspec
@@ -0,0 +1,33 @@
# frozen_string_literal: true

lib = File.expand_path('lib', __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'graphql/smart_select/version'

Gem::Specification.new do |spec|
spec.name = 'graphql-smart_select'
spec.version = GraphQL::SmartSelect::VERSION
spec.authors = ['Alexander Abroskin']
spec.email = ['a.a.abroskin@yandex.ru']

spec.summary = 'Plugin for graphql-ruby gem'
spec.description = 'Provide logic for select only required fields for query'
spec.homepage = 'https://github.com/Arkweid/graphql-smart_select'
spec.license = 'MIT'

spec.required_ruby_version = '>= 2.2.0'

spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR).select { |p| p.match(%r{^lib/}) } +
%w[README.md CHANGELOG.md LICENSE.txt]

spec.require_paths = ['lib']

spec.add_runtime_dependency 'graphql'

spec.add_development_dependency 'activerecord', '~> 5.2'
spec.add_development_dependency 'bundler', '~> 1.16'
spec.add_development_dependency 'byebug', '~> 10.0'
spec.add_development_dependency 'rake', '~> 10.0'
spec.add_development_dependency 'rspec', '~> 3.0'
spec.add_development_dependency 'sqlite3', '~> 1.3', '>= 1.3.13'
end
29 changes: 29 additions & 0 deletions lib/graphql/smart_select.rb
@@ -0,0 +1,29 @@
# frozen_string_literal: true

require 'graphql/smart_select/version'
require 'graphql/smart_select/resolver'

module GraphQL
#
# Apply additional scope to the AR query
# which selects only the required fields
#
module SmartSelect
def initialize(*args, **kwargs, &block)
@smart_select = kwargs.delete(:smart_select)
@db_columns = kwargs.delete(:db_columns)
super
end

private

def apply_scope(value, ctx)
if @smart_select && value.is_a?(ActiveRecord::Relation)
fields_for_select = Resolver.new(value, ctx, @smart_select, @db_columns).resolve

value = ctx.schema.after_lazy(value) { |inner_value| inner_value.select(fields_for_select) }
end
super
end
end
end

0 comments on commit f890cf2

Please sign in to comment.