appquery 0.7.0.rc3 → 0.7.0.rc4

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: b8cd0e15eb5369cdc045b147a86ad399c46d3db98788466ca97c34aad3ffdbff
4
- data.tar.gz: '09bc151be68fb86f52be75f0cb39c8574230f36df041106ca6ee360f8952c08b'
3
+ metadata.gz: 7a14a392efa76c538933b7e3a41ded16c0b424411401fe6bfbba25e04fdd5d58
4
+ data.tar.gz: '090b6b2dc6fc90bad886bcf204112e96375bac828aa940d275deed236a74956e'
5
5
  SHA512:
6
- metadata.gz: 5bca51f56f82a9e89a9d3e958f380845841c9da122e748cc89e0c67d55397d63d529f511f5ffe255ce905c0895d0a911f9df9e943a452d1ef8c8a83240d727c4
7
- data.tar.gz: 29e39bca885b03ef0e54a6c68e803b8819e24baedb85e7dcd0b1c6a13c9496b97fe9cce98555653e9eeebb6a9cbb82188ab3d078243f0f8d3bfcdedc2797633a
6
+ metadata.gz: ba9661f71020f4d1925f7ed059831017b0f4348049a3146be3a5a94ba78199006f99ebde72a38f6da31a172a677402663cbacdbfab03f72ec837fe29a5ea9162
7
+ data.tar.gz: e603c2c8b6cdb2bed56bdfc52ee568d5065c30e291e91c154dd4e9dccc35068493dde970682515f9566d8a7e313f3ac9dfbf6fd401af5a01089d29fbb393cd6b
@@ -0,0 +1,399 @@
1
+ window.__app = function () {
2
+ var localStorage = {},
3
+ sessionStorage = {};
4
+ try {
5
+ localStorage = window.localStorage;
6
+ } catch (e) {}
7
+ try {
8
+ sessionStorage = window.sessionStorage;
9
+ } catch (e) {}
10
+
11
+ function createSourceLinks() {
12
+ $(".method_details_list .source_code").before(
13
+ "<span class='showSource'>[<a href='#' class='toggleSource'>View source</a>]</span>"
14
+ );
15
+ $(".toggleSource").toggle(
16
+ function () {
17
+ $(this).parent().nextAll(".source_code").slideDown(100);
18
+ $(this).text("Hide source");
19
+ },
20
+ function () {
21
+ $(this).parent().nextAll(".source_code").slideUp(100);
22
+ $(this).text("View source");
23
+ }
24
+ );
25
+ }
26
+
27
+ function createDefineLinks() {
28
+ var tHeight = 0;
29
+ $(".defines").after(" <a href='#' class='toggleDefines'>more...</a>");
30
+ $(".toggleDefines").toggle(
31
+ function () {
32
+ tHeight = $(this).parent().prev().height();
33
+ $(this).prev().css("display", "inline");
34
+ $(this).parent().prev().height($(this).parent().height());
35
+ $(this).text("(less)");
36
+ },
37
+ function () {
38
+ $(this).prev().hide();
39
+ $(this).parent().prev().height(tHeight);
40
+ $(this).text("more...");
41
+ }
42
+ );
43
+ }
44
+
45
+ function createFullTreeLinks() {
46
+ var tHeight = 0;
47
+ $(".inheritanceTree").toggle(
48
+ function () {
49
+ tHeight = $(this).parent().prev().height();
50
+ $(this).parent().toggleClass("showAll");
51
+ $(this).text("(hide)");
52
+ $(this).parent().prev().height($(this).parent().height());
53
+ },
54
+ function () {
55
+ $(this).parent().toggleClass("showAll");
56
+ $(this).parent().prev().height(tHeight);
57
+ $(this).text("show all");
58
+ }
59
+ );
60
+ }
61
+
62
+ function searchFrameButtons() {
63
+ $(".full_list_link").click(function () {
64
+ toggleSearchFrame(this, $(this).attr("href"));
65
+ return false;
66
+ });
67
+ window.addEventListener("message", function (e) {
68
+ if (e.data === "navEscape") {
69
+ $("#nav").slideUp(100);
70
+ $("#search a").removeClass("active inactive");
71
+ $(window).focus();
72
+ }
73
+ });
74
+
75
+ $(window).resize(function () {
76
+ if ($("#search:visible").length === 0) {
77
+ $("#nav").removeAttr("style");
78
+ $("#search a").removeClass("active inactive");
79
+ $(window).focus();
80
+ }
81
+ });
82
+ }
83
+
84
+ function toggleSearchFrame(id, link) {
85
+ var frame = $("#nav");
86
+ $("#search a").removeClass("active").addClass("inactive");
87
+ if (frame.attr("src") === link && frame.css("display") !== "none") {
88
+ frame.slideUp(100);
89
+ $("#search a").removeClass("active inactive");
90
+ } else {
91
+ $(id).addClass("active").removeClass("inactive");
92
+ if (frame.attr("src") !== link) frame.attr("src", link);
93
+ frame.slideDown(100);
94
+ }
95
+ }
96
+
97
+ function linkSummaries() {
98
+ $(".summary_signature").click(function () {
99
+ document.location = $(this).find("a").attr("href");
100
+ });
101
+ }
102
+
103
+ function summaryToggle() {
104
+ $(".summary_toggle").click(function (e) {
105
+ e.preventDefault();
106
+ localStorage.summaryCollapsed = $(this).text();
107
+ $(".summary_toggle").each(function () {
108
+ $(this).text($(this).text() == "collapse" ? "expand" : "collapse");
109
+ var next = $(this).parent().parent().nextAll("ul.summary").first();
110
+ if (next.hasClass("compact")) {
111
+ next.toggle();
112
+ next.nextAll("ul.summary").first().toggle();
113
+ } else if (next.hasClass("summary")) {
114
+ var list = $('<ul class="summary compact" />');
115
+ list.html(next.html());
116
+ list.find(".summary_desc, .note").remove();
117
+ list.find("a").each(function () {
118
+ $(this).html($(this).find("strong").html());
119
+ $(this).parent().html($(this)[0].outerHTML);
120
+ });
121
+ next.before(list);
122
+ next.toggle();
123
+ }
124
+ });
125
+ return false;
126
+ });
127
+ if (localStorage.summaryCollapsed == "collapse") {
128
+ $(".summary_toggle").first().click();
129
+ } else {
130
+ localStorage.summaryCollapsed = "expand";
131
+ }
132
+ }
133
+
134
+ function constantSummaryToggle() {
135
+ $(".constants_summary_toggle").click(function (e) {
136
+ e.preventDefault();
137
+ localStorage.summaryCollapsed = $(this).text();
138
+ $(".constants_summary_toggle").each(function () {
139
+ $(this).text($(this).text() == "collapse" ? "expand" : "collapse");
140
+ var next = $(this).parent().parent().nextAll("dl.constants").first();
141
+ if (next.hasClass("compact")) {
142
+ next.toggle();
143
+ next.nextAll("dl.constants").first().toggle();
144
+ } else if (next.hasClass("constants")) {
145
+ var list = $('<dl class="constants compact" />');
146
+ list.html(next.html());
147
+ list.find("dt").each(function () {
148
+ $(this).addClass("summary_signature");
149
+ $(this).text($(this).text().split("=")[0]);
150
+ if ($(this).has(".deprecated").length) {
151
+ $(this).addClass("deprecated");
152
+ }
153
+ });
154
+ // Add the value of the constant as "Tooltip" to the summary object
155
+ list.find("pre.code").each(function () {
156
+ var dt_element = $(this).parent().prev();
157
+ var tooltip = $(this).text();
158
+ if (dt_element.hasClass("deprecated")) {
159
+ tooltip = "Deprecated. " + tooltip;
160
+ }
161
+ dt_element.attr("title", tooltip);
162
+ });
163
+ list.find(".docstring, .tags, dd").remove();
164
+ next.before(list);
165
+ next.toggle();
166
+ }
167
+ });
168
+ return false;
169
+ });
170
+ if (localStorage.summaryCollapsed == "collapse") {
171
+ $(".constants_summary_toggle").first().click();
172
+ } else {
173
+ localStorage.summaryCollapsed = "expand";
174
+ }
175
+ }
176
+
177
+ function generateTOC() {
178
+ if ($("#filecontents").length === 0) return;
179
+ var _toc = $('<ol class="top"></ol>');
180
+ var show = false;
181
+ var toc = _toc;
182
+ var counter = 0;
183
+ var tags = ["h2", "h3", "h4", "h5", "h6"];
184
+ var i;
185
+ var curli;
186
+ if ($("#filecontents h1").length > 1) tags.unshift("h1");
187
+ for (i = 0; i < tags.length; i++) {
188
+ tags[i] = "#filecontents " + tags[i];
189
+ }
190
+ var lastTag = parseInt(tags[0][1], 10);
191
+ $(tags.join(", ")).each(function () {
192
+ if ($(this).parents(".method_details .docstring").length != 0) return;
193
+ if (this.id == "filecontents") return;
194
+ show = true;
195
+ var thisTag = parseInt(this.tagName[1], 10);
196
+ if (this.id.length === 0) {
197
+ var proposedId = $(this).attr("toc-id");
198
+ if (typeof proposedId != "undefined") this.id = proposedId;
199
+ else {
200
+ var proposedId = $(this)
201
+ .text()
202
+ .replace(/[^a-z0-9-]/gi, "_");
203
+ if ($("#" + proposedId).length > 0) {
204
+ proposedId += counter;
205
+ counter++;
206
+ }
207
+ this.id = proposedId;
208
+ }
209
+ }
210
+ if (thisTag > lastTag) {
211
+ for (i = 0; i < thisTag - lastTag; i++) {
212
+ if (typeof curli == "undefined") {
213
+ curli = $("<li/>");
214
+ toc.append(curli);
215
+ }
216
+ toc = $("<ol/>");
217
+ curli.append(toc);
218
+ curli = undefined;
219
+ }
220
+ }
221
+ if (thisTag < lastTag) {
222
+ for (i = 0; i < lastTag - thisTag; i++) {
223
+ toc = toc.parent();
224
+ toc = toc.parent();
225
+ }
226
+ }
227
+ var title = $(this).attr("toc-title");
228
+ if (typeof title == "undefined") title = $(this).text();
229
+ curli = $('<li><a href="#' + this.id + '">' + title + "</a></li>");
230
+ toc.append(curli);
231
+ lastTag = thisTag;
232
+ });
233
+ if (!show) return;
234
+ html =
235
+ '<div id="toc"><p class="title hide_toc"><a href="#"><strong>Table of Contents</strong></a></p></div>';
236
+ $("#content").prepend(html);
237
+ $("#toc").append(_toc);
238
+ $("#toc .hide_toc").toggle(
239
+ function () {
240
+ $("#toc .top").slideUp("fast");
241
+ $("#toc").toggleClass("hidden");
242
+ $("#toc .title small").toggle();
243
+ },
244
+ function () {
245
+ $("#toc .top").slideDown("fast");
246
+ $("#toc").toggleClass("hidden");
247
+ $("#toc .title small").toggle();
248
+ }
249
+ );
250
+ }
251
+
252
+ function navResizer() {
253
+ const resizer = document.getElementById("resizer");
254
+ resizer.addEventListener(
255
+ "pointerdown",
256
+ function (e) {
257
+ resizer.setPointerCapture(e.pointerId);
258
+ e.preventDefault();
259
+ e.stopPropagation();
260
+ },
261
+ false
262
+ );
263
+ resizer.addEventListener(
264
+ "pointerup",
265
+ function (e) {
266
+ resizer.releasePointerCapture(e.pointerId);
267
+ e.preventDefault();
268
+ e.stopPropagation();
269
+ },
270
+ false
271
+ );
272
+ resizer.addEventListener(
273
+ "pointermove",
274
+ function (e) {
275
+ if ((e.buttons & 1) === 0) {
276
+ return;
277
+ }
278
+
279
+ sessionStorage.navWidth = e.pageX.toString();
280
+ $(".nav_wrap").css("width", Math.max(200, e.pageX));
281
+ e.preventDefault();
282
+ e.stopPropagation();
283
+ },
284
+ false
285
+ );
286
+
287
+ if (sessionStorage.navWidth) {
288
+ $(".nav_wrap").css(
289
+ "width",
290
+ Math.max(200, parseInt(sessionStorage.navWidth, 10))
291
+ );
292
+ }
293
+ }
294
+
295
+ function navExpander() {
296
+ if (typeof pathId === "undefined") return;
297
+ var done = false,
298
+ timer = setTimeout(postMessage, 500);
299
+ function postMessage() {
300
+ if (done) return;
301
+ clearTimeout(timer);
302
+ var opts = { action: "expand", path: pathId };
303
+ document.getElementById("nav").contentWindow.postMessage(opts, "*");
304
+ done = true;
305
+ }
306
+ }
307
+
308
+ function mainFocus() {
309
+ var hash = window.location.hash;
310
+ if (hash !== "" && $(hash)[0]) {
311
+ $(hash)[0].scrollIntoView();
312
+ }
313
+
314
+ setTimeout(function () {
315
+ $("#main").focus();
316
+ }, 10);
317
+ }
318
+
319
+ function navigationChange() {
320
+ // This works around the broken anchor navigation with the YARD template.
321
+ window.onpopstate = function () {
322
+ var hash = window.location.hash;
323
+ if (hash !== "" && $(hash)[0]) {
324
+ $(hash)[0].scrollIntoView();
325
+ }
326
+ };
327
+ }
328
+
329
+ $(document).ready(function () {
330
+ navResizer();
331
+ navExpander();
332
+ createSourceLinks();
333
+ createDefineLinks();
334
+ createFullTreeLinks();
335
+ searchFrameButtons();
336
+ linkSummaries();
337
+ summaryToggle();
338
+ constantSummaryToggle();
339
+ generateTOC();
340
+ mainFocus();
341
+ navigationChange();
342
+ });
343
+ };
344
+ window.__app();
345
+
346
+ window.addEventListener(
347
+ "message",
348
+ async (e) => {
349
+ if (e.data.action === "navigate") {
350
+ // Fix: resolve URL relative to the iframe's base (root), not current page
351
+ const nav = document.getElementById("nav");
352
+ const baseUrl = new URL(nav.src, window.location.href).href.replace(/[^/]*$/, '');
353
+ const absoluteUrl = new URL(e.data.url, baseUrl).href;
354
+ const response = await fetch(absoluteUrl);
355
+ const text = await response.text();
356
+ const parser = new DOMParser();
357
+ const doc = parser.parseFromString(text, "text/html");
358
+
359
+ const classListLink =
360
+ document.getElementById("class_list_link").classList;
361
+
362
+ const content = doc.querySelector("#main").innerHTML;
363
+ document.querySelector("#main").innerHTML = content;
364
+ document.title = doc.head.querySelector("title").innerText;
365
+ document.head.querySelectorAll("script").forEach((script) => {
366
+ if (
367
+ !script.type ||
368
+ (script.type.includes("text/javascript") && !script.src)
369
+ ) {
370
+ script.remove();
371
+ }
372
+ });
373
+
374
+ doc.head.querySelectorAll("script").forEach((script) => {
375
+ if (
376
+ !script.type ||
377
+ (script.type.includes("text/javascript") && !script.src)
378
+ ) {
379
+ const newScript = document.createElement("script");
380
+ newScript.type = "text/javascript";
381
+ newScript.textContent = script.textContent;
382
+ document.head.appendChild(newScript);
383
+ }
384
+ });
385
+
386
+ window.__app();
387
+
388
+ document.getElementById("class_list_link").classList = classListLink;
389
+
390
+ const url = new URL(e.data.url, "https://localhost");
391
+ const hash = decodeURIComponent(url.hash ?? "");
392
+ if (hash) {
393
+ document.getElementById(hash.substring(1)).scrollIntoView();
394
+ }
395
+ history.pushState({}, document.title, absoluteUrl);
396
+ }
397
+ },
398
+ false
399
+ );
@@ -9,42 +9,46 @@ module AppQuery
9
9
  # BaseQuery provides a structured way to work with SQL queries compared to
10
10
  # using `AppQuery[:my_query]` directly.
11
11
  #
12
+ # @see Paginatable Middleware for pagination support
13
+ # @see Mappable Middleware for mapping results to objects
14
+ #
12
15
  # ## Benefits over AppQuery[:my_query]
13
16
  #
14
17
  # ### 1. Explicit parameter declaration
15
18
  # Declare required binds and vars upfront with defaults:
16
19
  #
17
- # class ArticlesQuery < AppQuery::BaseQuery
18
- # bind :author_id # required
19
- # bind :status, default: nil # optional
20
- # var :order_by, default: "created_at DESC"
21
- # end
20
+ # class ArticlesQuery < AppQuery::BaseQuery
21
+ # bind :author_id # required
22
+ # bind :status, default: nil # optional
23
+ # var :order_by, default: "created_at DESC"
24
+ # end
22
25
  #
23
26
  # ### 2. Unknown parameter validation
24
27
  # Raises ArgumentError for typos or unknown parameters:
25
28
  #
26
- # ArticlesQuery.new(athor_id: 1) # => ArgumentError: Unknown param(s): athor_id
29
+ # ArticlesQuery.new(athor_id: 1)
30
+ # # => ArgumentError: Unknown param(s): athor_id
27
31
  #
28
32
  # ### 3. Self-documenting queries
29
33
  # Query classes show exactly what parameters are available:
30
34
  #
31
- # ArticlesQuery.binds # => {author_id: {default: nil}, status: {default: nil}}
32
- # ArticlesQuery.vars # => {order_by: {default: "created_at DESC"}}
35
+ # ArticlesQuery.binds # => {author_id: {default: nil}, ...}
36
+ # ArticlesQuery.vars # => {order_by: {default: "created_at DESC"}}
33
37
  #
34
38
  # ### 4. Middleware support
35
39
  # Include concerns to add functionality:
36
40
  #
37
- # class ApplicationQuery < AppQuery::BaseQuery
38
- # include AppQuery::Paginatable
39
- # include AppQuery::Mappable
40
- # end
41
+ # class ApplicationQuery < AppQuery::BaseQuery
42
+ # include AppQuery::Paginatable
43
+ # include AppQuery::Mappable
44
+ # end
41
45
  #
42
46
  # ### 5. Casts
43
47
  # Define casts for columns:
44
48
  #
45
- # class ApplicationQuery < AppQuery::BaseQuery
46
- # cast metadata: :json
47
- # end
49
+ # class ApplicationQuery < AppQuery::BaseQuery
50
+ # cast metadata: :json
51
+ # end
48
52
  #
49
53
  # ## Parameter types
