apiql 0.3.6 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 63b4f97269f59d36c635c7b748139aaa028ee54d39693d6f0f44e047448fbf50
4
- data.tar.gz: 2b349ebef9fc19be13bff57f40a3b35dbb9b87fd749087da5b57f2d853442c83
3
+ metadata.gz: 0df2f76cbbbf87e6a3b506c598a7e41ef620dc283ddc345cd157d2fc80661848
4
+ data.tar.gz: c6a9b1b1af21e094684ce86ea61f2a26f1f8432ed00f4657f8272429bea3df22
5
5
  SHA512:
6
- metadata.gz: ca5733013a1f7346c3ec80f9baab183694d8a2681a1f91d926c7827ae2d52014389a050d6ff5b3aefbec9da46e0bb28a5b89fc0d68cf318d62fa6f7e8baf03ea
7
- data.tar.gz: e6b7644edb288b4cf7f4b729706b292e4ca0aad43e251bf4862cb7024ccf15e12b60306616a0b9075ed3648209b6ff18ac41084dd7bb9968b1de680becb9b1e6
6
+ metadata.gz: b41c1af521d8feb114c107af996868d5d4a7ceaade3d20a4251c5881f8e54aeab5dbaf071c6a943650edaa00a21b066e9fea87b827bdbb9103d4a5fb128bab3c
7
+ data.tar.gz: 38d9b8b00bbf2cf92f940629b9fe76192aa1b702b5cf10364ba03d757c81eca0e5fbc21f3987391d08ea6ddb6ed4b2d5fe103e26a4bc59e9bbc216da8f834be8
data/README.md CHANGED
@@ -4,7 +4,7 @@ Implementation of the API language similar to GraphQL for Ruby on Rails.
4
4
 
5
5
  It compiles requests into Hashes for faster rendering.
6
6
 
7
- Now, it automatically detects nested entities and eager-loads them for faster DB access!
7
+ It automatically detects nested entities and eager-loads them for faster DB access!
8
8
 
9
9
  Define your responder (requested methods):
10
10
 
@@ -31,16 +31,16 @@ class UserAPIQL < ::APIQL
31
31
  end
32
32
 
33
33
  ```
34
- In controller or Grape API endpoint, handler of POST /user method:
34
+ In controller or Grape API endpoint, handler of POST /apiql method (or any other, see below APIQL.endpoint):
35
35
 
36
36
  ```ruby
37
- def user
37
+ def apiql
38
38
  schema = APIQL.cache(params)
39
39
  UserAPIQL.new(self, :session, :current_user, :params).render(schema)
40
40
  end
41
41
 
42
42
  ```
43
- variables `session`, `current_user` and `params` (you can list any you need) will be stored into context you can use in presenters and handlers
43
+ variables `session`, `current_user` and `params` (you can list any you need in your presenters/responders) will be stored into context you can use in presenters and handlers
44
44
 
45
45
  Define presenters for your models:
46
46
 
@@ -66,14 +66,14 @@ assets/javascripts/application.js:
66
66
 
67
67
  ```javascript
68
68
  //= require apiql
69
- APIQL.endpoint = "/"
69
+ APIQL.endpoint = "/apiql"
70
70
  ```
71
71
 
72
72
  ```javascript
73
- // function apiql(endpoint, schema, params = {}, form = null) -- schema is cached, so entire request is passed only for first time, later - short hashes only
73
+ // function apiql(schema, params = {}, form = null) -- schema is cached, so entire request is passed only for first time, later - short hashes only
74
74
 
