apiql 0.3.6 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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