50
54
  #
@@ -57,15 +61,13 @@ module AppQuery
57
61
  # - `ArticlesQuery` -> `articles.sql.erb`
58
62
  # - `Reports::MonthlyQuery` -> `reports/monthly.sql.erb`
59
63
  #
60
- # ## Example
61
- #
62
- # # app/queries/articles.sql.erb
64
+ # @example SQL template (app/queries/articles.sql.erb)
63
65
  # SELECT * FROM articles
64
66
  # WHERE author_id = :author_id
65
67
  # <% if @status %>AND status = :status<% end %>
66
68
  # ORDER BY <%= @order_by %>
67
69
  #
68
- # # app/queries/articles_query.rb
70
+ # @example Query class (app/queries/articles_query.rb)
69
71
  # class ArticlesQuery < AppQuery::BaseQuery
70
72
  # bind :author_id
71
73
  # bind :status, default: nil
@@ -73,7 +75,7 @@ module AppQuery
73
75
  # cast published_at: :datetime
74
76
  # end
75
77
  #
76
- # # Usage
78
+ # @example Usage
77
79
  # ArticlesQuery.new(author_id: 1).entries
78
80
  # ArticlesQuery.new(author_id: 1, status: "draft", order_by: "title").first
79
81
  #
@@ -3,10 +3,19 @@
3
3
  require "active_support/concern"
4
4
 
5
5
  module AppQuery
6
- # Maps query results to Ruby objects (e.g., Data classes, Structs).
6
+ # Middleware concern that maps query results to Ruby objects in {BaseQuery} subclasses.
7
7
  #
8
- # By default, looks for an `Item` constant in the query class.
9
- # Use `map_to` to specify a different class.
8
+ # Include this module to automatically convert result hashes into typed objects
9
+ # like +Data+ classes or +Struct+s.
10
+ #
11
+ # By default, looks for an +Item+ constant in the query class.
12
+ # Use +map_to+ to specify a different class.
13
+ #
14
+ # @note This is a {BaseQuery} middleware. Include it in classes that inherit
15
+ # from {BaseQuery} to transform hash results into typed objects.
16
+ #
17
+ # @see BaseQuery Base class for query objects
18
+ # @see Paginatable Another middleware for pagination support
10
19
  #
11
20
  # @example With default Item class
12
21
  # class ArticlesQuery < ApplicationQuery
@@ -31,6 +40,18 @@ module AppQuery
31
40
  # @example Skip mapping with raw
32
41
  # articles = ArticlesQuery.new.raw.entries
33
42
  # articles.first # => {"title" => "Hello", "url" => "..."}
43
+ #
44
+ # @example Combining with Paginatable
45
+ # class ArticlesQuery < ApplicationQuery
46
+ # include AppQuery::Paginatable
47
+ # include AppQuery::Mappable
48
+ #
49
+ # class Item < Data.define(:title, :url)
50
+ # end
51
+ # end
52
+ #
53
+ # # Results are paginated AND mapped to Item objects
54
+ # ArticlesQuery.new.paginate(page: 1).entries.first.title
34
55
  module Mappable
35
56
  extend ActiveSupport::Concern
36
57
 
@@ -3,13 +3,20 @@
3
3
  require "active_support/concern"
4
4
 
5
5
  module AppQuery
6
- # Adds pagination support to query classes.
6
+ # Middleware concern that adds pagination support to {BaseQuery} subclasses.
7
+ #
8
+ # Include this module in your query class to enable pagination with
9
+ # Kaminari-compatible result objects.
7
10
  #
8
11
  # Provides two modes:
9
12
  # - **With count**: Full pagination with page numbers (uses COUNT query)
10
13
  # - **Without count**: Simple prev/next for large datasets (uses limit+1 trick)
11
14
  #
12
- # Compatible with Kaminari view helpers.
15
+ # @note This is a {BaseQuery} middleware. Include it in classes that inherit
16
+ # from {BaseQuery} and use the +paginate+ ERB helper in your SQL template.
17
+ #
18
+ # @see BaseQuery Base class for query objects
19
+ # @see Mappable Another middleware for mapping results to objects
13
20
  #
14
21
  # @example Basic usage
15
22
  # class ApplicationQuery < AppQuery::BaseQuery
@@ -29,6 +36,12 @@ module AppQuery
29
36
  # # Without count (large datasets)
30
37
  # articles = ArticlesQuery.new.paginate(page: 1, without_count: true).entries
31
38
  # articles.next_page # => 2 (or nil if last page)
39
+ #
40
+ # @example SQL template with pagination
41
+ # -- app/queries/articles.sql
42
+ # SELECT * FROM articles
43
+ # ORDER BY published_on DESC
44
+ # <%= paginate(page: page, per_page: per_page) %>
32
45
  module Paginatable
33
46
  extend ActiveSupport::Concern
34
47
 
@@ -3,5 +3,5 @@
3
3
  module AppQuery
4
4
  # This should just contain the .dev of the upcoming version.
5
5
  # When doing the actual release, CI will write the tag here before pushing the gem.
6
- VERSION = "0.7.0.rc3"
6
+ VERSION = "0.7.0.rc4"
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appquery
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0.rc3
4
+ version: 0.7.0.rc4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gert Goet
@@ -44,6 +44,7 @@ files:
44
44
  - ".rspec"
45
45
  - ".standard.yml"
46
46
  - ".yard/templates/default/fulldoc/html/css/dark.css"
47
+ - ".yard/templates/default/fulldoc/html/js/app.js"
47
48
  - ".yard/templates/default/fulldoc/html/setup.rb"
48
49
  - ".yard/templates/default/layout/html/setup.rb"
49
50
  - ".yardopts"