75
75
  authenticate(email, password) {
76
- apiql("user", `
76
+ apiql(`
77
77
  logout()
78
78
 
79
79
  authenticate(email, password) {
@@ -88,7 +88,7 @@ authenticate(email, password) {
88
88
  }
89
89
  }
90
90
  `, {
91
- email: email, // these var will be passed into methods on the server side
91
+ email: email, // these vars will be passed into methods on the server side
92
92
  password: password
93
93
  })
94
94
  .then(response => { // response contains results of called methods
@@ -97,7 +97,7 @@ authenticate(email, password) {
97
97
  }
98
98
 
99
99
  logout() {
100
- apiql("user", `
100
+ apiql(`
101
101
  logout
102
102
  `)
103
103
  .then(response => {
@@ -109,12 +109,12 @@ logout() {
109
109
  you can call methods on entities:
110
110
 
111
111
  ```javascript
112
- apiql("user", `
112
+ apiql(`
113
113
  authenticate(email, password) {
114
114
  token
115
115
  }
116
116
 
117
- me.reload {
117
+ user: me.reload {
118
118
  email full_name role token
119
119
 
120
120
  roles(filter) {
@@ -132,7 +132,7 @@ you can call methods on entities:
132
132
  password: password
133
133
  })
134
134
  .then(response => {
135
- let user = response['me.reload'] // name in response equals to called
135
+ let user = response.user
136
136
  })
137
137
  }
138
138
  ```
@@ -143,12 +143,6 @@ config/initializers/apiql.rb:
143
143
 
144
144
  ```ruby
145
145
  class APIQL
146
- delegate :authorize!, to: :@context
147
-
148
- class Entity
149
- delegate :authorize!, to: :@context
150
- end
151
-
152
146
  class Context
153
147
  def authorize!(*args)
154
148
  ability.authorize!(*args)
@@ -182,3 +176,22 @@ class User < ApplicationRecord
182
176
  end
183
177
 
184
178
  ```
179
+
180
+ you can add CRUD methods for your models:
181
+
182
+ ```ruby
183
+ class UserAPIQL < ::APIQL
184
+ model ::User
185
+ model ::Role
186
+ end
187
+ ```
188
+
189
+ or mount methods from external modules:
190
+
191
+ ```ruby
192
+ class UserAPIQL < ::APIQL
193
+ mount ::Services::User # all methouds could be called with "user" prefix like "user.logout()"
194
+ mount ::Services::Common, as: '' # all methods could be called without prefixes
195
+ mount ::Services::Employer, as: 'dashboard" # all methods could be called with specified prefix
196
+ end
197
+ ```
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = 'apiql'
7
- spec.version = '0.3.6'
7
+ spec.version = '0.4.0'
8
8
  spec.authors = ['Dmitry Silchenko']
9
9
  spec.email = ['dmitry@desofto.com']
10
10
 
@@ -13,7 +13,7 @@ const APIQL = {
13
13
  return hash
14
14
  },
15
15
 
16
- call(endpoint, schema, params = {}, form = null) {
16
+ call(schema, params = {}, form = null) {
17
17
  return new Promise((resolve, reject) => {
18
18
  if(params instanceof FormData) {
19
19
  form = params
@@ -32,7 +32,7 @@ const APIQL = {
32
32
  params.apiql = this.hash(schema)
33
33
  }
34
34
 
35
- Vue.http.post(`${APIQL.endpoint}${endpoint}`, form || params)
35
+ Vue.http.post(APIQL.endpoint, form || params)
36
36
  .then(response => {
37
37
  resolve(response.body)
38
38
  })
@@ -50,7 +50,7 @@ const APIQL = {
50
50
  params.apiql_request = schema
51
51
  }
52
52
 
53
- Vue.http.post(`${APIQL.endpoint}${endpoint}`, form || params)
53
+ Vue.http.post(APIQL.endpoint, form || params)
54
54
  .then(response => {
55
55
  resolve(response.body)
56
56
  })
@@ -66,6 +66,6 @@ const APIQL = {
66
66
  }
67
67
  }
68
68
 
69
- function apiql(endpoint, schema, params = {}, form = null) {
70
- return APIQL.call(endpoint, schema, params, form)
69
+ function apiql(schema, params = {}, form = null) {
70
+ return APIQL.call(schema, params, form)
71
71
  }
@@ -7,12 +7,90 @@ class APIQL
7
7
  end
8
8
  end
9
9
 
10
+ module CRUD
11
+ def model(klass)
12
+ define_method "#{klass.name.pluralize.underscore}" do |page = nil, page_size = 10|
13
+ authorize! :read, klass
14
+
15
+ if page.present?
16
+ {
17
+ total: klass.count,
18
+ items: klass.offset(page * page_size).limit(page_size)
19
+ }
20
+ else
21
+ klass.all
22
+ end
23
+ end
24
+
25
+ define_method "#{klass.name.underscore}" do |id|
26
+ item = klass.find(id)
27
+
28
+ authorize! :read, item
29
+
30
+ item
31
+ end
32
+
33
+ define_method "#{klass.name.underscore}.create" do |params|
34
+ authorize! :create, klass
35
+
36
+ klass_entity = "#{klass.name}::Entity".constantize
37
+
38
+ if klass_entity.respond_to?(:create_params, params)
39
+ params = klass_entity.send(:create_params, params)
40
+ elsif klass_entity.respond_to?(:params, params)
41
+ params = klass_entity.send(:params, params)
42
+ end
43
+
44
+ klass.create!(params)
45
+ end
46
+
47
+ define_method "#{klass.name.underscore}.update" do |id, params|
48
+ item = klass.find(id)
49
+
50
+ authorize! :update, item
51
+
52
+ klass_entity = "#{klass.name}::Entity".constantize
53
+
54
+ if klass_entity.respond_to?(:update_params, params)
55
+ params = klass_entity.send(:update_params, params)
56
+ elsif klass_entity.respond_to?(:params, params)
57
+ params = klass_entity.send(:params, params)
58
+ end
59
+
60
+ item.update!(params)
61
+ end
62
+
63
+ define_method "#{klass.name.underscore}.destroy" do |id|
64
+ item = klass.find(id)
65
+
66
+ authorize! :destroy, item
67
+
68
+ item.destroy!
69
+ end
70
+ end
71
+ end
72
+
10
73
  class Error < StandardError; end
11
74
  class CacheMissed < StandardError; end
12
75
 
13
76
  attr_reader :context
77
+ delegate :authorize!, to: :@context
14
78
 
15
79
  class << self
80
+ include ::APIQL::CRUD
81
+
82
+ def mount(klass, as: nil)
83
+ as ||= klass.name.split('::').last.underscore
84
+ as += '.' if as.present?
85
+
86
+ klass.instance_methods(false).each do |method|
87
+ klass.alias_method("#{as}#{method}", method)
88
+ klass.remove_method(method) if as.present?
89
+ end
90
+
91
+ include klass
92
+ end
93
+
16
94
  @@cache = {}
17
95
 
18
96
  def cache(params)
@@ -185,6 +263,8 @@ class APIQL
185
263
  private
186
264
 
187
265
  class Entity
266
+ delegate :authorize!, to: :@context
267
+
188
268
  class << self
189
269
  attr_reader :apiql_attributes
190
270
 
@@ -350,6 +430,8 @@ class APIQL
350
430
  end
351
431
  end
352
432
 
433
+ def authorize!(*args); end
434
+
353
435
  def inject_delegators(target)
354
436
  @fields.each do |field|
355
437
  target.class_eval do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apiql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.6
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Silchenko
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-07-26 00:00:00.000000000 Z
11
+ date: 2018-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler