diff --git a/about/index.html b/about/index.html new file mode 100644 index 00000000..27a5ec81 --- /dev/null +++ b/about/index.html @@ -0,0 +1,113 @@ + + + + + + + What is ElasticGraph? + + + + + + + + + +
+
+
+

What is ElasticGraph?

+ +

ElasticGraph is a general purpose, near real-time data query and search platform that is scalable and performant, serves rich interactive queries, and dramatically simplifies the creation of complex reports. The platform combines the power of indexing and search of Elasticsearch or OpenSearch with the query flexibility of GraphQL language. Optimized for AWS cloud, it also offers scale and reliability.

+ +

ElasticGraph is a naturally flexible framework with many different possible applications. However, the main motivation we have for building it is to power various data APIs, UIs and reports. These modern reports require filtering and aggregations across a body of ever growing data sets. Modern APIs allow us to:

+ +
    +
  • Minimize network trips to retrieve your data
  • +
  • Get exactly what you want in a single query. No over- or under-serving the data.
  • +
  • Push filtering complex calculations to the backend.
  • +
+ +

What can I do with it?

+ +

The ElasticGraph platform will allow you to query your data in many different configurations. To do so requires defining a schema which ElasticGraph will use to both index data and also query it. Besides all basic GraphQL query features, ElasticGraph also supports:

+ +
    +
  • Real-time indexing and data querying
  • +
  • Filtering, sorting, pagination, grouping, aggregations, and sub-aggregations
  • +
  • Navigating across data sets in a single query
  • +
  • Robust, safe schema evolution support via Query Registry mechanism
  • +
  • Derived indexes to power commonly accessed queries and aggregations
  • +
  • Client and Publisher libraries
  • +
+ +

Get started

+ +
gem install elasticgraph
+
+ +
+
+
+ + + + + + + diff --git a/assets/css/highlight.css b/assets/css/highlight.css new file mode 100644 index 00000000..7e5e6d3b --- /dev/null +++ b/assets/css/highlight.css @@ -0,0 +1,171 @@ +.highlight table td { padding: 5px; } +.highlight table pre { margin: 0; } +.highlight { + color: #FFFFFF; + background-color: #231529; +} +.highlight .c, .highlight .ch, .highlight .cd, .highlight .cm, .highlight .cpf, .highlight .c1, .highlight .cs { + color: #6D6E70; + font-style: italic; +} +.highlight .cp { + color: #41ff5b; + font-weight: bold; +} +.highlight .err { + color: #FFFFFF; + background-color: #CC0000; +} +.highlight .gr { + color: #FFFFFF; + background-color: #CC0000; +} +.highlight .k, .highlight .kd, .highlight .kv { + color: #FFF02A; + font-weight: bold; +} +.highlight .o, .highlight .ow { + color: #41ff5b; +} +.highlight .p, .highlight .pi { + color: #41ff5b; +} +.highlight .gd { + color: #CC0000; +} +.highlight .gi { + color: #3FB34F; +} +.highlight .ge { + font-style: italic; +} +.highlight .ges { + font-weight: bold; + font-style: italic; +} +.highlight .gs { + font-weight: bold; +} +.highlight .gt { + color: #FFFFFF; + background-color: #766DAF; +} +.highlight .gl { + color: #FFFFFF; + background-color: #766DAF; +} +.highlight .kc { + color: #9f93e6; + font-weight: bold; +} +.highlight .kn { + color: #FFFFFF; + font-weight: bold; +} +.highlight .kp { + color: #FFFFFF; + font-weight: bold; +} +.highlight .kr { + color: #FFFFFF; + font-weight: bold; +} +.highlight .gh { + color: #FFFFFF; + font-weight: bold; +} +.highlight .gu { + color: #FFFFFF; + font-weight: bold; +} +.highlight .kt { + color: #FAAF4C; + font-weight: bold; +} +.highlight .no { + color: #FAAF4C; + font-weight: bold; +} +.highlight .nc { + color: #FAAF4C; + font-weight: bold; +} +.highlight .nd { + color: #FAAF4C; + font-weight: bold; +} +.highlight .nn { + color: #FAAF4C; + font-weight: bold; +} +.highlight .bp { + color: #FAAF4C; + font-weight: bold; +} +.highlight .ne { + color: #FAAF4C; + font-weight: bold; +} +.highlight .nl { + color: #9f93e6; + font-weight: bold; +} +.highlight .nt { + color: #9f93e6; + font-weight: bold; +} +.highlight .m, .highlight .mb, .highlight .mf, .highlight .mh, .highlight .mi, .highlight .il, .highlight .mo, .highlight .mx { + color: #9f93e6; + font-weight: bold; +} +.highlight .ld { + color: #9f93e6; + font-weight: bold; +} +.highlight .ss { + color: #9f93e6; + font-weight: bold; +} +.highlight .s, .highlight .sb, .highlight .dl, .highlight .sd, .highlight .s2, .highlight .sh, .highlight .sx, .highlight .sr, .highlight .s1 { + color: #fff0a6; + font-weight: bold; +} +.highlight .sa { + color: #FFF02A; + font-weight: bold; +} +.highlight .se { + color: #FAAF4C; + font-weight: bold; +} +.highlight .sc { + color: #FAAF4C; + font-weight: bold; +} +.highlight .si { + color: #FAAF4C; + font-weight: bold; +} +.highlight .nb { + font-weight: bold; +} +.highlight .ni { + color: #999999; + font-weight: bold; +} +.highlight .w { + color: #BBBBBB; +} +.highlight .nf, .highlight .fm { + color: #41ff5b; +} +.highlight .py { + color: #41ff5b; +} +.highlight .na { + color: #41ff5b; +} +.highlight .nv, .highlight .vc, .highlight .vg, .highlight .vi, .highlight .vm { + color: #41ff5b; + font-weight: bold; +} \ No newline at end of file diff --git a/assets/css/main.css b/assets/css/main.css new file mode 100644 index 00000000..f05a83bf --- /dev/null +++ b/assets/css/main.css @@ -0,0 +1 @@ +/*! tailwindcss v3.4.10 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"\201C""\201D""\2018""\2019";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows)/10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows)/10%);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:17 24 39;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:255 255 255;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.collapse{visibility:collapse}.static{position:static}.absolute{position:absolute}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-8{margin-top:2rem;margin-bottom:2rem}.-mr-2{margin-right:-.5rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-4{margin-left:1rem}.mr-2{margin-right:.5rem}.mt-2{margin-top:.5rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-6{height:1.5rem}.h-screen{height:100vh}.w-6{width:1.5rem}.w-full{width:100%}.max-w-xl{max-width:36rem}.flex-grow{flex-grow:1}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-8{gap:2rem}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.p-0{padding:0}.p-6{padding:1.5rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem}.text-lg,.text-xl{line-height:1.75rem}.text-xl{font-size:1.25rem}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.capitalize{text-transform:capitalize}.italic{font-style:italic}.text-blue-100{--tw-text-opacity:1;color:rgb(219 234 254/var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}@media (min-width:1024px){.lg\:prose-xl{font-size:1.25rem;line-height:1.8}.lg\:prose-xl :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.2em;margin-bottom:1.2em}.lg\:prose-xl :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2em;line-height:1.5;margin-top:1em;margin-bottom:1em}.lg\:prose-xl :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1.0666667em}.lg\:prose-xl :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.8em;margin-top:0;margin-bottom:.8571429em;line-height:1}.lg\:prose-xl :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.8em;margin-top:1.5555556em;margin-bottom:.8888889em;line-height:1.1111111}.lg\:prose-xl :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.5em;margin-top:1.6em;margin-bottom:.6666667em;line-height:1.3333333}.lg\:prose-xl :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.8em;margin-bottom:.6em;line-height:1.6}.lg\:prose-xl :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.lg\:prose-xl :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.lg\:prose-xl :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.lg\:prose-xl :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.lg\:prose-xl :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em;border-radius:.3125rem;padding-top:.25em;padding-inline-end:.4em;padding-bottom:.25em;padding-inline-start:.4em}.lg\:prose-xl :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.lg\:prose-xl :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8611111em}.lg\:prose-xl :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.lg\:prose-xl :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em;line-height:1.7777778;margin-top:2em;margin-bottom:2em;border-radius:.5rem;padding-top:1.1111111em;padding-inline-end:1.3333333em;padding-bottom:1.1111111em;padding-inline-start:1.3333333em}.lg\:prose-xl :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.2em;margin-bottom:1.2em;padding-inline-start:1.6em}.lg\:prose-xl :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.2em;margin-bottom:1.2em;padding-inline-start:1.6em}.lg\:prose-xl :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.6em;margin-bottom:.6em}.lg\:prose-xl :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4em}.lg\:prose-xl :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4em}.lg\:prose-xl :where(.lg\:prose-xl>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.8em;margin-bottom:.8em}.lg\:prose-xl :where(.lg\:prose-xl>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.2em}.lg\:prose-xl :where(.lg\:prose-xl>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.2em}.lg\:prose-xl :where(.lg\:prose-xl>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.2em}.lg\:prose-xl :where(.lg\:prose-xl>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.2em}.lg\:prose-xl :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.8em;margin-bottom:.8em}.lg\:prose-xl :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.2em;margin-bottom:1.2em}.lg\:prose-xl :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.2em}.lg\:prose-xl :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.6em;padding-inline-start:1.6em}.lg\:prose-xl :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2.8em;margin-bottom:2.8em}.lg\:prose-xl :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.lg\:prose-xl :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.lg\:prose-xl :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.lg\:prose-xl :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.lg\:prose-xl :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em;line-height:1.5555556}.lg\:prose-xl :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.6666667em;padding-bottom:.8888889em;padding-inline-start:.6666667em}.lg\:prose-xl :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.lg\:prose-xl :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.lg\:prose-xl :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.8888889em;padding-inline-end:.6666667em;padding-bottom:.8888889em;padding-inline-start:.6666667em}.lg\:prose-xl :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.lg\:prose-xl :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.lg\:prose-xl :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.lg\:prose-xl :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.lg\:prose-xl :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em;line-height:1.5555556;margin-top:1em}.lg\:prose-xl :where(.lg\:prose-xl>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.lg\:prose-xl :where(.lg\:prose-xl>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}}@media (prefers-color-scheme:dark){.dark\:prose-invert{--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}}.hover\:bg-blue-500:hover{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity))}.hover\:text-blue-800:hover{--tw-text-opacity:1;color:rgb(30 64 175/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}@media (min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:py-20{padding-top:5rem;padding-bottom:5rem}}@media (prefers-color-scheme:dark){.dark\:bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity))}.dark\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.dark\:bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.dark\:bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.dark\:text-blue-400{--tw-text-opacity:1;color:rgb(96 165 250/var(--tw-text-opacity))}.dark\:text-gray-100{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}.dark\:text-gray-200{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}.dark\:text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}.dark\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.dark\:hover\:bg-blue-400:hover{--tw-bg-opacity:1;background-color:rgb(96 165 250/var(--tw-bg-opacity))}.dark\:hover\:text-blue-600:hover{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity))}} \ No newline at end of file diff --git a/assets/css/tailwind.css b/assets/css/tailwind.css new file mode 100644 index 00000000..b5c61c95 --- /dev/null +++ b/assets/css/tailwind.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/docs/main/ElasticGraph.html b/docs/main/ElasticGraph.html new file mode 100644 index 00000000..dfeb8537 --- /dev/null +++ b/docs/main/ElasticGraph.html @@ -0,0 +1,262 @@ + + + + + + + Module: ElasticGraph + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/graphql/engine_extension.rb,
+ elasticgraph-admin_lambda/lib/elastic_graph/admin_lambda.rb,
elasticgraph-admin_lambda/lib/elastic_graph/admin_lambda/rake_adapter.rb,
elasticgraph-admin_lambda/lib/elastic_graph/admin_lambda/lambda_function.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/graphql/service_field_resolver.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/graphql/entities_field_resolver.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/graphql/http_endpoint_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/api_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/field_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/state_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/factory_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/argument_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/enum_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/enum_value_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/input_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/union_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/entity_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/object_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/scalar_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/interface_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/graphql_sdl_enumerator_extension.rb,
elasticgraph-elasticsearch/lib/elastic_graph/elasticsearch/client.rb,
elasticgraph-graphql_lambda/lib/elastic_graph/graphql_lambda.rb,
elasticgraph-graphql_lambda/lib/elastic_graph/graphql_lambda/lambda_function.rb,
elasticgraph-graphql_lambda/lib/elastic_graph/graphql_lambda/graphql_endpoint.rb,
elasticgraph-indexer_autoscaler_lambda/lib/elastic_graph/indexer_autoscaler_lambda.rb,
elasticgraph-indexer_autoscaler_lambda/lib/elastic_graph/indexer_autoscaler_lambda/details_logger.rb,
elasticgraph-indexer_autoscaler_lambda/lib/elastic_graph/indexer_autoscaler_lambda/lambda_function.rb,
elasticgraph-indexer_autoscaler_lambda/lib/elastic_graph/indexer_autoscaler_lambda/concurrency_scaler.rb,
elasticgraph-indexer_lambda/lib/elastic_graph/indexer_lambda.rb,
elasticgraph-indexer_lambda/lib/elastic_graph/indexer_lambda/sqs_processor.rb,
elasticgraph-indexer_lambda/lib/elastic_graph/indexer_lambda/lambda_function.rb,
elasticgraph-json_schema/lib/elastic_graph/json_schema/validator.rb,
elasticgraph-json_schema/lib/elastic_graph/json_schema/validator_factory.rb,
elasticgraph-json_schema/lib/elastic_graph/json_schema/meta_schema_validator.rb,
elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb,
elasticgraph-local/lib/elastic_graph/local/docker_runner.rb,
elasticgraph-local/lib/elastic_graph/local/local_indexer.rb,
elasticgraph-local/lib/elastic_graph/local/indexing_coordinator.rb,
elasticgraph-opensearch/lib/elastic_graph/opensearch/client.rb,
elasticgraph-rack/lib/elastic_graph/rack.rb,
elasticgraph-rack/lib/elastic_graph/rack/graphiql.rb,
elasticgraph-rack/lib/elastic_graph/rack/graphql_endpoint.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/state.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/factory.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/results.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/rake_tasks.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/test_support.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/scripting/script.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/json_schema_pruner.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_indices.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_subtypes.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_type_info.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_directives.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/event_envelope.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_artifact_manager.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_reference.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/rollover_config.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_documentation.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/argument.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/union.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/directive.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/object.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/can_be_graphql_only.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field_path.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/input_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_namer.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/union_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/input_field.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/object_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/list_counts_mapping.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/verifies_graphql_name.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field_source.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/relationship.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/supports_default_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/relationship_resolver.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/update_target_factory.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/built_in_types.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/interface_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_reference.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/update_target_resolver.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_value_namer.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/scripting/file_system_repository.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/list_counts_state.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/json_schema_with_metadata.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/deprecated_element.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/json_schema_field_metadata.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/sub_aggregation_path.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/sort_order_enum_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/graphql_sdl_enumerator.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/append_only_set.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/immutable_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enums_for_indexed_types.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/supports_filtering_and_aggregation.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_derived_graphql_type_customizations.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/field_initializer_support.rb,
elasticgraph-support/lib/elastic_graph/errors.rb,
elasticgraph-support/lib/elastic_graph/version.rb,
elasticgraph-support/lib/elastic_graph/constants.rb,
elasticgraph-support/lib/elastic_graph/support/logger.rb,
elasticgraph-support/lib/elastic_graph/support/time_set.rb,
elasticgraph-support/lib/elastic_graph/support/hash_util.rb,
elasticgraph-support/lib/elastic_graph/support/threading.rb,
elasticgraph-support/lib/elastic_graph/support/time_util.rb,
elasticgraph-support/lib/elastic_graph/support/from_yaml_file.rb,
elasticgraph-support/lib/elastic_graph/support/memoizable_data.rb,
elasticgraph-support/lib/elastic_graph/support/monotonic_clock.rb,
elasticgraph-support/lib/elastic_graph/support/untyped_encoder.rb,
elasticgraph-support/lib/elastic_graph/support/graphql_formatter.rb,
elasticgraph-support/lib/elastic_graph/support/faraday_middleware/support_timeouts.rb,
elasticgraph-support/lib/elastic_graph/support/faraday_middleware/msearch_using_get_instead_of_post.rb
+
+
+ +
+ +

Overview

+
+

Copyright 2024 Block, Inc.

+ +

Use of this source code is governed by an MIT-style +license that can be found in the LICENSE file or at +https://opensource.org/licenses/MIT.

+ +

frozen_string_literal: true

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + Modules: Apollo, JSONSchema, Local, Rack, SchemaDefinition, Support + + + + +

+ + +

+ Constant Summary + collapse +

+ +
+ +
VERSION = +
+
+

The version of all ElasticGraph gems.

+ + +
+
+
+ + +
+
+
"0.18.0.5"
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .define_schemaObject + + + + + +

+
+

The main entry point for schema definition from ElasticGraph applications.

+ +

Call this API from a Ruby file configured as the path_to_schema (or from a Ruby file +loaded from the path_to_schema file).

+ + +
+
+
+ +
+

Examples:

+ + +
ElasticGraph.define_schema do |schema|
+  # The `schema` object provides the schema definition API. Use it in this block.
+end
+ +
+ + +
+ + + + +
+
+
+
+25
+26
+27
+28
+29
+30
+31
+32
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb', line 25
+
+def self.define_schema
+  if (api_instance = ::Thread.current[:ElasticGraph_SchemaDefinition_API_instance])
+    yield api_instance
+  else
+    raise Errors::SchemaError, "No active `SchemaDefinition::API` instance is available. " \
+      "Let ElasticGraph load the schema definition files."
+  end
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo.html b/docs/main/ElasticGraph/Apollo.html new file mode 100644 index 00000000..572cdedb --- /dev/null +++ b/docs/main/ElasticGraph/Apollo.html @@ -0,0 +1,160 @@ + + + + + + + Module: ElasticGraph::Apollo + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/api_extension.rb,
+ elasticgraph-apollo/lib/elastic_graph/apollo/graphql/engine_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/graphql/service_field_resolver.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/graphql/entities_field_resolver.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/graphql/http_endpoint_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/field_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/state_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/factory_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/argument_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/enum_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/enum_value_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/input_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/union_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/entity_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/object_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/scalar_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/interface_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/graphql_sdl_enumerator_extension.rb
+
+
+ +
+ +

Overview

+
+

ElasticGraph extension library that implements the Apollo subgraph federation +spec, turning +any ElasticGraph instance into an Apollo subgraph.

+ +

ElasticGraph::Apollo has two parts:

+ +
    +
  • SchemaDefinition is an extension used while defining an ElasticGraph schema. It includes all schema elements that are part +of the Apollo spec, including _Entity and the various directives.
  • +
  • GraphQL is an extension used by elasticgraph-graphql to support queries against Apollo’s subgraph schema additions (e.g. +_service and _entities). It includes reference resolvers +for all indexed types in your schema.
  • +
+ +

To use elasticgraph-apollo, simply use SchemaDefinition::APIExtension as a schema definition extension module. The GraphQL +extension module will get used by elasticgraph-graphql automatically.

+ + +
+
+
+ +
+

Examples:

+ + +

Use elasticgraph-apollo in a project

+
+ +
require "elastic_graph/apollo/schema_definition/api_extension"
+
+ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  tasks.schema_definition_extension_modules = [ElasticGraph::Apollo::SchemaDefinition::APIExtension]
+end
+ +
+ + +

Defined Under Namespace

+

+ + + Modules: GraphQL, SchemaDefinition + + + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/GraphQL.html b/docs/main/ElasticGraph/Apollo/GraphQL.html new file mode 100644 index 00000000..4b948b07 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/GraphQL.html @@ -0,0 +1,125 @@ + + + + + + + Module: ElasticGraph::Apollo::GraphQL + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::GraphQL + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/graphql/engine_extension.rb,
+ elasticgraph-apollo/lib/elastic_graph/apollo/graphql/service_field_resolver.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/graphql/entities_field_resolver.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/graphql/http_endpoint_extension.rb
+
+
+ +
+ +

Overview

+
+ +
+ Note: +

This module provides no public types or APIs. It will be used automatically when you use +SchemaDefinition::APIExtension as a schema definition extension module.

+
+
+ +

Namespace for all Apollo GraphQL enging logic.

+ + +
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition.html new file mode 100644 index 00000000..9f9ba7d7 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition.html @@ -0,0 +1,129 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/api_extension.rb,
+ elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/field_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/state_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/factory_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/argument_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/enum_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/enum_value_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/input_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/union_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/entity_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/object_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/scalar_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/interface_type_extension.rb,
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/graphql_sdl_enumerator_extension.rb
+
+
+ +
+ +

Overview

+
+

Namespace for all Apollo schema definition support.

+ +

APIExtension is the primary entry point and should be used as a schema definition extension module.

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + Modules: APIExtension, ApolloDirectives, ArgumentExtension, EnumTypeExtension, EnumValueExtension, FieldExtension, InputTypeExtension, InterfaceTypeExtension, ObjectTypeExtension, ScalarTypeExtension, UnionTypeExtension + + + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/APIExtension.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/APIExtension.html new file mode 100644 index 00000000..e2b77f9c --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/APIExtension.html @@ -0,0 +1,400 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::APIExtension + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::APIExtension + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/api_extension.rb
+
+ +
+ +

Overview

+
+

Module designed to be extended onto an SchemaDefinition::API instance +to customize the schema artifacts based on the Apollo Federation subgraph +spec.

+ +

To use this module, pass it in schema_definition_extension_modules when defining your Local::RakeTasks.

+ + +
+
+
+ +
+

Examples:

+ + +

Define local rake tasks with this extension module

+
+ +
require "elastic_graph/apollo/schema_definition/api_extension"
+
+ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  tasks.schema_definition_extension_modules = [ElasticGraph::Apollo::SchemaDefinition::APIExtension]
+end
+ +
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #tag_built_in_types_with(name, except: []) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Applies an apollo tag to built-in types so that they are included in the Apollo contract schema.

+ + +
+
+
+ +
+

Examples:

+ + +

Tag all built-in types (except two) for inclusion in the public schema

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.tag_built_in_types_with "public", except: ["IntAggregatedValue", "FloatAggregatedValues"]
+end
+ +
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    tag name

    +
    + +
  • + +
  • + + except + + + (Array<String>) + + + (defaults to: []) + + + — +

    built-in types not to tag

    +
    + +
  • + +
+ + +

See Also:

+ + +
+ + + + +
+
+
+
+82
+83
+84
+85
+86
+87
+88
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/api_extension.rb', line 82
+
+def tag_built_in_types_with(name, except: [])
+  except_set = except.to_set
+  on_built_in_types do |type|
+    apollo_type = (_ = type) # : ApolloDirectives::Tag
+    apollo_type.apollo_tag(name: name) unless except_set.include?(type.name)
+  end
+end
+
+
+ +
+

+ + #target_apollo_federation_version(version) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Picks which version of Apollo federation to target. By default, the latest supported version is +targeted, but you can call this to pick an earlier version, which may be necessary if your +organization is on an older version of Apollo federation.

+ + +
+
+
+ +
+

Examples:

+ + +

Set the Apollo Federation Version

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.target_apollo_federation_version "2.6"
+end
+ +
+

Parameters:

+
    + +
  • + + version + + + (String) + + + + — +

    version number

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/api_extension.rb', line 101
+
+def target_apollo_federation_version(version)
+  # Allow the version to have the `v` prefix, but don't require it.
+  version = version.delete_prefix("v")
+
+  state.apollo_directive_definitions = DIRECTIVE_DEFINITIONS_BY_FEDERATION_VERSION.fetch(version) do
+    supported_version_descriptions = DIRECTIVE_DEFINITIONS_BY_FEDERATION_VERSION.keys.map do |version_number|
+      "v#{version_number}"
+    end.join(", ")
+
+    raise Errors::SchemaError, "elasticgraph-apollo v#{ElasticGraph::VERSION} does not support Apollo federation v#{version}. " \
+      "Pick one of the supported versions (#{supported_version_descriptions}) instead."
+  end
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives.html new file mode 100644 index 00000000..10cafb13 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives.html @@ -0,0 +1,127 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb
+
+ +
+ +

Overview

+
+

Namespace for mixins that provide support for Apollo’s federation directives. +Each Apollo federation directive is offered via an API starting with apollo. For example, apollo_key can be used to define an +Apollo @key.

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + Modules: Authenticated, Extends, External, Inaccessible, InterfaceObject, Key, Override, Policy, Provides, Requires, RequiresScopes, Shareable, Tag + + + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Authenticated.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Authenticated.html new file mode 100644 index 00000000..64eeb8a0 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Authenticated.html @@ -0,0 +1,216 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Authenticated + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Authenticated + + + +

+
+ + + + + + + + + +
+
Included in:
+
EnumTypeExtension, FieldExtension, InterfaceTypeExtension, ObjectTypeExtension, ScalarTypeExtension
+
+ + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb
+
+ +
+ +

Overview

+
+

Supports Apollo’s @authenticated directive.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apollo_authenticatedvoid + + + + + +

+
+

This method returns an undefined value.

Adds the @authenticated directive +to the schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Add @authenticated to a type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.apollo_authenticated
+  end
+end
+ +
+ + +
+ + + + +
+
+
+
+29
+30
+31
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb', line 29
+
+def apollo_authenticated
+  directive "authenticated"
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Extends.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Extends.html new file mode 100644 index 00000000..06858bca --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Extends.html @@ -0,0 +1,216 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Extends + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Extends + + + +

+
+ + + + + + + + + +
+
Included in:
+
InterfaceTypeExtension, ObjectTypeExtension
+
+ + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb
+
+ +
+ +

Overview

+
+

Supports Apollo’s @extends directive.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apollo_extendsvoid + + + + + +

+
+

This method returns an undefined value.

Adds the @extends directive +to the schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Add @extends to a type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.apollo_extends
+  end
+end
+ +
+ + +
+ + + + +
+
+
+
+47
+48
+49
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb', line 47
+
+def apollo_extends
+  directive "extends"
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/External.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/External.html new file mode 100644 index 00000000..09d068de --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/External.html @@ -0,0 +1,216 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::External + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::External + + + +

+
+ + + + + + + + + +
+
Included in:
+
FieldExtension, ObjectTypeExtension
+
+ + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb
+
+ +
+ +

Overview

+
+

Supports Apollo’s @external directive.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apollo_externalvoid + + + + + +

+
+

This method returns an undefined value.

Adds the @external directive +to the schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Add @external to a type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.apollo_external
+  end
+end
+ +
+ + +
+ + + + +
+
+
+
+65
+66
+67
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb', line 65
+
+def apollo_external
+  directive "external"
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Inaccessible.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Inaccessible.html new file mode 100644 index 00000000..76af9d23 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Inaccessible.html @@ -0,0 +1,216 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Inaccessible + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Inaccessible + + + +

+
+ + + + + + + + + +
+
Included in:
+
ElasticGraph::Apollo::SchemaDefinition::ArgumentExtension, EnumTypeExtension, EnumValueExtension, FieldExtension, InputTypeExtension, InterfaceTypeExtension, ObjectTypeExtension, ScalarTypeExtension, UnionTypeExtension
+
+ + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb
+
+ +
+ +

Overview

+
+

Supports Apollo’s @inaccessible directive.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apollo_inaccessiblevoid + + + + + +

+
+

This method returns an undefined value.

Adds the @inaccessible directive +to the schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Add @inaccessible to a type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.apollo_inaccessible
+  end
+end
+ +
+ + +
+ + + + +
+
+
+
+83
+84
+85
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb', line 83
+
+def apollo_inaccessible
+  directive "inaccessible"
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/InterfaceObject.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/InterfaceObject.html new file mode 100644 index 00000000..2a3f0889 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/InterfaceObject.html @@ -0,0 +1,216 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::InterfaceObject + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::InterfaceObject + + + +

+
+ + + + + + + + + +
+
Included in:
+
ObjectTypeExtension
+
+ + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb
+
+ +
+ +

Overview

+
+

Supports Apollo’s @interfaceObject directive.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apollo_interface_objectvoid + + + + + +

+
+

This method returns an undefined value.

Adds the @interfaceObject directive +to the schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Add @interfaceObject to a type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.apollo_interface_object
+  end
+end
+ +
+ + +
+ + + + +
+
+
+
+101
+102
+103
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb', line 101
+
+def apollo_interface_object
+  directive "interfaceObject"
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Key.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Key.html new file mode 100644 index 00000000..1ad48377 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Key.html @@ -0,0 +1,265 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Key + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Key + + + +

+
+ + + + + + + + + +
+
Included in:
+
InterfaceTypeExtension, ObjectTypeExtension
+
+ + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb
+
+ +
+ +

Overview

+
+

Supports Apollo’s @key directive.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apollo_key(fields:, resolvable: true) ⇒ void + + + + + +

+
+ +
+ Note: +

ElasticGraph automatically defines an apollo_key of id for every indexed type. This API is only needed when defining +additional keys on an indexed type, or defining a key for a non-indexed type.

+
+
+ +

This method returns an undefined value.

Adds the @key directive +to the schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Define a @key on a non-indexed type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "organizationId", "ID"
+    t.field "id", "ID"
+    t.apollo_key fields: "id organizationId", resolvable: false
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + fields + + + (String) + + + + — +

    A GraphQL selection set (provided as a string) of fields and subfields that contribute to the entity’s +unique key.

    +
    + +
  • + +
  • + + resolvable + + + (Boolean) + + + (defaults to: true) + + + — +

    If false, indicates to the Apollo router that this subgraph doesn’t define a reference resolver for +this entity. This means that router query plans can’t “jump to” this subgraph to resolve fields that aren’t defined in another +subgraph.

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+129
+130
+131
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb', line 129
+
+def apollo_key(fields:, resolvable: true)
+  directive "key", fields: fields, resolvable: resolvable
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Override.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Override.html new file mode 100644 index 00000000..3647f034 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Override.html @@ -0,0 +1,237 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Override + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Override + + + +

+
+ + + + + + + + + +
+
Included in:
+
FieldExtension
+
+ + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb
+
+ +
+ +

Overview

+
+

Supports Apollo’s @override directive.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apollo_override(from:) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Adds the @override directive +to the schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Add @override to a field

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Product" do |t|
+    t.field "inStock", "Boolean" do |f|
+      f.apollo_override from: "Products"
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + from + + + (String) + + + + — +

    The name of the other subgraph that no longer resolves the field.

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+150
+151
+152
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb', line 150
+
+def apollo_override(from:)
+  directive "override", from: from
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Policy.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Policy.html new file mode 100644 index 00000000..a480ab0e --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Policy.html @@ -0,0 +1,235 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Policy + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Policy + + + +

+
+ + + + + + + + + +
+
Included in:
+
EnumTypeExtension, FieldExtension, InterfaceTypeExtension, ObjectTypeExtension, ScalarTypeExtension
+
+ + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb
+
+ +
+ +

Overview

+
+

Supports Apollo’s @policy directive.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apollo_policy(policies:) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Adds the @policy directive +to the schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Add @policy to a type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.apollo_policy policies: ["Policy1", "Policy2"]
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + policies + + + (Array<String>) + + + + — +

    List of authorization policies.

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+169
+170
+171
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb', line 169
+
+def apollo_policy(policies:)
+  directive "policy", policies: policies
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Provides.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Provides.html new file mode 100644 index 00000000..ac618c34 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Provides.html @@ -0,0 +1,243 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Provides + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Provides + + + +

+
+ + + + + + + + + +
+
Included in:
+
FieldExtension
+
+ + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb
+
+ +
+ +

Overview

+
+

Supports Apollo’s @provides directive.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apollo_provides(fields:) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Adds the @provides directive +to the schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Add @provides to a field

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Product" do |t|
+    t.field "name", "String"
+  end
+
+  schema.object_type "StoreLocation" do |t|
+    t.field "products", "[Product!]!" do |f|
+      f.mapping type: "nested"
+      f.apollo_provides fields: "name"
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + fields + + + (String) + + + + — +

    A GraphQL selection set (provided as a string) of object fields and subfields that the subgraph can +resolve only at this query path.

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+196
+197
+198
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb', line 196
+
+def apollo_provides(fields:)
+  directive "provides", fields: fields
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Requires.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Requires.html new file mode 100644 index 00000000..ed853f2a --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Requires.html @@ -0,0 +1,240 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Requires + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Requires + + + +

+
+ + + + + + + + + +
+
Included in:
+
FieldExtension
+
+ + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb
+
+ +
+ +

Overview

+
+

Supports Apollo’s @requires directive.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apollo_requires(fields:) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Adds the @requires directive +to the schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Add @requires to a field

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Product" do |t|
+    t.field "size", "Int"
+    t.field "weight", "Int"
+    t.field "shippingEstimate", "String" do |f|
+      f.apollo_requires fields: "size weight"
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + fields + + + (String) + + + + — +

    A GraphQL selection set (provided as a string) of object fields and subfields that the subgraph can +resolve only at this query path.

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+220
+221
+222
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb', line 220
+
+def apollo_requires(fields:)
+  directive "requires", fields: fields
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/RequiresScopes.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/RequiresScopes.html new file mode 100644 index 00000000..4001d8fb --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/RequiresScopes.html @@ -0,0 +1,237 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::RequiresScopes + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::RequiresScopes + + + +

+
+ + + + + + + + + +
+
Included in:
+
EnumTypeExtension, FieldExtension, InterfaceTypeExtension, ObjectTypeExtension, ScalarTypeExtension
+
+ + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb
+
+ +
+ +

Overview

+
+

Supports Apollo’s @requiresScopes directive.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apollo_requires_scopes(scopes:) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Adds the @requiresScopes directive +to the schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Add @requiresScopes to a field

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Product" do |t|
+    t.field "shippingEstimate", "String" do |f|
+      f.apollo_requires_scopes scopes: "shipping"
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + scopes + + + (Array<String>) + + + + — +

    List of JWT scopes that must be granted to the user in order to access the underlying element data.

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+241
+242
+243
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb', line 241
+
+def apollo_requires_scopes(scopes:)
+  directive "requiresScopes", scopes: scopes
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Shareable.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Shareable.html new file mode 100644 index 00000000..7e51b825 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Shareable.html @@ -0,0 +1,216 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Shareable + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Shareable + + + +

+
+ + + + + + + + + +
+
Included in:
+
FieldExtension, ObjectTypeExtension
+
+ + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb
+
+ +
+ +

Overview

+
+

Supports Apollo’s @shareable directive.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apollo_shareablevoid + + + + + +

+
+

This method returns an undefined value.

Adds the @shareable directive +to the schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Add @shareable to a type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.apollo_shareable
+  end
+end
+ +
+ + +
+ + + + +
+
+
+
+259
+260
+261
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb', line 259
+
+def apollo_shareable
+  directive "shareable"
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Tag.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Tag.html new file mode 100644 index 00000000..375ed5a4 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ApolloDirectives/Tag.html @@ -0,0 +1,225 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Tag + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Tag + + + +

+
+ + + + + + + + + +
+
Included in:
+
ElasticGraph::Apollo::SchemaDefinition::ArgumentExtension, EnumTypeExtension, EnumValueExtension, FieldExtension, InputTypeExtension, InterfaceTypeExtension, ObjectTypeExtension, ScalarTypeExtension, UnionTypeExtension
+
+ + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb
+
+ +
+ +

Overview

+
+

Supports Apollo’s @tag directive.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apollo_tag(name:) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Adds the @tag directive +to the schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Add @tag to a type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.apollo_tag name: "public"
+  end
+end
+ +
+ + +

See Also:

+ + +
+ + + + +
+
+
+
+280
+281
+282
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb', line 280
+
+def apollo_tag(name:)
+  directive "tag", name: name
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ArgumentExtension.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ArgumentExtension.html new file mode 100644 index 00000000..495602d2 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ArgumentExtension.html @@ -0,0 +1,142 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ArgumentExtension + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ArgumentExtension + + + +

+
+ + + + + + +
+
Includes:
+
ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Inaccessible, ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Tag
+
+ + + + + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/argument_extension.rb
+
+ +
+ +

Overview

+
+

Extends SchemaDefinition::SchemaElements::Argument to offer Apollo argument directives.

+ + +
+
+
+ + +
+ + + + + + + + + + + + + +

Method Summary

+ +

Methods included from ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Tag

+

#apollo_tag

+ + + + + + + + + +

Methods included from ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Inaccessible

+

#apollo_inaccessible

+ + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/EnumTypeExtension.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/EnumTypeExtension.html new file mode 100644 index 00000000..baec325f --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/EnumTypeExtension.html @@ -0,0 +1,175 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::EnumTypeExtension + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::EnumTypeExtension + + + +

+
+ + + + + + +
+
Includes:
+
ApolloDirectives::Authenticated, ApolloDirectives::Inaccessible, ApolloDirectives::Policy, ApolloDirectives::RequiresScopes, ApolloDirectives::Tag
+
+ + + + + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/enum_type_extension.rb
+
+ +
+ +

Overview

+
+

Extends SchemaDefinition::SchemaElements::EnumType to offer Apollo enum type directives.

+ + +
+
+
+ + +
+ + + + + + + + + + + + + +

Method Summary

+ +

Methods included from ApolloDirectives::Tag

+

#apollo_tag

+ + + + + + + + + +

Methods included from ApolloDirectives::RequiresScopes

+

#apollo_requires_scopes

+ + + + + + + + + +

Methods included from ApolloDirectives::Policy

+

#apollo_policy

+ + + + + + + + + +

Methods included from ApolloDirectives::Inaccessible

+

#apollo_inaccessible

+ + + + + + + + + +

Methods included from ApolloDirectives::Authenticated

+

#apollo_authenticated

+ + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/EnumValueExtension.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/EnumValueExtension.html new file mode 100644 index 00000000..0bcab75a --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/EnumValueExtension.html @@ -0,0 +1,142 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::EnumValueExtension + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::EnumValueExtension + + + +

+
+ + + + + + +
+
Includes:
+
ApolloDirectives::Inaccessible, ApolloDirectives::Tag
+
+ + + + + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/enum_value_extension.rb
+
+ +
+ +

Overview

+
+

Extends SchemaDefinition::SchemaElements::EnumValue to offer Apollo enum value directives.

+ + +
+
+
+ + +
+ + + + + + + + + + + + + +

Method Summary

+ +

Methods included from ApolloDirectives::Tag

+

#apollo_tag

+ + + + + + + + + +

Methods included from ApolloDirectives::Inaccessible

+

#apollo_inaccessible

+ + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/FieldExtension.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/FieldExtension.html new file mode 100644 index 00000000..e97dd3fc --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/FieldExtension.html @@ -0,0 +1,512 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::FieldExtension + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::FieldExtension + + + +

+ + +

Overview

+
+

Extends SchemaDefinition::SchemaElements::Field to offer Apollo field directives.

+ + +
+
+
+ + +
+ + + + + + + +

+ Class Method Summary + collapse +

+ + + +

+ Instance Method Summary + collapse +

+ + + + + + + + + + + + + +

Methods included from ApolloDirectives::Tag

+

#apollo_tag

+ + + + + + + + + +

Methods included from ApolloDirectives::Shareable

+

#apollo_shareable

+ + + + + + + + + +

Methods included from ApolloDirectives::RequiresScopes

+

#apollo_requires_scopes

+ + + + + + + + + +

Methods included from ApolloDirectives::Requires

+

#apollo_requires

+ + + + + + + + + +

Methods included from ApolloDirectives::Provides

+

#apollo_provides

+ + + + + + + + + +

Methods included from ApolloDirectives::Policy

+

#apollo_policy

+ + + + + + + + + +

Methods included from ApolloDirectives::Override

+

#apollo_override

+ + + + + + + + + +

Methods included from ApolloDirectives::Inaccessible

+

#apollo_inaccessible

+ + + + + + + + + +

Methods included from ApolloDirectives::External

+

#apollo_external

+ + + + + + + + + +

Methods included from ApolloDirectives::Authenticated

+

#apollo_authenticated

+ + +
+

Class Method Details

+ + +
+

+ + .tagged_with?(element, tag_name) ⇒ Boolean + + + + + +

+
+

Helper method that indicates if the given schema element has a specific tag.

+ + +
+
+
+

Parameters:

+
    + +
  • + + element + + + (Object) + + + + — +

    element to check

    +
    + +
  • + +
  • + + tag_name + + + (String) + + + + — +

    tag to check

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+70
+71
+72
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/field_extension.rb', line 70
+
+def self.tagged_with?(element, tag_name)
+  element.directives.any? { |dir| dir.name == "tag" && dir.arguments == {name: tag_name} }
+end
+
+
+ +
+ +
+

Instance Method Details

+ + +
+

+ + #tag_with(tag_name) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Extension method designed to support Apollo’s contract variant tagging.

+ +

Calling this method on a field will cause the field and every schema element derived from the field (e.g. the filter field, +he aggregation field, etc), to be tagged with the given tag_name, ensuring that all capabilities related to the field are +available in the contract variant.

+ + +
+
+
+ +
+

Examples:

+ + +

Tag a field (and its derived elements) with “public”

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "name", "String" do |f|
+      f.tag_with "public"
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + tag_name + + + (String) + + + + — +

    tag to add to schema elements generated for this field

    +
    + +
  • + +
+ + +

See Also:

+ + +
+ + + + +
+
+
+
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+
+
# File 'elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/field_extension.rb', line 47
+
+def tag_with(tag_name)
+  on_each_generated_schema_element do |element|
+    needs_tagging =
+      if element.is_a?(ElasticGraph::SchemaDefinition::SchemaElements::SortOrderEnumValue)
+        # Each sort order enum value is based on a full field path (e.g. `parentField_subField_furtherNestedField_ASC`).
+        # We must only tag the enum if each part of the full field path is also tagged. In this example, we should only
+        # tag the enum value if `parentField`, `subField`, and `furtherNestedField` are all tagged.
+        element.sort_order_field_path.all? { |f| FieldExtension.tagged_with?(f, tag_name) }
+      else
+        true
+      end
+
+    if needs_tagging && !FieldExtension.tagged_with?(element, tag_name)
+      (_ = element).apollo_tag name: tag_name
+    end
+  end
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/InputTypeExtension.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/InputTypeExtension.html new file mode 100644 index 00000000..da75cb40 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/InputTypeExtension.html @@ -0,0 +1,142 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::InputTypeExtension + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::InputTypeExtension + + + +

+
+ + + + + + +
+
Includes:
+
ApolloDirectives::Inaccessible, ApolloDirectives::Tag
+
+ + + + + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/input_type_extension.rb
+
+ +
+ +

Overview

+
+

Extends SchemaDefinition::SchemaElements::InputType to offer Apollo input type directives.

+ + +
+
+
+ + +
+ + + + + + + + + + + + + +

Method Summary

+ +

Methods included from ApolloDirectives::Tag

+

#apollo_tag

+ + + + + + + + + +

Methods included from ApolloDirectives::Inaccessible

+

#apollo_inaccessible

+ + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/InterfaceTypeExtension.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/InterfaceTypeExtension.html new file mode 100644 index 00000000..7eb03793 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/InterfaceTypeExtension.html @@ -0,0 +1,197 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::InterfaceTypeExtension + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::InterfaceTypeExtension + + + +

+
+ + + + + + +
+
Includes:
+
ApolloDirectives::Authenticated, ApolloDirectives::Extends, ApolloDirectives::Inaccessible, ApolloDirectives::Key, ApolloDirectives::Policy, ApolloDirectives::RequiresScopes, ApolloDirectives::Tag
+
+ + + + + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/interface_type_extension.rb
+
+ +
+ +

Overview

+
+

Extends SchemaDefinition::SchemaElements::InterfaceType to offer Apollo interface type directives.

+ + +
+
+
+ + +
+ + + + + + + + + + + + + +

Method Summary

+ +

Methods included from ApolloDirectives::Tag

+

#apollo_tag

+ + + + + + + + + +

Methods included from ApolloDirectives::RequiresScopes

+

#apollo_requires_scopes

+ + + + + + + + + +

Methods included from ApolloDirectives::Policy

+

#apollo_policy

+ + + + + + + + + +

Methods included from ApolloDirectives::Key

+

#apollo_key

+ + + + + + + + + +

Methods included from ApolloDirectives::Inaccessible

+

#apollo_inaccessible

+ + + + + + + + + +

Methods included from ApolloDirectives::Extends

+

#apollo_extends

+ + + + + + + + + +

Methods included from ApolloDirectives::Authenticated

+

#apollo_authenticated

+ + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ObjectTypeExtension.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ObjectTypeExtension.html new file mode 100644 index 00000000..0edd0418 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ObjectTypeExtension.html @@ -0,0 +1,230 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ObjectTypeExtension + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ObjectTypeExtension + + + +

+ + +

Overview

+
+

Extends SchemaDefinition::SchemaElements::ObjectType to offer Apollo object type directives.

+ + +
+
+
+ + +
+ + + + + + + + + + + + + +

Method Summary

+ +

Methods included from ApolloDirectives::Tag

+

#apollo_tag

+ + + + + + + + + +

Methods included from ApolloDirectives::Shareable

+

#apollo_shareable

+ + + + + + + + + +

Methods included from ApolloDirectives::RequiresScopes

+

#apollo_requires_scopes

+ + + + + + + + + +

Methods included from ApolloDirectives::Policy

+

#apollo_policy

+ + + + + + + + + +

Methods included from ApolloDirectives::Key

+

#apollo_key

+ + + + + + + + + +

Methods included from ApolloDirectives::InterfaceObject

+

#apollo_interface_object

+ + + + + + + + + +

Methods included from ApolloDirectives::Inaccessible

+

#apollo_inaccessible

+ + + + + + + + + +

Methods included from ApolloDirectives::External

+

#apollo_external

+ + + + + + + + + +

Methods included from ApolloDirectives::Extends

+

#apollo_extends

+ + + + + + + + + +

Methods included from ApolloDirectives::Authenticated

+

#apollo_authenticated

+ + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/ScalarTypeExtension.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ScalarTypeExtension.html new file mode 100644 index 00000000..82e7ad6a --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/ScalarTypeExtension.html @@ -0,0 +1,175 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::ScalarTypeExtension + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::ScalarTypeExtension + + + +

+
+ + + + + + +
+
Includes:
+
ApolloDirectives::Authenticated, ApolloDirectives::Inaccessible, ApolloDirectives::Policy, ApolloDirectives::RequiresScopes, ApolloDirectives::Tag
+
+ + + + + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/scalar_type_extension.rb
+
+ +
+ +

Overview

+
+

Extends SchemaDefinition::SchemaElements::ScalarType to offer Apollo scalar type directives.

+ + +
+
+
+ + +
+ + + + + + + + + + + + + +

Method Summary

+ +

Methods included from ApolloDirectives::Tag

+

#apollo_tag

+ + + + + + + + + +

Methods included from ApolloDirectives::RequiresScopes

+

#apollo_requires_scopes

+ + + + + + + + + +

Methods included from ApolloDirectives::Policy

+

#apollo_policy

+ + + + + + + + + +

Methods included from ApolloDirectives::Inaccessible

+

#apollo_inaccessible

+ + + + + + + + + +

Methods included from ApolloDirectives::Authenticated

+

#apollo_authenticated

+ + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Apollo/SchemaDefinition/UnionTypeExtension.html b/docs/main/ElasticGraph/Apollo/SchemaDefinition/UnionTypeExtension.html new file mode 100644 index 00000000..8371c081 --- /dev/null +++ b/docs/main/ElasticGraph/Apollo/SchemaDefinition/UnionTypeExtension.html @@ -0,0 +1,142 @@ + + + + + + + Module: ElasticGraph::Apollo::SchemaDefinition::UnionTypeExtension + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Apollo::SchemaDefinition::UnionTypeExtension + + + +

+
+ + + + + + +
+
Includes:
+
ApolloDirectives::Inaccessible, ApolloDirectives::Tag
+
+ + + + + + +
+
Defined in:
+
elasticgraph-apollo/lib/elastic_graph/apollo/schema_definition/union_type_extension.rb
+
+ +
+ +

Overview

+
+

Extends SchemaDefinition::SchemaElements::UnionType to offer Apollo union type directives.

+ + +
+
+
+ + +
+ + + + + + + + + + + + + +

Method Summary

+ +

Methods included from ApolloDirectives::Tag

+

#apollo_tag

+ + + + + + + + + +

Methods included from ApolloDirectives::Inaccessible

+

#apollo_inaccessible

+ + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/JSONSchema.html b/docs/main/ElasticGraph/JSONSchema.html new file mode 100644 index 00000000..5fff6ecb --- /dev/null +++ b/docs/main/ElasticGraph/JSONSchema.html @@ -0,0 +1,337 @@ + + + + + + + Module: ElasticGraph::JSONSchema + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::JSONSchema + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-json_schema/lib/elastic_graph/json_schema/meta_schema_validator.rb,
+ elasticgraph-json_schema/lib/elastic_graph/json_schema/validator.rb,
elasticgraph-json_schema/lib/elastic_graph/json_schema/validator_factory.rb
+
+
+ +
+ +

Overview

+
+

Provides JSON Schema validation for ElasticGraph.

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + Modules: MetaSchemaLoader + + + + Classes: Validator, ValidatorFactory + + +

+ + + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .elastic_graph_internal_meta_schema_validatorValidator + + + + + +

+
+

Provides a validator to validate a JSON schema definition according to the JSON schema meta schema. +The validator is configured to validate strictly, so that non-standard JSON schema properties are disallowed, +except for internal ElasticGraph metadata properties.

+ + +
+
+
+ +

Returns:

+ + +

See Also:

+ + +
+ + + + +
+
+
+
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+
+
# File 'elasticgraph-json_schema/lib/elastic_graph/json_schema/meta_schema_validator.rb', line 32
+
+def self.elastic_graph_internal_meta_schema_validator
+  @elastic_graph_internal_meta_schema_validator ||= MetaSchemaLoader.load_strict_validator({
+    "properties" => {
+      "ElasticGraph" => {
+        "type" => "object",
+        "required" => ["type", "nameInIndex"],
+        "properties" => {
+          "type" => {"type" => "string"},
+          "nameInIndex" => {"type" => "string"}
+        }
+      }
+    }
+  })
+end
+
+
+ +
+

+ + .strict_meta_schema_validatorValidator + + + + + +

+
+

Provides a validator to validate a JSON schema definitions according to the JSON schema meta schema. +The validator is configured to validate strictly, so that non-standard JSON schema properties are disallowed.

+ + +
+
+
+ +

Returns:

+ + +

See Also:

+ + +
+ + + + +
+
+
+
+22
+23
+24
+
+
# File 'elasticgraph-json_schema/lib/elastic_graph/json_schema/meta_schema_validator.rb', line 22
+
+def self.strict_meta_schema_validator
+  @strict_meta_schema_validator ||= MetaSchemaLoader.load_strict_validator
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/JSONSchema/MetaSchemaLoader.html b/docs/main/ElasticGraph/JSONSchema/MetaSchemaLoader.html new file mode 100644 index 00000000..394173fc --- /dev/null +++ b/docs/main/ElasticGraph/JSONSchema/MetaSchemaLoader.html @@ -0,0 +1,240 @@ + + + + + + + Module: ElasticGraph::JSONSchema::MetaSchemaLoader + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::JSONSchema::MetaSchemaLoader + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-json_schema/lib/elastic_graph/json_schema/meta_schema_validator.rb
+
+ +
+ +

Overview

+
+

Responsible for building Validators that can validate JSON schema definitions.

+ + +
+
+
+ + +
+ + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .load_strict_validator(overrides = {}) ⇒ Object + + + + + +

+
+

Builds a validator to validate a JSON schema definition according to the JSON schema meta schema.

+ + +
+
+
+

Parameters:

+
    + +
  • + + overrides + + + (Hash<String, Object>) + + + (defaults to: {}) + + + — +

    meta schema overrides

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+
+
# File 'elasticgraph-json_schema/lib/elastic_graph/json_schema/meta_schema_validator.rb', line 52
+
+def self.load_strict_validator(overrides = {})
+  # Downloaded from: https://json-schema.org/draft-07/schema
+  schema = ::JSON.parse(::File.read(::File.expand_path("../json_schema_draft_7_schema.json", __FILE__)))
+  schema = Support::HashUtil.deep_merge(schema, overrides) unless overrides.empty?
+
+  # The meta schema allows additionalProperties in nearly every place. While a JSON schema definition
+  # with additional properties is considered valid, we do not intend to use any additional properties,
+  # and any usage of an additional property is almost certainly a typo. So here we set
+  # `with_unknown_properties_disallowed`.
+  root_schema = ValidatorFactory.new(schema: schema, sanitize_pii: false) # The meta schema has no PII
+    .with_unknown_properties_disallowed
+    .root_schema
+
+  Validator.new(schema: root_schema, sanitize_pii: false)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/JSONSchema/Validator.html b/docs/main/ElasticGraph/JSONSchema/Validator.html new file mode 100644 index 00000000..313f71f2 --- /dev/null +++ b/docs/main/ElasticGraph/JSONSchema/Validator.html @@ -0,0 +1,865 @@ + + + + + + + Class: ElasticGraph::JSONSchema::Validator + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::JSONSchema::Validator + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-json_schema/lib/elastic_graph/json_schema/validator.rb
+
+ +
+ +

Overview

+
+

Responsible for validating JSON data against the ElasticGraph JSON schema for a particular type.

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + + +
+

Instance Attribute Details

+ + + +
+

+ + #sanitize_piiBoolean (readonly) + + + + + +

+
+

Returns whether to omit data that may contain PII from error messages.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + + — +

    whether to omit data that may contain PII from error messages

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+
+
# File 'elasticgraph-json_schema/lib/elastic_graph/json_schema/validator.rb', line 19
+
+class Validator < ::Data.define(:schema, :sanitize_pii)
+  # Validates the given data against the JSON schema, returning true if the data is valid.
+  #
+  # @param data [Object] JSON data to validate
+  # @return [Boolean] true if the data is valid; false if it is invalid
+  #
+  # @see #validate
+  # @see #validate_with_error_message
+  def valid?(data)
+    schema.valid?(data)
+  end
+
+  # Validates the given data against the JSON schema, returning an array of error objects for
+  # any validation errors.
+  #
+  # @param data [Object] JSON data to validate
+  # @return [Array<Hash<String, Object>>] validation errors; will be empty if `data` is valid
+  #
+  # @see #valid?
+  # @see #validate_with_error_message
+  def validate(data)
+    schema.validate(data).map do |error|
+      # The schemas can be very large and make the output very noisy, hiding what matters. So we remove them here.
+      error.delete("root_schema")
+      error.delete("schema")
+      error
+    end
+  end
+
+  # Validates the given data against the JSON schema, returning an error message string if it is invalid.
+  # The error message is intended to be usable to include in a log message or a raised error.
+  #
+  # @param data [Object] JSON data to validate
+  # @return [nil, String] a validation error message, if the data is invalid
+  #
+  # @note The returned error message may contain PII unless {#sanitize_pii} has not been set.
+  #
+  # @see #valid?
+  # @see #validate
+  def validate_with_error_message(data)
+    errors = validate(data)
+    return if errors.empty?
+
+    errors.each { |error| error.delete("data") } if sanitize_pii
+
+    "Validation errors:\n\n#{errors.map { |e| ::JSON.pretty_generate(e) }.join("\n\n")}"
+  end
+end
+
+
+ + + +
+

+ + #schemaHash<String, Object> (readonly) + + + + + +

+
+

Returns a JSON schema.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, Object>) + + + + — +

    a JSON schema

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+
+
# File 'elasticgraph-json_schema/lib/elastic_graph/json_schema/validator.rb', line 19
+
+class Validator < ::Data.define(:schema, :sanitize_pii)
+  # Validates the given data against the JSON schema, returning true if the data is valid.
+  #
+  # @param data [Object] JSON data to validate
+  # @return [Boolean] true if the data is valid; false if it is invalid
+  #
+  # @see #validate
+  # @see #validate_with_error_message
+  def valid?(data)
+    schema.valid?(data)
+  end
+
+  # Validates the given data against the JSON schema, returning an array of error objects for
+  # any validation errors.
+  #
+  # @param data [Object] JSON data to validate
+  # @return [Array<Hash<String, Object>>] validation errors; will be empty if `data` is valid
+  #
+  # @see #valid?
+  # @see #validate_with_error_message
+  def validate(data)
+    schema.validate(data).map do |error|
+      # The schemas can be very large and make the output very noisy, hiding what matters. So we remove them here.
+      error.delete("root_schema")
+      error.delete("schema")
+      error
+    end
+  end
+
+  # Validates the given data against the JSON schema, returning an error message string if it is invalid.
+  # The error message is intended to be usable to include in a log message or a raised error.
+  #
+  # @param data [Object] JSON data to validate
+  # @return [nil, String] a validation error message, if the data is invalid
+  #
+  # @note The returned error message may contain PII unless {#sanitize_pii} has not been set.
+  #
+  # @see #valid?
+  # @see #validate
+  def validate_with_error_message(data)
+    errors = validate(data)
+    return if errors.empty?
+
+    errors.each { |error| error.delete("data") } if sanitize_pii
+
+    "Validation errors:\n\n#{errors.map { |e| ::JSON.pretty_generate(e) }.join("\n\n")}"
+  end
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #valid?(data) ⇒ Boolean + + + + + +

+
+

Validates the given data against the JSON schema, returning true if the data is valid.

+ + +
+
+
+

Parameters:

+
    + +
  • + + data + + + (Object) + + + + — +

    JSON data to validate

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + + — +

    true if the data is valid; false if it is invalid

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+27
+28
+29
+
+
# File 'elasticgraph-json_schema/lib/elastic_graph/json_schema/validator.rb', line 27
+
+def valid?(data)
+  schema.valid?(data)
+end
+
+
+ +
+

+ + #validate(data) ⇒ Array<Hash<String, Object>> + + + + + +

+
+

Validates the given data against the JSON schema, returning an array of error objects for +any validation errors.

+ + +
+
+
+

Parameters:

+
    + +
  • + + data + + + (Object) + + + + — +

    JSON data to validate

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Hash<String, Object>>) + + + + — +

    validation errors; will be empty if data is valid

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+39
+40
+41
+42
+43
+44
+45
+46
+
+
# File 'elasticgraph-json_schema/lib/elastic_graph/json_schema/validator.rb', line 39
+
+def validate(data)
+  schema.validate(data).map do |error|
+    # The schemas can be very large and make the output very noisy, hiding what matters. So we remove them here.
+    error.delete("root_schema")
+    error.delete("schema")
+    error
+  end
+end
+
+
+ +
+

+ + #validate_with_error_message(data) ⇒ nil, String + + + + + +

+
+ +
+ Note: +

The returned error message may contain PII unless #sanitize_pii has not been set.

+
+
+ +

Validates the given data against the JSON schema, returning an error message string if it is invalid. +The error message is intended to be usable to include in a log message or a raised error.

+ + +
+
+
+

Parameters:

+
    + +
  • + + data + + + (Object) + + + + — +

    JSON data to validate

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (nil, String) + + + + — +

    a validation error message, if the data is invalid

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+58
+59
+60
+61
+62
+63
+64
+65
+
+
# File 'elasticgraph-json_schema/lib/elastic_graph/json_schema/validator.rb', line 58
+
+def validate_with_error_message(data)
+  errors = validate(data)
+  return if errors.empty?
+
+  errors.each { |error| error.delete("data") } if sanitize_pii
+
+  "Validation errors:\n\n#{errors.map { |e| ::JSON.pretty_generate(e) }.join("\n\n")}"
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/JSONSchema/ValidatorFactory.html b/docs/main/ElasticGraph/JSONSchema/ValidatorFactory.html new file mode 100644 index 00000000..6f1fb766 --- /dev/null +++ b/docs/main/ElasticGraph/JSONSchema/ValidatorFactory.html @@ -0,0 +1,508 @@ + + + + + + + Class: ElasticGraph::JSONSchema::ValidatorFactory + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::JSONSchema::ValidatorFactory + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-json_schema/lib/elastic_graph/json_schema/validator_factory.rb
+
+ +
+ +

Overview

+
+

Factory class responsible for creating Validators for particular ElasticGraph types.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(schema:, sanitize_pii:) ⇒ ValidatorFactory + + + + + +

+
+

Returns a new instance of ValidatorFactory.

+ + +
+
+
+

Parameters:

+
    + +
  • + + schema + + + (Hash<String, Object>) + + + + — +

    the JSON schema for an entire ElasticGraph schema

    +
    + +
  • + +
  • + + sanitize_pii + + + (Boolean) + + + + — +

    whether to omit data that may contain PII from error messages

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+
+
# File 'elasticgraph-json_schema/lib/elastic_graph/json_schema/validator_factory.rb', line 22
+
+def initialize(schema:, sanitize_pii:)
+  @raw_schema = schema
+  @root_schema = ::JSONSchemer.schema(
+    schema,
+    meta_schema: schema.fetch("$schema"),
+    # Here we opt to have regular expressions resolved using an ecmo-compatible resolver, instead of Ruby's.
+    #
+    # We do this because regexp patterns in our JSON schema are intended to be used by JSON schema libraries
+    # in many languages, not just in Ruby, and we want to support the widest compatibility. For example,
+    # Ruby requires that we use `\A` and `\z` to anchor the start and end of the string (`^` and `$` anchor the
+    # start and end of a line instead), where as ecmo regexes treat `^` and `$` as the start and end of the string.
+    # For a pattern to be usable by non-Ruby publishers, we need to use `^/`$` for our start/end anchors, and we
+    # want our validator to treat it the same way here.
+    #
+    # Also, this was the default before json_schemer 1.0 (and we used 0.x versions for a long time...).
+    # This maintains the historical behavior we've had.
+    #
+    # For more info:
+    # https://github.com/davishmcclurg/json_schemer/blob/v1.0.0/CHANGELOG.md#breaking-changes
+    regexp_resolver: "ecma"
+  )
+
+  @sanitize_pii = sanitize_pii
+  @validators_by_type_name = ::Hash.new do |hash, key|
+    hash[key] = Validator.new(
+      schema: root_schema.ref("#/$defs/#{key}"),
+      sanitize_pii: sanitize_pii
+    )
+  end
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #validator_for(type_name) ⇒ Validator + + + + + +

+
+

Gets the ElasticGraph::JSONSchema::Validator for a particular ElasticGraph type.

+ + +
+
+
+

Parameters:

+
    + +
  • + + type_name + + + (String) + + + + — +

    name of an ElasticGraph type

    +
    + +
  • + +
+ +

Returns:

+ + +
+ + + + +
+
+
+
+57
+58
+59
+
+
# File 'elasticgraph-json_schema/lib/elastic_graph/json_schema/validator_factory.rb', line 57
+
+def validator_for(type_name)
+  @validators_by_type_name[type_name]
+end
+
+
+ +
+

+ + #with_unknown_properties_disallowed(except: []) ⇒ ValidatorFactory + + + + + +

+
+

Returns a new factory configured to disallow unknown properties. By default, JSON schema +allows unknown properties (they’ll simply be ignored when validating a JSON document). It +can be useful to validate more strictly, so that a document with properties not defined in +the JSON schema gets validation errors.

+ + +
+
+
+

Parameters:

+
    + +
  • + + except + + + (Array<String>) + + + (defaults to: []) + + + — +

    paths under which unknown properties should still be allowed

    +
    + +
  • + +
+ +

Returns:

+ + +
+ + + + +
+
+
+
+68
+69
+70
+71
+72
+73
+74
+
+
# File 'elasticgraph-json_schema/lib/elastic_graph/json_schema/validator_factory.rb', line 68
+
+def with_unknown_properties_disallowed(except: [])
+  allow_paths = except.map { |p| p.split(".") }
+  schema_copy = ::Marshal.load(::Marshal.dump(@raw_schema)) # deep copy so our mutations don't affect caller
+  prevent_unknown_properties!(schema_copy, allow_paths: allow_paths)
+
+  ValidatorFactory.new(schema: schema_copy, sanitize_pii: @sanitize_pii)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Local.html b/docs/main/ElasticGraph/Local.html new file mode 100644 index 00000000..a25d889d --- /dev/null +++ b/docs/main/ElasticGraph/Local.html @@ -0,0 +1,127 @@ + + + + + + + Module: ElasticGraph::Local + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Local + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb,
+ elasticgraph-local/lib/elastic_graph/local/docker_runner.rb,
elasticgraph-local/lib/elastic_graph/local/local_indexer.rb,
elasticgraph-local/lib/elastic_graph/local/indexing_coordinator.rb
+
+
+ +
+ +

Overview

+
+

Provides support for developing and running ElasticGraph applications locally.

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + + + Classes: RakeTasks + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Local/RakeTasks.html b/docs/main/ElasticGraph/Local/RakeTasks.html new file mode 100644 index 00000000..4654e1bd --- /dev/null +++ b/docs/main/ElasticGraph/Local/RakeTasks.html @@ -0,0 +1,1980 @@ + + + + + + + Class: ElasticGraph::Local::RakeTasks + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::Local::RakeTasks + + + +

+
+ +
+
Inherits:
+
+ Rake::TaskLib + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb
+
+ +
+ +

Overview

+
+ +
+ Note: +

All tasks (besides the schema_artifacts tasks) require docker and docker-compose to be available on your machine.

+
+
+ +

Defines tasks for local development. These tasks include:

+ +
    +
  • Running OpenSearch and/or Elasticsearch locally ((elasticsearch|opensearch):[env]:(boot|daemon|halt))
  • +
  • Managing schema artifacts (schema_artifacts:(check|dump))
  • +
  • Configuring OpenSearch/Elasticsearch locally (clusters:configure:(dry_run|perform))
  • +
  • Indexing fake data (index_fake_data:[type])
  • +
  • Booting an ElasticGraph application locally (boot_locally)
  • +
+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
UI_PORT_OFFSET = +
+
+

Offset we add to a port number for the UI (e.g. Kibana or OpenSearch Dashboards).

+ +

Example: if Elasticsearch/OpenSearch is running on port 9876, the UI for it will run on port 19876.

+ + +
+
+
+ + +
+
+
10_000
+ +
+ + + + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + + +
+

Constructor Details

+ +
+

+ + #initialize(local_config_yaml:, path_to_schema:) {|RakeTasks| ... } ⇒ RakeTasks + + + + + +

+
+ +
+ Note: +

This method uses keyword args for all required arguments. Optional task settings are instead specified using the block.

+
+
+ +

Returns a new instance of RakeTasks.

+ + +
+
+
+

Parameters:

+
    + +
  • + + local_config_yaml + + + (String, Pathname) + + + + — +

    path to the settings YAML file for the local/development environment

    +
    + +
  • + +
  • + + path_to_schema + + + (String, Pathname) + + + + — +

    path to the Ruby schema definition file–either the only file that defines the schema +(using ElasticGraph.define_schema) or the “main” schema definition file, which loads other files which further define parts of +the schema.

    +
    + +
  • + +
+ +

Yields:

+
    + +
  • + + + (RakeTasks) + + + + — +

    instance for further configuration

    +
    + +
  • + +
+

Yield Returns:

+
    + +
  • + + + (void) + + + +
  • + +
+ +
+ + + + +
+
+
+
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 352
+
+def initialize(local_config_yaml:, path_to_schema:)
+  @local_config_yaml = local_config_yaml.to_s
+
+  self.index_document_sizes = false
+  self.schema_element_name_form = :camelCase
+  self.schema_element_name_overrides = {}
+  self.derived_type_name_formats = {}
+  self.type_name_overrides = {}
+  self.enum_value_overrides_by_type = {}
+  self.schema_definition_extension_modules = []
+  self.enforce_json_schema_version = true
+  self.env_port_mapping = {}
+  self.output = $stdout
+  self.daemon_timeout = 120
+
+  datastore_versions = ::YAML.load_file("#{__dir__}/tested_datastore_versions.yaml")
+  self.elasticsearch_versions = datastore_versions.fetch("elasticsearch")
+  self.opensearch_versions = datastore_versions.fetch("opensearch")
+
+  @fake_data_batch_generator_by_type = {}
+
+  yield self if block_given?
+
+  # Default the local port from the local_config_yaml file.
+  self.env_port_mapping = {"local" => local_datastore_port}.merge(env_port_mapping || {})
+  if (invalid_port_mapping = env_port_mapping.reject { |env, port| VALID_PORT_RANGE.cover?(port) }).any?
+    raise "`env_port_mapping` has invalid ports: #{invalid_port_mapping.inspect}. Valid ports must be in the #{VALID_PORT_RANGE} range."
+  end
+
+  # Load admin and schema def rake tasks...
+  Admin::RakeTasks.from_yaml_file(local_config_yaml, output: output)
+  SchemaDefinition::RakeTasks.new(
+    index_document_sizes: index_document_sizes,
+    path_to_schema: path_to_schema,
+    schema_artifacts_directory: local_config.fetch("schema_artifacts").fetch("directory"),
+    schema_element_name_form: schema_element_name_form,
+    schema_element_name_overrides: schema_element_name_overrides,
+    derived_type_name_formats: derived_type_name_formats,
+    type_name_overrides: type_name_overrides,
+    enum_value_overrides_by_type: enum_value_overrides_by_type,
+    extension_modules: schema_definition_extension_modules,
+    enforce_json_schema_version: enforce_json_schema_version,
+    output: output
+  )
+
+  # ...then define a bunch of our own.
+  define_docker_tasks("Elasticsearch", "Kibana", elasticsearch_versions, /license \[[^\]]+\] mode \[[^\]]+\] - valid/)
+  define_docker_tasks("OpenSearch", "OpenSearch Dashboards", opensearch_versions, /o\.o\.n\.Node.+started/)
+  define_other_tasks
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #daemon_timeoutInteger + + + + + +

+
+

Maximum time (in seconds) to wait for the datastore to boot when booting it as a daemon. Defaults to 120.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Integer) + + + + — +

    maximum time in seconds to wait when booting Elasticsearch/OpenSearch as a daemon

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+312
+313
+314
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 312
+
+def daemon_timeout
+  @daemon_timeout
+end
+
+
+ + + +
+

+ + #derived_type_name_formatsObject + + + + + +

+
+

Overrides for the naming formats used by ElasticGraph for derived GraphQL type names. For example, to use Metrics instead of +AggregatedValues as the suffix for the generated types supporting getting aggregated metrid values, set to +{AggregatedValues: "%{base}Metrics"}. See SchemaDefinition::SchemaElements::TypeNamer::DEFAULT_FORMATS for the available +formats.

+ +

Defaults to an empty hash.

+ + +
+
+
+ +
+

Examples:

+ + +

Change the AggregatedValues type suffix to Metrics

+
+ +
ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  tasks.derived_type_name_formats = {AggregatedValues: "Metrics"}
+end
+ +
+ + +
+ + + + +
+
+
+
+109
+110
+111
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 109
+
+def derived_type_name_formats
+  @derived_type_name_formats
+end
+
+
+ + + +
+

+ + #elasticsearch_versionsArray<String> + + + + + +

+
+

List of Elasticsearch versions you want to be able to boot. Rake tasks will be defined for each version to support booting and +halting Elasticsearch locally. Defaults to the versions of Elasticsearch that are exercised by the ElasticGraph test suite, as +defined by lib/elastic_graph/local/tested_datastore_versions.yaml:

+ +

# This file determines the versions the ElasticGraph CI build tests against, and is also
# used to provide the default versions offered by the `elasticgraph-local` rake tasks.
elasticsearch:
- 8.15.1 # latest version as of 2024-09-06.
opensearch:
- 2.16.0 # latest version as of 2024-09-06.
- 2.7.0 # lowest version ElasticGraph currently supports

+ + +
+
+
+ +
+

Examples:

+ + +

Disable Elasticsearch tasks for a project that uses OpenSearch

+
+ +
ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  tasks.elasticsearch_versions = []
+end
+ +
+ +

Returns:

+
    + +
  • + + + (Array<String>) + + + + — +

    list of Elasticsearch versions

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+259
+260
+261
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 259
+
+def elasticsearch_versions
+  @elasticsearch_versions
+end
+
+
+ + + +
+

+ + #enforce_json_schema_versionBoolean + + + + + +

+
+ +
+ Note: +

Generally speaking, you will want this to be true for any ElasticGraph application that is in +production as the versioning of JSON schemas is what supports safe schema evolution as it allows +ElasticGraph to identify which version of the JSON schema the publishing system was operating on +when it published an event.

+ +

It can be useful to set it to false before your application is in production, as you do not want +to be forced to bump the version after every single schema change while you are building an initial +prototype.

+
+
+ +

Whether or not to enforce the requirement that the JSON schema version is incremented every time +dumping the JSON schemas results in a changed artifact. Defaults to true.

+ + +
+
+
+ +
+

Examples:

+ + +

Disable enforcement during initial prototyping

+
+ +
ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  # TODO: remove this once we're past the prototyping stage
+  tasks.enforce_json_schema_version = false
+end
+ +
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + + — +

    whether to require json_schema_version to be incremented on changes that impact json_schemas.yaml

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+239
+240
+241
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 239
+
+def enforce_json_schema_version
+  @enforce_json_schema_version
+end
+
+
+ + + +
+

+ + #enum_value_overrides_by_typeHash<Symbol, Hash<Symbol, String>> + + + + + +

+
+

Overrides for the names of specific GraphQL enum values for specific enum types. For example, to rename the DayOfWeek.MONDAY +enum to DayOfWeek.MON, set to {DayOfWeek: {MONDAY: "MON"}}.

+ +

Defaults to an empty hash.

+ + +
+
+
+ +
+

Examples:

+ + +

Shorten the names of the DayOfWeek enum values

+
+ +
ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  tasks.enum_value_overrides_by_type = {
+    DayOfWeek: {
+      MONDAY: "MON",
+      TUESDAY: "TUE",
+      WEDNESDAY: "WED",
+      THURSDAY: "THU",
+      FRIDAY: "FRI",
+      SATURDAY: "SAT",
+      SUNDAY: "SUN"
+    }
+  }
+end
+ +
+ +

Returns:

+
    + +
  • + + + (Hash<Symbol, Hash<Symbol, String>>) + + + + — +

    overrides for the names of specific enum values for specific enum types

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+155
+156
+157
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 155
+
+def enum_value_overrides_by_type
+  @enum_value_overrides_by_type
+end
+
+
+ + + +
+

+ + #env_port_mappingHash<Symbol, Integer> + + + + + +

+
+ +
+ Note: +

When booting Elasticsearch/OpenSearch, Kibana (or its OpenSearch equivalent, “OpenSearch Dashboards”) will also get booted, +selecting the port by adding 10000 to the configured port.

+
+
+ +

Hash mapping environments (e.g. :test, :dev, etc) to port numbers for use when booting Elasticsearch or OpenSearch. The hash +automatically includes an entry for the :local environment, using a port number extracted from local_config_yaml.

+ + +
+
+
+ +
+

Examples:

+ + +

Define what port to use to boot the datastore for the :test environment

+
+ +
ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  tasks.env_port_mapping = {test: 9999}
+end
+ +
+ +

Returns:

+
    + +
  • + + + (Hash<Symbol, Integer>) + + + + — +

    mapping from environment name to port number

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+298
+299
+300
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 298
+
+def env_port_mapping
+  @env_port_mapping
+end
+
+
+ + + +
+

+ + #index_document_sizesBoolean + + + + + +

+
+ +
+ Note: +

Enabling this requires the mapper-size plugin +to be installed on your datastore cluster. You are responsible for ensuring that is installed if you enable this feature. If you +enable this and the plugin is not installed, you will get errors!

+
+
+ +

When enabled, ElasticGraph will configure the index mappings so that the datastore indexes a _size field in each index document. +ElasticGraph itself does not do anything with this field, but it will be available for your use in any direct queries (e.g. via +Kibana).

+ +

Defaults to false since it requires a plugin.

+ + +
+
+
+ +
+

Examples:

+ + +

Enable indexing document sizes

+
+ +
ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  tasks.index_document_sizes = true
+end
+ +
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + + — +

    whether or not the _size field should be indexed on each indexed type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+49
+50
+51
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 49
+
+def index_document_sizes
+  @index_document_sizes
+end
+
+
+ + + +
+

+ + #opensearch_versionsArray<String> + + + + + +

+
+

List of OpenSearch versions you want to be able to boot. Rake tasks will be defined for each version to support booting and +halting OpenSearch locally. Defaults to the versions of OpenSearch that are exercised by the ElasticGraph test suite, as +defined by lib/elastic_graph/local/tested_datastore_versions.yaml:

+ +

# This file determines the versions the ElasticGraph CI build tests against, and is also
# used to provide the default versions offered by the `elasticgraph-local` rake tasks.
elasticsearch:
- 8.15.1 # latest version as of 2024-09-06.
opensearch:
- 2.16.0 # latest version as of 2024-09-06.
- 2.7.0 # lowest version ElasticGraph currently supports

+ + +
+
+
+ +
+

Examples:

+ + +

Disable OpenSearch tasks for a project that uses Elasticsearch

+
+ +
ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  tasks.opensearch_versions = []
+end
+ +
+ +

Returns:

+
    + +
  • + + + (Array<String>) + + + + — +

    list of OpenSearch versions

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+279
+280
+281
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 279
+
+def opensearch_versions
+  @opensearch_versions
+end
+
+
+ + + +
+

+ + #outputIO + + + + + +

+
+

IO for printing output (defaults to stdout).

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (IO) + + + + — +

    IO object used for printing output.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+305
+306
+307
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 305
+
+def output
+  @output
+end
+
+
+ + + +
+

+ + #schema_definition_extension_modulesArray<Module> + + + + + +

+
+

List of Ruby modules to extend onto the SchemaDefinition::API instance. Designed to support ElasticGraph extensions (such as +Apollo::SchemaDefinition::APIExtension). Defaults to an empty list.

+ + +
+
+
+ +
+

Examples:

+ + +

Use elasticgraph-apollo

+
+ +
require "elastic_graph/apollo/schema_definition/api_extension"
+
+ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  tasks.schema_definition_extension_modules = [ElasticGraph::Apollo::SchemaDefinition::APIExtension]
+end
+ + +

Extension that defines a @since directive and offers a since API on fields

+
+ +
module SinceExtension
+  # `self.extended` is a standard Ruby hook that gets called when a module is extended onto an object.
+  # The argument is the object the module was extended onto (a `SchemaDefinition::API` instance in this case).
+  def self.extended(api)
+    # Define our `@since` directive
+    api.raw_sdl "directive @since(date: Date!) on FIELD_DEFINITION"
+
+    # In order to hook into fields, extend the `SchemaDefinition::Factory` with a module. The factory is used
+    # for creation of all schema definition objects.
+    api.factory.extend FactoryExtension
+  end
+
+  module FactoryExtension
+    # Hook into the creation of all `SchemaDefinition::Field` objects so that we can extend each field
+    # instance with our `FieldExtension` module.
+    def new_field(*args, **options)
+      super(*args, **options) do |field|
+        field.extend FieldExtension
+        yield field if block_given?
+      end
+    end
+  end
+
+  # Offer a `f.since date` API on fields.
+  module FieldExtension
+    def since(date)
+      directive "since", date: date
+    end
+  end
+end
+
+ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  tasks.schema_definition_extension_modules = [SinceExtension]
+end
+ +
+ +

Returns:

+
    + +
  • + + + (Array<Module>) + + + + — +

    list of extension modules

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+212
+213
+214
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 212
+
+def schema_definition_extension_modules
+  @schema_definition_extension_modules
+end
+
+
+ + + +
+

+ + #schema_element_name_form:camelCase, :snake_case + + + + + +

+
+

The form of names for schema elements (fields, arguments, directives) generated by ElasticGraph, either :snake_case or +:camelCase. For example, if set to :camelCase, ElasticGraph will generate a groupedBy field, but if set to :snake_case, +ElasticGraph will generate a grouped_by field.

+ +

Defaults to :camelCase since most GraphQL schemas use that casing.

+ + +
+
+
+ +
+

Examples:

+ + +

Use snake_case names instead of camelCase

+
+ +
ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  tasks.schema_element_name_form = :snake_case
+end
+ +
+ +

Returns:

+
    + +
  • + + + (:camelCase, :snake_case) + + + + — +

    which form to use

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+68
+69
+70
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 68
+
+def schema_element_name_form
+  @schema_element_name_form
+end
+
+
+ + + +
+

+ + #schema_element_name_overridesHash<Symbol, String> + + + + + +

+
+

Overrides for specific names of schema elements (fields, arguments, directives) generated by ElasticGraph. For example, to rename +the gt filter field to greaterThan, set to {gt: "greaterThan"}.

+ +

Defaults to an empty hash.

+ + +
+
+
+ +
+

Examples:

+ + +

Spell out comparison operators instead of using shortened forms

+
+ +
ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  tasks.schema_element_name_overrides = {
+    gt: "greaterThan",
+    gte: "greaterThanOrEqualTo",
+    lt: "lessThan",
+    lte: "lessThanOrEqualTo"
+  }
+end
+ +
+ +

Returns:

+
    + +
  • + + + (Hash<Symbol, String>) + + + + — +

    overrides for specific field, argument, or directive names

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+91
+92
+93
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 91
+
+def schema_element_name_overrides
+  @schema_element_name_overrides
+end
+
+
+ + + +
+

+ + #type_name_overridesHash<Symbol, String> + + + + + +

+
+

Overrides for the names of specific GraphQL types. For example, to rename the JsonSafeLong scalar to BigInt, set to +{JsonSafeLong: "BigInt}.

+ +

Defaults to an empty hash.

+ + +
+
+
+ +
+

Examples:

+ + +

Rename JsonSafeLong to BigInt

+
+ +
ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  tasks.type_name_overrides = {JsonSafeLong: "BigInt"}
+end
+ +
+ +

Returns:

+
    + +
  • + + + (Hash<Symbol, String>) + + + + — +

    overrides for specific type names

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+127
+128
+129
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 127
+
+def type_name_overrides
+  @type_name_overrides
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #define_fake_data_batch_for(type) {|Array<Hash<String, Object>>, Array<Hash<Symbol, Object>>| ... } ⇒ Object + + + + + +

+
+

Register a callback for use when indexing a batch fake data. An index_fake_data:[type] rake task will be generated for each +registered callback.

+ + +
+
+
+ +
+

Examples:

+ + +

Register a callback to generate fake campaigns data

+
+ +
ElasticGraph::Local::RakeTasks.new(
+  local_config_yaml: "config/settings/local.yaml",
+  path_to_schema: "config/schema.rb"
+) do |tasks|
+  tasks.define_fake_data_batch_for :campaigns do |batch|
+    batch.concat(FactoryBot.build_list(:campaigns))
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + type + + + (Symbol) + + + + — +

    type of data batch. Can be the name of a GraphQL type or any other name you want to give a batch of fake data

    +
    + +
  • + +
+ +

Yields:

+
    + +
  • + + + (Array<Hash<String, Object>>, Array<Hash<Symbol, Object>>) + + + + — +

    list the block should append to when generating data

    +
    + +
  • + +
+

Yield Returns:

+
    + +
  • + + + (void) + + + +
  • + +
+ +
+ + + + +
+
+
+
+341
+342
+343
+
+
# File 'elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb', line 341
+
+def define_fake_data_batch_for(type, &block)
+  @fake_data_batch_generator_by_type[type] = block
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Rack.html b/docs/main/ElasticGraph/Rack.html new file mode 100644 index 00000000..789b7f00 --- /dev/null +++ b/docs/main/ElasticGraph/Rack.html @@ -0,0 +1,137 @@ + + + + + + + Module: ElasticGraph::Rack + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Rack + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-rack/lib/elastic_graph/rack.rb,
+ elasticgraph-rack/lib/elastic_graph/rack/graphiql.rb,
elasticgraph-rack/lib/elastic_graph/rack/graphql_endpoint.rb
+
+
+ +
+ +

Overview

+
+

Adapts an ElasticGraph GraphQL endpoint to run as a Rack application. +This allows an ElasticGraph GraphQL endpoint to run inside any Rack-compatible web +framework, including Ruby on Rails, +or as a stand-alone application. Two configurations are supported:

+ + + + +
+
+
+ + +

Defined Under Namespace

+

+ + + Modules: GraphiQL + + + + Classes: GraphQLEndpoint + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Rack/GraphQLEndpoint.html b/docs/main/ElasticGraph/Rack/GraphQLEndpoint.html new file mode 100644 index 00000000..2ed3dbde --- /dev/null +++ b/docs/main/ElasticGraph/Rack/GraphQLEndpoint.html @@ -0,0 +1,400 @@ + + + + + + + Class: ElasticGraph::Rack::GraphQLEndpoint + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::Rack::GraphQLEndpoint + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-rack/lib/elastic_graph/rack/graphql_endpoint.rb
+
+ +
+ +

Overview

+
+

A simple Rack wrapper around an ElasticGraph GraphQL endpoint. +This can be used for local development, mounted in a Rails application, +or run in any other Rack-compatible context.

+ + +
+
+
+ +
+

Examples:

+ + +

Simple config.ru to run an ElasticGraph endpoint as a Rack application

+
+ +
require "elastic_graph/graphql"
+require "elastic_graph/rack/graphql_endpoint"
+
+graphql = ElasticGraph::GraphQL.from_yaml_file("config/settings/development.yaml")
+run ElasticGraph::Rack::GraphQLEndpoint.new(graphql)
+ +
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(graphql) ⇒ GraphQLEndpoint + + + + + +

+
+

Returns a new instance of GraphQLEndpoint.

+ + +
+
+
+

Parameters:

+
    + +
  • + + graphql + + + (ElasticGraph::GraphQL) + + + + — +

    ElasticGraph GraphQL instance

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+26
+27
+28
+29
+
+
# File 'elasticgraph-rack/lib/elastic_graph/rack/graphql_endpoint.rb', line 26
+
+def initialize(graphql)
+  @logger = graphql.logger
+  @graphql_http_endpoint = graphql.graphql_http_endpoint
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #call(env) ⇒ Array(Integer, Hash<String, String>, Array<String>) + + + + + +

+
+

Responds to a Rack request.

+ + +
+
+
+

Parameters:

+
    + +
  • + + env + + + (Hash<String, Object>) + + + + — +

    Rack env

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array(Integer, Hash<String, String>, Array<String>)) + + + +
  • + +
+ +
+ + + + +
+
+
+
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+
+
# File 'elasticgraph-rack/lib/elastic_graph/rack/graphql_endpoint.rb', line 35
+
+def call(env)
+  rack_request = ::Rack::Request.new(env)
+
+  # Rack doesn't provide a nice method to provide all HTTP headers. In general,
+  # HTTP headers are prefixed with `HTTP_` as per https://stackoverflow.com/a/6318491/16481862,
+  # but `Content-Type`, as a "standard" header, isn't exposed that way, sadly.
+  headers = env
+    .select { |k, v| k.start_with?("HTTP_") }
+    .to_h { |k, v| [k.delete_prefix("HTTP_"), v] }
+    .merge("Content-Type" => rack_request.content_type)
+
+  request = GraphQL::HTTPRequest.new(
+    http_method: rack_request.request_method.downcase.to_sym,
+    url: rack_request.url,
+    headers: headers,
+    body: rack_request.body&.read
+  )
+
+  response = @graphql_http_endpoint.process(request)
+
+  [response.status_code, response.headers.transform_keys(&:downcase), [response.body]]
+rescue => e
+  raise if ENV["RACK_ENV"] == "test"
+
+  @logger.error "Got an exception: #{e.class.name}: #{e.message}\n\n#{e.backtrace.join("\n")}"
+  error = {message: e.message, exception_class: e.class, backtrace: e.backtrace}
+  [500, {"content-type" => "application/json"}, [::JSON.generate(errors: [error])]]
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Rack/GraphiQL.html b/docs/main/ElasticGraph/Rack/GraphiQL.html new file mode 100644 index 00000000..f5b83d02 --- /dev/null +++ b/docs/main/ElasticGraph/Rack/GraphiQL.html @@ -0,0 +1,265 @@ + + + + + + + Module: ElasticGraph::Rack::GraphiQL + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Rack::GraphiQL + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-rack/lib/elastic_graph/rack/graphiql.rb
+
+ +
+ +

Overview

+
+

A Rack application that serves both an ElasticGraph GraphQL endpoint +and a GraphiQL IDE. This can be used for local development, +mounted in a Rails application, or run in any other Rack-compatible context.

+ + +
+
+
+ +
+

Examples:

+ + +

Simple config.ru to run GraphiQL as a Rack application, targeting an ElasticGraph endpoint

+
+ +
require "elastic_graph/graphql"
+require "elastic_graph/rack/graphiql"
+
+graphql = ElasticGraph::GraphQL.from_yaml_file("config/settings/development.yaml")
+run ElasticGraph::Rack::GraphiQL.new(graphql)
+ +
+ + +
+ + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .new(graphql) ⇒ Rack::Builder + + + + + +

+
+

Builds a Rack application that serves both an ElasticGraph GraphQL endpoint +and a GraphiQL IDE.

+ + +
+
+
+

Parameters:

+
    + +
  • + + graphql + + + (ElasticGraph::GraphQL) + + + + — +

    ElasticGraph GraphQL instance

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Rack::Builder) + + + + — +

    built Rack application

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+
+
# File 'elasticgraph-rack/lib/elastic_graph/rack/graphiql.rb', line 31
+
+def self.new(graphql)
+  graphql_endpoint = ElasticGraph::Rack::GraphQLEndpoint.new(graphql)
+
+  ::Rack::Builder.new do
+    use ::Rack::Static, urls: {"/" => "index.html"}, root: ::File.join(__dir__, "graphiql")
+
+    map "/graphql" do
+      run graphql_endpoint
+    end
+  end
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition.html b/docs/main/ElasticGraph/SchemaDefinition.html new file mode 100644 index 00000000..730ac5c5 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition.html @@ -0,0 +1,129 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb,
+ elasticgraph-schema_definition/lib/elastic_graph/schema_definition/state.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/factory.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/results.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/rake_tasks.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/test_support.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/scripting/script.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/json_schema_pruner.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_indices.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_subtypes.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_type_info.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_directives.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/event_envelope.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_artifact_manager.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_reference.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/rollover_config.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_documentation.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/argument.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/union.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/directive.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/object.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/can_be_graphql_only.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field_path.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/input_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_namer.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/union_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/input_field.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/object_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/list_counts_mapping.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/verifies_graphql_name.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field_source.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/relationship.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/supports_default_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/relationship_resolver.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/update_target_factory.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/built_in_types.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/interface_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_reference.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/update_target_resolver.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_value_namer.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/scripting/file_system_repository.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/list_counts_state.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/json_schema_with_metadata.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/deprecated_element.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/json_schema_field_metadata.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/sub_aggregation_path.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/sort_order_enum_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/graphql_sdl_enumerator.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/append_only_set.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/immutable_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enums_for_indexed_types.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/supports_filtering_and_aggregation.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_derived_graphql_type_customizations.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/field_initializer_support.rb
+
+
+ +
+ +

Overview

+
+

Provides the ElasticGraph schema definition API. The primary entry point is define_schema.

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + Modules: Indexing, Mixins, SchemaElements + + + + Classes: API, RakeTasks, Results + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/API.html b/docs/main/ElasticGraph/SchemaDefinition/API.html new file mode 100644 index 00000000..e59d6a73 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/API.html @@ -0,0 +1,1645 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::API + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::API + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb
+
+ +
+ +

Overview

+
+

Root API object that provides the schema definition API.

+ + +
+
+
+ +
+

Examples:

+ + +
ElasticGraph.define_schema do |schema|
+  # The `schema` object is an instance of `API`
+end
+ +
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + + +
+

Instance Attribute Details

+ + + +
+

+ + #factoryFactory (readonly) + + + + + +

+
+

Returns object responsible for instantiating all schema element classes.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Factory) + + + + — +

    object responsible for instantiating all schema element classes

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+51
+52
+53
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb', line 51
+
+def factory
+  @factory
+end
+
+
+ + + +
+

+ + #stateState (readonly) + + + + + +

+
+

Returns object which holds all state for the schema definition.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (State) + + + + — +

    object which holds all state for the schema definition

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+48
+49
+50
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb', line 48
+
+def state
+  @state
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #deleted_type(name) ⇒ void + + + + + +

+
+ +
+ Note: +

In situations where this API applies, ElasticGraph will give you an error message indicating that you need to use this API +or SchemaElements::TypeWithSubfields#renamed_from. Likewise, when ElasticGraph no longer needs to know about this, it’ll give you a warning +indicating the call to this method can be removed.

+
+
+ +

This method returns an undefined value.

Registers the name of a type that existed in a prior version of the schema but has been deleted.

+ + +
+
+
+ +
+

Examples:

+ + +

Indicate that Widget has been deleted

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.deleted_type "Widget"
+end
+ +
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    name of type that used to exist but has been deleted

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+261
+262
+263
+264
+265
+266
+267
+268
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb', line 261
+
+def deleted_type(name)
+  @state.register_deleted_type(
+    name,
+    defined_at: caller_locations(1, 1).first, # : ::Thread::Backtrace::Location
+    defined_via: %(schema.deleted_type "#{name}")
+  )
+  nil
+end
+
+
+ +
+

+ + #enum_type(name) {|SchemaElements::EnumType| ... } ⇒ void + + + + + +

+
+

This method returns an undefined value.

Defines a GraphQL enum type. +The type is restricted to an enumerated set of values, each with a unique name. +Use value or values to define the enum values in the passed block.

+ +

Note: if required by your configuration, this may generate a pair of Enum types (an input +enum and an output enum).

+ + +
+
+
+ +
+

Examples:

+ + +

Define an enum type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.enum_type "Currency" do |t|
+    t.value "USD" do |v|
+      v.documentation "US Dollars."
+    end
+
+    t.value "JPY" do |v|
+      v.documentation "Japanese Yen."
+    end
+
+    # You can define multiple values in one call if you don't care about their docs or directives.
+    t.values "GBP", "AUD"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    name of the enum type

    +
    + +
  • + +
+ +

Yields:

+ + +
+ + + + +
+
+
+
+193
+194
+195
+196
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb', line 193
+
+def enum_type(name, &block)
+  @state.register_enum_type @factory.new_enum_type(name.to_s, &block)
+  nil
+end
+
+
+ +
+

+ + #interface_type(name) {|SchemaElements::InterfaceType| ... } ⇒ void + + + + + +

+
+

This method returns an undefined value.

Defines a GraphQL interface. Use it to define an abstract supertype with +one or more fields that concrete implementations of the interface must also define. Each implementation can be an +SchemaElements::ObjectType or SchemaElements::InterfaceType.

+ + +
+
+
+ +
+

Examples:

+ + +

Define an interface and implement it

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.interface_type "Athlete" do |t|
+    t.field "name", "String"
+    t.field "team", "String"
+  end
+
+  schema.object_type "BaseballPlayer" do |t|
+    t.implements "Athlete"
+    t.field "name", "String"
+    t.field "team", "String"
+    t.field "battingAvg", "Float"
+  end
+
+  schema.object_type "BasketballPlayer" do |t|
+    t.implements "Athlete"
+    t.field "name", "String"
+    t.field "team", "String"
+    t.field "pointsPerGame", "Float"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    name of the interface

    +
    + +
  • + +
+ +

Yields:

+ + +
+ + + + +
+
+
+
+162
+163
+164
+165
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb', line 162
+
+def interface_type(name, &block)
+  @state.register_object_interface_or_union_type @factory.new_interface_type(name.to_s, &block)
+  nil
+end
+
+
+ +
+

+ + #json_schema_version(version) ⇒ void + + + + + +

+
+ +
+ Note: +

While this is an important part of how ElasticGraph is designed to support schema evolution, it can be annoying constantly +have to increment this while rapidly changing the schema during prototyping. You can disable the requirement to increment this +on every JSON schema change by setting enforce_json_schema_version to false in your Rakefile.

+
+
+ +

This method returns an undefined value.

Defines the version number of the current JSON schema. Importantly, every time a change is made that impacts the JSON schema +artifact, the version number must be incremented to ensure that each different version of the JSON schema is identified by a unique +version number. The publisher will then include this version number in published events to identify the version of the schema it +was using. This avoids the need to deploy the publisher and ElasticGraph indexer at the same time to keep them in sync.

+ + +
+
+
+ +
+

Examples:

+ + +

Set the JSON schema version to 1

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.json_schema_version 1
+end
+ +
+

Parameters:

+
    + +
  • + + version + + + (Integer) + + + + — +

    current version number of the JSON schema artifact

    +
    + +
  • + +
+ + +

See Also:

+ + +
+ + + + +
+
+
+
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb', line 315
+
+def json_schema_version(version)
+  if !version.is_a?(Integer) || version < 1
+    raise Errors::SchemaError, "`json_schema_version` must be a positive integer. Specified version: #{version}"
+  end
+
+  if @state.json_schema_version
+    raise Errors::SchemaError, "`json_schema_version` can only be set once on a schema. Previously-set version: #{@state.json_schema_version}"
+  end
+
+  @state.json_schema_version = version
+  @state.json_schema_version_setter_location = caller_locations(1, 1).to_a.first
+  nil
+end
+
+
+ +
+

+ + #object_type(name) {|SchemaElements::ObjectType| ... } ⇒ void + + + + + +

+
+

This method returns an undefined value.

Defines a GraphQL object type Use it to define a concrete type that +has subfields. Object types can either be indexed (e.g. directly indexed in the datastore, and available to query from the +root Query object) or embedded in other indexed types.

+ + +
+
+
+ +
+

Examples:

+ + +

Define embedded and indexed object types

+
+ +
ElasticGraph.define_schema do |schema|
+  # `Money` is an embedded object type
+  schema.object_type "Money" do |t|
+    t.field "currency", "String"
+    t.field "amount", "JsonSafeLong"
+  end
+
+  # `Transaction` is an indexed object type
+  schema.object_type "Transaction" do |t|
+    t.root_query_fields plural: "transactions"
+    t.field "id", "ID"
+    t.field "cost", "Money"
+    t.index "transactions"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    name of the object type

    +
    + +
  • + +
+ +

Yields:

+ + +
+ + + + +
+
+
+
+128
+129
+130
+131
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb', line 128
+
+def object_type(name, &block)
+  @state.register_object_interface_or_union_type @factory.new_object_type(name.to_s, &block)
+  nil
+end
+
+
+ +
+

+ + #on_built_in_types {|SchemaElements::EnumType, SchemaElements::InputType, SchemaElements::InterfaceType, SchemaElements::ObjectType, SchemaElements::ScalarType, SchemaElements::UnionType| ... } ⇒ void + + + + + +

+
+

This method returns an undefined value.

Registers a customization callback that will be applied to every built-in type automatically provided by ElasticGraph. Provides +an opportunity to customize the built-in types (e.g. to add directives to them or whatever).

+ + +
+
+
+ +
+

Examples:

+ + +

Customize documentation of built-in types

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.on_built_in_types do |type|
+    type.append_to_documentation "This is a built-in ElasticGraph type."
+  end
+end
+ +
+ +

Yields:

+ + +
+ + + + +
+
+
+
+341
+342
+343
+344
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb', line 341
+
+def on_built_in_types(&customization_block)
+  @state.built_in_types_customization_blocks << customization_block
+  nil
+end
+
+
+ +
+

+ + #raw_sdl(string) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Defines a raw GraphQL SDL snippet that will be included in the generated schema.graphql artifact. Designed to be an escape hatch, +for when ElasticGraph doesn’t provide another way to write some type of GraphQL SDL element that you need. Currently, the only +known use case is to define custom GraphQL directives.

+ + +
+
+
+ +
+

Examples:

+ + +

Define a custom directive and use it

+
+ +
ElasticGraph.define_schema do |schema|
+  # Define a directive we can use to annotate what system a data type comes from.
+  schema.raw_sdl "directive @sourcedFrom(system: String!) on OBJECT"
+
+  schema.object_type "Transaction" do |t|
+    t.directive "sourcedFrom", system: "transaction-processor"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + string + + + (String) + + + + — +

    Raw snippet of SDL

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+99
+100
+101
+102
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb', line 99
+
+def raw_sdl(string)
+  @state.sdl_parts << string
+  nil
+end
+
+
+ +
+

+ + #register_graphql_extension(extension_module, defined_at:, **extension_config) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Registers a GraphQL extension module that will be loaded and used by elasticgraph-graphql. While such +extension modules can also be configured in a settings YAML file, it can be useful to register it here +when you want to ensure that the extension is used in all environments. For example, an extension library +that defines custom schema elements (such as elasticgraph-apollo) may need to ensure its corresponding +GraphQL extension module is used since the custom schema elements would not work correctly otherwise.

+ + +
+
+
+ +
+

Examples:

+ + +

Register elasticgraph-query_registry extension module

+
+ +
require(query_registry_require_path = "elastic_graph/query_registry/graphql_extension")
+
+ElasticGraph.define_schema do |schema|
+  schema.register_graphql_extension ElasticGraph::QueryRegistry::GraphQLExtension,
+    defined_at: query_registry_require_path
+end
+ +
+

Parameters:

+
    + +
  • + + extension_module + + + (Module) + + + + — +

    GraphQL extension module

    +
    + +
  • + +
  • + + defined_at + + + (String) + + + + — +

    the require path of the extension module

    +
    + +
  • + +
  • + + extension_config + + + (Hash<Symbol, Object>) + + + + — +

    configuration options for the extension module

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+288
+289
+290
+291
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb', line 288
+
+def register_graphql_extension(extension_module, defined_at:, **extension_config)
+  @state.graphql_extension_modules << SchemaArtifacts::RuntimeMetadata::Extension.new(extension_module, defined_at, extension_config)
+  nil
+end
+
+
+ +
+

+ + #resultsObject + + + + + +

+
+

Returns the results of the schema definition.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + + + + + +

    the results of the schema definition

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+294
+295
+296
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb', line 294
+
+def results
+  @results ||= Results.new(@state)
+end
+
+
+ +
+

+ + #scalar_type(name) {|SchemaElements::ScalarType| ... } ⇒ void + + + + + +

+
+

This method returns an undefined value.

Defines a GraphQL scalar type. ElasticGraph itself uses this to define a few +common scalar types (e.g. Date and DateTime), but it is also available to you to use to define your own custom scalar types.

+ + +
+
+
+ +
+

Examples:

+ + +

Define a scalar type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.scalar_type "URL" do |t|
+    t.mapping type: "keyword"
+    t.json_schema type: "string", format: "uri"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    name of the scalar type

    +
    + +
  • + +
+ +

Yields:

+ + +
+ + + + +
+
+
+
+243
+244
+245
+246
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb', line 243
+
+def scalar_type(name, &block)
+  @state.register_scalar_type @factory.new_scalar_type(name.to_s, &block)
+  nil
+end
+
+
+ +
+

+ + #union_type(name) {|SchemaElements::UnionType| ... } ⇒ void + + + + + +

+
+

This method returns an undefined value.

Defines a GraphQL union type. Use it to define an abstract supertype with one or +more concrete subtypes. Each subtype must be an SchemaElements::ObjectType, but they do not have to share any fields in common.

+ + +
+
+
+ +
+

Examples:

+ + +

Define a union type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Card" do |t|
+    # ...
+  end
+
+  schema.object_type "BankAccount" do |t|
+    # ...
+  end
+
+  schema.object_type "BitcoinWallet" do |t|
+    # ...
+  end
+
+  schema.union_type "FundingSource" do |t|
+    t.subtype "Card"
+    t.subtypes "BankAccount", "BitcoinWallet"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    name of the union type

    +
    + +
  • + +
+ +

Yields:

+ + +
+ + + + +
+
+
+
+224
+225
+226
+227
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb', line 224
+
+def union_type(name, &block)
+  @state.register_object_interface_or_union_type @factory.new_union_type(name.to_s, &block)
+  nil
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing.html new file mode 100644 index 00000000..2c333a2c --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing.html @@ -0,0 +1,129 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Indexing + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Indexing + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb,
+ elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/event_envelope.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_reference.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/rollover_config.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/union.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/object.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/list_counts_mapping.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/relationship_resolver.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/update_target_factory.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/update_target_resolver.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/json_schema_with_metadata.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/json_schema_field_metadata.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/append_only_set.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/immutable_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/field_initializer_support.rb
+
+
+ +
+ +

Overview

+
+

Contains schema definition logic specific to indexing (such as JSON schema and mapping generation).

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + Modules: DerivedFields, EventEnvelope, FieldType + + + + Classes: DerivedIndexedType, Field, FieldReference, Index, JSONSchemaFieldMetadata + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields.html new file mode 100644 index 00000000..8f478d8d --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields.html @@ -0,0 +1,133 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Indexing::DerivedFields + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Indexing::DerivedFields + + + Private +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/field_initializer_support.rb,
+ elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/append_only_set.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/immutable_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb
+
+
+ +
+ +

Overview

+
+

+ This module is part of a private API. + You should avoid using this module if possible, as it may be removed or be changed in the future. +

+

Contains implementation logic for the different kinds of derived fields.

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + Modules: FieldInitializerSupport + + + + Classes: AppendOnlySet, ImmutableValue, MinOrMaxValue + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields/AppendOnlySet.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields/AppendOnlySet.html new file mode 100644 index 00000000..4915f8c3 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields/AppendOnlySet.html @@ -0,0 +1,405 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::Indexing::DerivedFields::AppendOnlySet + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::Indexing::DerivedFields::AppendOnlySet + + + Private +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/append_only_set.rb
+
+ +
+ +

Overview

+
+

+ This class is part of a private API. + You should avoid using this class if possible, as it may be removed or be changed in the future. +

+

Responsible for providing bits of the painless script specific to a ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType#append_only_set field.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apply_operation_returning_update_statusString + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns a line of painless code to append a value to the set and return a boolean indicating if the set was updated.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    a line of painless code to append a value to the set and return a boolean indicating if the set was updated.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+28
+29
+30
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/append_only_set.rb', line 28
+
+def apply_operation_returning_update_status
+  %{appendOnlySet_idempotentlyInsertValues(data["#{source_field}"], ctx._source.#{destination_field})}
+end
+
+
+ +
+

+ + #function_definitionsArray<String> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns painless functions required by append_only_set.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Array<String>) + + + + — +

    painless functions required by append_only_set.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+23
+24
+25
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/append_only_set.rb', line 23
+
+def function_definitions
+  [IDEMPOTENTLY_INSERT_VALUES, IDEMPOTENTLY_INSERT_VALUE]
+end
+
+
+ +
+

+ + #setup_statementsArray<String> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

The statements here initialize the field to an empty list if it is null. This primarily happens when the document +does not already exist, but can also happen when we add a new derived field to an existing type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Array<String>) + + + + — +

    a list of painless statements that must be called at the top of the script to set things up.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+36
+37
+38
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/append_only_set.rb', line 36
+
+def setup_statements
+  FieldInitializerSupport.build_empty_value_initializers(destination_field, leaf_value: FieldInitializerSupport::EMPTY_PAINLESS_LIST)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields/FieldInitializerSupport.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields/FieldInitializerSupport.html new file mode 100644 index 00000000..7d1c1749 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields/FieldInitializerSupport.html @@ -0,0 +1,393 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Indexing::DerivedFields::FieldInitializerSupport + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Indexing::DerivedFields::FieldInitializerSupport + + + Private +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/field_initializer_support.rb
+
+ +
+ +

Overview

+
+

+ This module is part of a private API. + You should avoid using this module if possible, as it may be removed or be changed in the future. +

+

Contains helper logic for field initialization applicable to all types of derived fields.

+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
EMPTY_PAINLESS_LIST = +
+
+

+ This constant is part of a private API. + You should avoid using this constant if possible, as it may be removed or be changed in the future. +

+

Painless literal for an empty list, from the docs.

+ + +
+
+
+ + +
+
+
"[]"
+ +
EMPTY_PAINLESS_MAP = +
+
+

+ This constant is part of a private API. + You should avoid using this constant if possible, as it may be removed or be changed in the future. +

+

Painless literal for an empty map, from the docs.

+ + +
+
+
+ + +
+
+
"[:]"
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .build_empty_value_initializers(destination_field, leaf_value:) ⇒ Array<String> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns a list of painless statements that will initialize a given destination_field path to an empty value.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Array<String>) + + + + — +

    a list of painless statements that will initialize a given destination_field path to an empty value.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/field_initializer_support.rb', line 27
+
+def self.build_empty_value_initializers(destination_field, leaf_value:)
+  snippets = [] # : ::Array[::String]
+  path_so_far = [] # : ::Array[::String]
+
+  destination_field.split(".").each do |path_part|
+    path_to_this_part = (path_so_far + [path_part]).join(".")
+    is_leaf = path_to_this_part == destination_field
+
+    unless is_leaf && leaf_value == :leave_unset
+      # The empty value of all parent fields must be an empty painless map, but for a leaf field it can be different.
+      empty_value = is_leaf ? leaf_value : EMPTY_PAINLESS_MAP
+
+      snippets << default_source_field_to_empty(path_to_this_part, empty_value.to_s)
+      path_so_far << path_part
+    end
+  end
+
+  snippets
+end
+
+
+ +
+

+ + .default_source_field_to_empty(field_path, empty_value) ⇒ String + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns a painless statement that will default a single field to an empty value.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    a painless statement that will default a single field to an empty value.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+48
+49
+50
+51
+52
+53
+54
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/field_initializer_support.rb', line 48
+
+def self.default_source_field_to_empty(field_path, empty_value)
+  <<~EOS.strip
+    if (ctx._source.#{field_path} == null) {
+      ctx._source.#{field_path} = #{empty_value};
+    }
+  EOS
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields/ImmutableValue.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields/ImmutableValue.html new file mode 100644 index 00000000..0fdaf25f --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields/ImmutableValue.html @@ -0,0 +1,410 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::Indexing::DerivedFields::ImmutableValue + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::Indexing::DerivedFields::ImmutableValue + + + Private +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/immutable_value.rb
+
+ +
+ +

Overview

+
+

+ This class is part of a private API. + You should avoid using this class if possible, as it may be removed or be changed in the future. +

+

Responsible for providing bits of the painless script specific to a ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType#immutable_value field.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #apply_operation_returning_update_statusString + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns a line of painless code to manage an immutable value field and return a boolean indicating if it was updated.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    a line of painless code to manage an immutable value field and return a boolean indicating if it was updated.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+21
+22
+23
+24
+25
+26
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/immutable_value.rb', line 21
+
+def apply_operation_returning_update_status
+  *parent_parts, field = destination_field.split(".")
+  parent_parts = ["ctx", "_source"] + parent_parts
+
+  %{immutableValue_idempotentlyUpdateValue(scriptErrors, data["#{source_field}"], #{parent_parts.join(".")}, "#{destination_field}", "#{field}", #{nullable}, #{can_change_from_null})}
+end
+
+
+ +
+

+ + #function_definitionsArray<String> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns painless functions required by immutable_value.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Array<String>) + + + + — +

    painless functions required by immutable_value.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+34
+35
+36
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/immutable_value.rb', line 34
+
+def function_definitions
+  [IDEMPOTENTLY_SET_VALUE]
+end
+
+
+ +
+

+ + #setup_statementsArray<String> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns a list of painless statements that must be called at the top of the script to set things up.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Array<String>) + + + + — +

    a list of painless statements that must be called at the top of the script to set things up.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+29
+30
+31
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/immutable_value.rb', line 29
+
+def setup_statements
+  FieldInitializerSupport.build_empty_value_initializers(destination_field, leaf_value: :leave_unset)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields/MinOrMaxValue.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields/MinOrMaxValue.html new file mode 100644 index 00000000..fa4442c5 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedFields/MinOrMaxValue.html @@ -0,0 +1,557 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::Indexing::DerivedFields::MinOrMaxValue + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::Indexing::DerivedFields::MinOrMaxValue + + + Private +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb
+
+ +
+ +

Overview

+
+

+ This class is part of a private API. + You should avoid using this class if possible, as it may be removed or be changed in the future. +

+

Responsible for providing bits of the painless script specific to a ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType#min_value or +ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType#max_value field.

+ + +
+
+
+ + +
+ + + + + + + +

+ Class Method Summary + collapse +

+ + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .function_def(min_or_max) ⇒ String + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns painless function for managing a min or max field.

+ + +
+
+
+

Parameters:

+
    + +
  • + + min_or_max + + + (:min, :max) + + + + — +

    which type of function to generate.

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    painless function for managing a min or max field.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb', line 41
+
+def self.function_def(min_or_max)
+  operator = (min_or_max == :min) ? "<" : ">"
+
+  <<~EOS
+    boolean #{min_or_max}Value_idempotentlyUpdateValue(List values, def parentObject, String fieldName) {
+      def currentFieldValue = parentObject[fieldName];
+      def #{min_or_max}NewValue = values.isEmpty() ? null : Collections.#{min_or_max}(values);
+
+      if (currentFieldValue == null || (#{min_or_max}NewValue != null && #{min_or_max}NewValue.compareTo(currentFieldValue) #{operator} 0)) {
+        parentObject[fieldName] = #{min_or_max}NewValue;
+        return true;
+      }
+
+      return false;
+    }
+  EOS
+end
+
+
+ +
+ +
+

Instance Method Details

+ + +
+

+ + #apply_operation_returning_update_statusString + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns a line of painless code to manage a min or max value field and return a boolean indicating if it was updated.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    a line of painless code to manage a min or max value field and return a boolean indicating if it was updated.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+22
+23
+24
+25
+26
+27
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb', line 22
+
+def apply_operation_returning_update_status
+  *parent_parts, field = destination_field.split(".")
+  parent_parts = ["ctx", "_source"] + parent_parts
+
+  %{#{min_or_max}Value_idempotentlyUpdateValue(data["#{source_field}"], #{parent_parts.join(".")}, "#{field}")}
+end
+
+
+ +
+

+ + #function_definitionsArray<String> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns painless functions required by a min or max value field.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Array<String>) + + + + — +

    painless functions required by a min or max value field.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+35
+36
+37
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb', line 35
+
+def function_definitions
+  [MinOrMaxValue.function_def(min_or_max)]
+end
+
+
+ +
+

+ + #setup_statementsArray<String> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns a list of painless statements that must be called at the top of the script to set things up.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Array<String>) + + + + — +

    a list of painless statements that must be called at the top of the script to set things up.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+30
+31
+32
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb', line 30
+
+def setup_statements
+  FieldInitializerSupport.build_empty_value_initializers(destination_field, leaf_value: :leave_unset)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedIndexedType.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedIndexedType.html new file mode 100644 index 00000000..0a2d764a --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/DerivedIndexedType.html @@ -0,0 +1,4380 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb
+
+ +
+ +

Overview

+
+

Used to configure the derivation of a derived indexed type from a source type. +This type is yielded from Mixins::HasIndices#derive_indexed_type_fields.

+ + +
+
+
+ +
+

Examples:

+ + +

Derive a Course type from StudentCourseEnrollment events

+
+ +
ElasticGraph.define_schema do |schema|
+  # `StudentCourseEnrollment` is a directly indexed type.
+  schema.object_type "StudentCourseEnrollment" do |t|
+    t.field "id", "ID"
+    t.field "courseId", "ID"
+    t.field "courseName", "String"
+    t.field "studentName", "String"
+    t.field "courseStartDate", "Date"
+
+    t.index "student_course_enrollments"
+
+    # Here we define how the `Course` indexed type  is derived when we index `StudentCourseEnrollment` events.
+    t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+      # `derive` is an instance of `DerivedIndexedType`.
+      derive.immutable_value "name", from: "courseName"
+      derive.append_only_set "students", from: "studentName"
+      derive.min_value "firstOfferedDate", from: "courseStartDate"
+      derive.max_value "mostRecentlyOfferedDate", from: "courseStartDate"
+    end
+  end
+
+  # `Course` is an indexed type that is derived entirely from `StudentCourseEnrollment` events.
+  schema.object_type "Course" do |t|
+    t.field "id", "ID"
+    t.field "name", "String"
+    t.field "students", "[String!]!"
+    t.field "firstOfferedDate", "Date"
+    t.field "mostRecentlyOfferedDate", "Date"
+
+    t.index "courses"
+  end
+end
+ +
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(source_type:, destination_type_ref:, id_source:, routing_value_source:, rollover_timestamp_value_source:) {|DerivedIndexedType| ... } ⇒ DerivedIndexedType + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns a new instance of DerivedIndexedType.

+ + +
+
+
+

Parameters:

+
    + +
  • + + source_type + + + (SchemaElements::ObjectType) + + + + — +

    the type used as a source for this derive type

    +
    + +
  • + +
  • + + destination_type_ref + + + (SchemaElements::TypeReference) + + + + — +

    the derived type

    +
    + +
  • + +
  • + + id_source + + + (String) + + + + — +

    path to field on the source type used as id on the derived type

    +
    + +
  • + +
  • + + routing_value_source + + + (String, nil) + + + + — +

    path to field on the source type used for shard routing

    +
    + +
  • + +
  • + + rollover_timestamp_value_source + + + (String, nil) + + + + — +

    path to field on the source type used as the timestamp field for rollover

    +
    + +
  • + +
+ +

Yields:

+ + +
+ + + + +
+
+
+
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb', line 82
+
+def initialize(
+  source_type:,
+  destination_type_ref:,
+  id_source:,
+  routing_value_source:,
+  rollover_timestamp_value_source:
+)
+  fields = [] # : ::Array[_DerivedField]
+  super(
+    source_type: source_type,
+    destination_type_ref: destination_type_ref,
+    id_source: id_source,
+    routing_value_source: routing_value_source,
+    rollover_timestamp_value_source: rollover_timestamp_value_source,
+    fields: fields
+  )
+  yield self
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #fieldsArray<DerivedFields::AppendOnlySet, DerivedFields::ImmutableValue, DerivedFields::MinOrMaxValue> + + + + + +

+
+

Returns derived field definitions.

+ + +
+
+
+ +

Returns:

+ + +
+ + + + +
+
+
+
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb', line 67
+
+class DerivedIndexedType < ::Struct.new(
+  :source_type,
+  :destination_type_ref,
+  :id_source,
+  :routing_value_source,
+  :rollover_timestamp_value_source,
+  :fields
+)
+  # @param source_type [SchemaElements::ObjectType] the type used as a source for this derive type
+  # @param destination_type_ref [SchemaElements::TypeReference] the derived type
+  # @param id_source [String] path to field on the source type used as `id` on the derived type
+  # @param routing_value_source [String, nil] path to field on the source type used for shard routing
+  # @param rollover_timestamp_value_source [String, nil] path to field on the source type used as the timestamp field for rollover
+  # @yield [DerivedIndexedType] the `DerivedIndexedType` instance
+  # @api private
+  def initialize(
+    source_type:,
+    destination_type_ref:,
+    id_source:,
+    routing_value_source:,
+    rollover_timestamp_value_source:
+  )
+    fields = [] # : ::Array[_DerivedField]
+    super(
+      source_type: source_type,
+      destination_type_ref: destination_type_ref,
+      id_source: id_source,
+      routing_value_source: routing_value_source,
+      rollover_timestamp_value_source: rollover_timestamp_value_source,
+      fields: fields
+    )
+    yield self
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the set union of all values from
+  # the `from` field on the source type. Values are only ever appended to the set, so the field will
+  # act as an append-only set.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived set
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::AppendOnlySet]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "studentName", "String"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.append_only_set "students", from: "studentName"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "students", "[String!]!"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def append_only_set(field_name, from:)
+    fields << DerivedFields::AppendOnlySet.new(field_name, from)
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain a single immutable value from the
+  # `from` field on the source type. Immutability is enforced by triggering an indexing failure with a
+  # clear error if any event's source value is different from the value already indexed on this field.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @param nullable [Boolean] whether the field is allowed to be set to `null`. When set to false, events
+  #   that contain a `null` value in the `from` field will be rejected instead of setting the field’s value
+  #   to `null`.
+  # @param can_change_from_null [Boolean] whether a one-time mutation of the field value is allowed from
+  #   `null` to a non-`null` value. This can be useful when dealing with a field that may not have a value
+  #   on all source events. For example, if the source field was not initially part of the schema of your
+  #   source dataset, you may have old records that lack a value for this field. When set, this option
+  #   allows a one-time mutation of the field value from `null` to a non-`null` value. Once set to a
+  #   non-`null` value, any additional `null` values that are encountered will be ignored (ensuring that
+  #   the indexed data converges on the same state regardless of the order the events are ingested in).
+  #   Note: this option cannot be enabled when `nullable: false` has been set.
+  # @return [DerivedFields::ImmutableValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseName", "String"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.immutable_value "name", from: "courseName"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "name", "String"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def immutable_value(field_name, from:, nullable: true, can_change_from_null: false)
+    if !nullable && can_change_from_null
+      raise Errors::SchemaError, "`can_change_from_null: true` is not allowed with `nullable: false` (as there would be no `null` values to change from)."
+    end
+
+    fields << DerivedFields::ImmutableValue.new(
+      destination_field: field_name,
+      source_field: from,
+      nullable: nullable,
+      can_change_from_null: can_change_from_null
+    )
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the minimum of all values from the `from`
+  # field on the source type.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::MinOrMaxValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseStartDate", "Date"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.min_value "firstOfferedDate", from: "courseStartDate"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "firstOfferedDate", "Date"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def min_value(field_name, from:)
+    fields << DerivedFields::MinOrMaxValue.new(field_name, from, :min)
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the maximum of all values from the `from`
+  # field on the source type.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::MinOrMaxValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseStartDate", "Date"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.max_value "mostRecentlyOfferedDate", from: "courseStartDate"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "mostRecentlyOfferedDate", "Date"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def max_value(field_name, from:)
+    fields << DerivedFields::MinOrMaxValue.new(field_name, from, :max)
+  end
+
+  # @return [Scripting::Script] Painless script that will maintain the derived fields
+  # @api private
+  def painless_script
+    Scripting::Script.new(
+      source: generate_script.strip,
+      name: "#{destination_type_ref}_from_#{source_type.name}",
+      language: "painless",
+      context: "update"
+    )
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::UpdateTarget] runtime metadata for the source type
+  # @api private
+  def 
+    SchemaArtifacts::RuntimeMetadata::UpdateTarget.new(
+      type: destination_type_ref.name,
+      relationship: nil,
+      script_id: painless_script.id,
+      id_source: id_source,
+      routing_value_source: routing_value_source,
+      rollover_timestamp_value_source: rollover_timestamp_value_source,
+      metadata_params: {},
+      data_params: fields.map(&:source_field).to_h do |f|
+        [f, SchemaArtifacts::RuntimeMetadata::DynamicParam.new(source_path: f, cardinality: :many)]
+      end
+    )
+  end
+
+  private
+
+  def generate_script
+    if fields.empty?
+      raise Errors::SchemaError, "`derive_indexed_type_fields` definition for #{destination_type_ref} (from #{source_type.name}) " \
+        "has no derived field definitions."
+    end
+
+    sorted_fields = fields.sort_by(&:destination_field)
+
+    # We use `uniq` here to avoid re-doing the same setup multiple times, since multiple fields can sometimes
+    # need the same setup (such as initializing a common parent field to an empty map).
+    function_defs = sorted_fields.flat_map(&:function_definitions).uniq.map(&:strip).sort
+
+    setup_statements = [STATIC_SETUP_STATEMENTS] + sorted_fields.flat_map(&:setup_statements).uniq.map(&:strip)
+
+    apply_update_statements = sorted_fields.map { |f| apply_update_statement(f).strip }
+
+    # Note: comments in the script are effectively "free" since:
+    #
+    #   - The compiler will strip them out.
+    #   - We only send the script to the datastore once (when configuring the cluster), and later
+    #     reference it only by id--so we don't pay for the larger payload on each indexing request.
+    <<~EOS
+      #{function_defs.join("\n\n")}
+
+      #{setup_statements.join("\n")}
+
+      #{apply_update_statements.join("\n")}
+
+      if (!#{SCRIPT_ERRORS_VAR}.isEmpty()) {
+        throw new IllegalArgumentException("#{DERIVED_INDEX_FAILURE_MESSAGE_PREAMBLE}: " + #{SCRIPT_ERRORS_VAR}.join(" "));
+      }
+
+      // For records with no new values to index, only skip the update if the document itself doesn't already exist.
+      // Otherwise create an (empty) document to reflect the fact that the id has been seen.
+      if (ctx._source.id != null && #{sorted_fields.map { |f| was_noop_variable(f) }.join(" && ")}) {
+        ctx.op = 'none';
+      } else {
+        // Here we set `_source.id` because if we don't, it'll never be set, making these docs subtly
+        // different from docs indexed the normal way.
+        //
+        // Note also that we MUST use `params.id` instead of `ctx._id`. The latter works on an update
+        // of an existing document, but is unavailable when we are inserting the document for the first time.
+        ctx._source.id = params.id;
+      }
+    EOS
+  end
+
+  def apply_update_statement(field)
+    "boolean #{was_noop_variable(field)} = !#{field.apply_operation_returning_update_status};"
+  end
+
+  def was_noop_variable(field)
+    "#{field.destination_field.gsub(".", "__")}_was_noop"
+  end
+
+  SCRIPT_ERRORS_VAR = "scriptErrors"
+
+  STATIC_SETUP_STATEMENTS = <<~EOS.strip
+    Map data = params.data;
+    // A variable to accumulate script errors so that we can surface _all_ issues and not just the first.
+    List #{SCRIPT_ERRORS_VAR} = new ArrayList();
+  EOS
+end
+
+
+ + + +
+

+ + #id_sourceString + + + + + +

+
+

Returns path to field on the source type used as id on the derived type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    path to field on the source type used as id on the derived type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb', line 67
+
+class DerivedIndexedType < ::Struct.new(
+  :source_type,
+  :destination_type_ref,
+  :id_source,
+  :routing_value_source,
+  :rollover_timestamp_value_source,
+  :fields
+)
+  # @param source_type [SchemaElements::ObjectType] the type used as a source for this derive type
+  # @param destination_type_ref [SchemaElements::TypeReference] the derived type
+  # @param id_source [String] path to field on the source type used as `id` on the derived type
+  # @param routing_value_source [String, nil] path to field on the source type used for shard routing
+  # @param rollover_timestamp_value_source [String, nil] path to field on the source type used as the timestamp field for rollover
+  # @yield [DerivedIndexedType] the `DerivedIndexedType` instance
+  # @api private
+  def initialize(
+    source_type:,
+    destination_type_ref:,
+    id_source:,
+    routing_value_source:,
+    rollover_timestamp_value_source:
+  )
+    fields = [] # : ::Array[_DerivedField]
+    super(
+      source_type: source_type,
+      destination_type_ref: destination_type_ref,
+      id_source: id_source,
+      routing_value_source: routing_value_source,
+      rollover_timestamp_value_source: rollover_timestamp_value_source,
+      fields: fields
+    )
+    yield self
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the set union of all values from
+  # the `from` field on the source type. Values are only ever appended to the set, so the field will
+  # act as an append-only set.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived set
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::AppendOnlySet]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "studentName", "String"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.append_only_set "students", from: "studentName"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "students", "[String!]!"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def append_only_set(field_name, from:)
+    fields << DerivedFields::AppendOnlySet.new(field_name, from)
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain a single immutable value from the
+  # `from` field on the source type. Immutability is enforced by triggering an indexing failure with a
+  # clear error if any event's source value is different from the value already indexed on this field.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @param nullable [Boolean] whether the field is allowed to be set to `null`. When set to false, events
+  #   that contain a `null` value in the `from` field will be rejected instead of setting the field’s value
+  #   to `null`.
+  # @param can_change_from_null [Boolean] whether a one-time mutation of the field value is allowed from
+  #   `null` to a non-`null` value. This can be useful when dealing with a field that may not have a value
+  #   on all source events. For example, if the source field was not initially part of the schema of your
+  #   source dataset, you may have old records that lack a value for this field. When set, this option
+  #   allows a one-time mutation of the field value from `null` to a non-`null` value. Once set to a
+  #   non-`null` value, any additional `null` values that are encountered will be ignored (ensuring that
+  #   the indexed data converges on the same state regardless of the order the events are ingested in).
+  #   Note: this option cannot be enabled when `nullable: false` has been set.
+  # @return [DerivedFields::ImmutableValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseName", "String"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.immutable_value "name", from: "courseName"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "name", "String"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def immutable_value(field_name, from:, nullable: true, can_change_from_null: false)
+    if !nullable && can_change_from_null
+      raise Errors::SchemaError, "`can_change_from_null: true` is not allowed with `nullable: false` (as there would be no `null` values to change from)."
+    end
+
+    fields << DerivedFields::ImmutableValue.new(
+      destination_field: field_name,
+      source_field: from,
+      nullable: nullable,
+      can_change_from_null: can_change_from_null
+    )
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the minimum of all values from the `from`
+  # field on the source type.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::MinOrMaxValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseStartDate", "Date"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.min_value "firstOfferedDate", from: "courseStartDate"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "firstOfferedDate", "Date"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def min_value(field_name, from:)
+    fields << DerivedFields::MinOrMaxValue.new(field_name, from, :min)
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the maximum of all values from the `from`
+  # field on the source type.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::MinOrMaxValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseStartDate", "Date"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.max_value "mostRecentlyOfferedDate", from: "courseStartDate"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "mostRecentlyOfferedDate", "Date"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def max_value(field_name, from:)
+    fields << DerivedFields::MinOrMaxValue.new(field_name, from, :max)
+  end
+
+  # @return [Scripting::Script] Painless script that will maintain the derived fields
+  # @api private
+  def painless_script
+    Scripting::Script.new(
+      source: generate_script.strip,
+      name: "#{destination_type_ref}_from_#{source_type.name}",
+      language: "painless",
+      context: "update"
+    )
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::UpdateTarget] runtime metadata for the source type
+  # @api private
+  def 
+    SchemaArtifacts::RuntimeMetadata::UpdateTarget.new(
+      type: destination_type_ref.name,
+      relationship: nil,
+      script_id: painless_script.id,
+      id_source: id_source,
+      routing_value_source: routing_value_source,
+      rollover_timestamp_value_source: rollover_timestamp_value_source,
+      metadata_params: {},
+      data_params: fields.map(&:source_field).to_h do |f|
+        [f, SchemaArtifacts::RuntimeMetadata::DynamicParam.new(source_path: f, cardinality: :many)]
+      end
+    )
+  end
+
+  private
+
+  def generate_script
+    if fields.empty?
+      raise Errors::SchemaError, "`derive_indexed_type_fields` definition for #{destination_type_ref} (from #{source_type.name}) " \
+        "has no derived field definitions."
+    end
+
+    sorted_fields = fields.sort_by(&:destination_field)
+
+    # We use `uniq` here to avoid re-doing the same setup multiple times, since multiple fields can sometimes
+    # need the same setup (such as initializing a common parent field to an empty map).
+    function_defs = sorted_fields.flat_map(&:function_definitions).uniq.map(&:strip).sort
+
+    setup_statements = [STATIC_SETUP_STATEMENTS] + sorted_fields.flat_map(&:setup_statements).uniq.map(&:strip)
+
+    apply_update_statements = sorted_fields.map { |f| apply_update_statement(f).strip }
+
+    # Note: comments in the script are effectively "free" since:
+    #
+    #   - The compiler will strip them out.
+    #   - We only send the script to the datastore once (when configuring the cluster), and later
+    #     reference it only by id--so we don't pay for the larger payload on each indexing request.
+    <<~EOS
+      #{function_defs.join("\n\n")}
+
+      #{setup_statements.join("\n")}
+
+      #{apply_update_statements.join("\n")}
+
+      if (!#{SCRIPT_ERRORS_VAR}.isEmpty()) {
+        throw new IllegalArgumentException("#{DERIVED_INDEX_FAILURE_MESSAGE_PREAMBLE}: " + #{SCRIPT_ERRORS_VAR}.join(" "));
+      }
+
+      // For records with no new values to index, only skip the update if the document itself doesn't already exist.
+      // Otherwise create an (empty) document to reflect the fact that the id has been seen.
+      if (ctx._source.id != null && #{sorted_fields.map { |f| was_noop_variable(f) }.join(" && ")}) {
+        ctx.op = 'none';
+      } else {
+        // Here we set `_source.id` because if we don't, it'll never be set, making these docs subtly
+        // different from docs indexed the normal way.
+        //
+        // Note also that we MUST use `params.id` instead of `ctx._id`. The latter works on an update
+        // of an existing document, but is unavailable when we are inserting the document for the first time.
+        ctx._source.id = params.id;
+      }
+    EOS
+  end
+
+  def apply_update_statement(field)
+    "boolean #{was_noop_variable(field)} = !#{field.apply_operation_returning_update_status};"
+  end
+
+  def was_noop_variable(field)
+    "#{field.destination_field.gsub(".", "__")}_was_noop"
+  end
+
+  SCRIPT_ERRORS_VAR = "scriptErrors"
+
+  STATIC_SETUP_STATEMENTS = <<~EOS.strip
+    Map data = params.data;
+    // A variable to accumulate script errors so that we can surface _all_ issues and not just the first.
+    List #{SCRIPT_ERRORS_VAR} = new ArrayList();
+  EOS
+end
+
+
+ + + +
+

+ + #rollover_timestamp_value_sourceString? + + + + + +

+
+

Returns path to field on the source type used as the timestamp field for rollover.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String, nil) + + + + — +

    path to field on the source type used as the timestamp field for rollover

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb', line 67
+
+class DerivedIndexedType < ::Struct.new(
+  :source_type,
+  :destination_type_ref,
+  :id_source,
+  :routing_value_source,
+  :rollover_timestamp_value_source,
+  :fields
+)
+  # @param source_type [SchemaElements::ObjectType] the type used as a source for this derive type
+  # @param destination_type_ref [SchemaElements::TypeReference] the derived type
+  # @param id_source [String] path to field on the source type used as `id` on the derived type
+  # @param routing_value_source [String, nil] path to field on the source type used for shard routing
+  # @param rollover_timestamp_value_source [String, nil] path to field on the source type used as the timestamp field for rollover
+  # @yield [DerivedIndexedType] the `DerivedIndexedType` instance
+  # @api private
+  def initialize(
+    source_type:,
+    destination_type_ref:,
+    id_source:,
+    routing_value_source:,
+    rollover_timestamp_value_source:
+  )
+    fields = [] # : ::Array[_DerivedField]
+    super(
+      source_type: source_type,
+      destination_type_ref: destination_type_ref,
+      id_source: id_source,
+      routing_value_source: routing_value_source,
+      rollover_timestamp_value_source: rollover_timestamp_value_source,
+      fields: fields
+    )
+    yield self
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the set union of all values from
+  # the `from` field on the source type. Values are only ever appended to the set, so the field will
+  # act as an append-only set.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived set
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::AppendOnlySet]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "studentName", "String"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.append_only_set "students", from: "studentName"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "students", "[String!]!"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def append_only_set(field_name, from:)
+    fields << DerivedFields::AppendOnlySet.new(field_name, from)
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain a single immutable value from the
+  # `from` field on the source type. Immutability is enforced by triggering an indexing failure with a
+  # clear error if any event's source value is different from the value already indexed on this field.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @param nullable [Boolean] whether the field is allowed to be set to `null`. When set to false, events
+  #   that contain a `null` value in the `from` field will be rejected instead of setting the field’s value
+  #   to `null`.
+  # @param can_change_from_null [Boolean] whether a one-time mutation of the field value is allowed from
+  #   `null` to a non-`null` value. This can be useful when dealing with a field that may not have a value
+  #   on all source events. For example, if the source field was not initially part of the schema of your
+  #   source dataset, you may have old records that lack a value for this field. When set, this option
+  #   allows a one-time mutation of the field value from `null` to a non-`null` value. Once set to a
+  #   non-`null` value, any additional `null` values that are encountered will be ignored (ensuring that
+  #   the indexed data converges on the same state regardless of the order the events are ingested in).
+  #   Note: this option cannot be enabled when `nullable: false` has been set.
+  # @return [DerivedFields::ImmutableValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseName", "String"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.immutable_value "name", from: "courseName"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "name", "String"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def immutable_value(field_name, from:, nullable: true, can_change_from_null: false)
+    if !nullable && can_change_from_null
+      raise Errors::SchemaError, "`can_change_from_null: true` is not allowed with `nullable: false` (as there would be no `null` values to change from)."
+    end
+
+    fields << DerivedFields::ImmutableValue.new(
+      destination_field: field_name,
+      source_field: from,
+      nullable: nullable,
+      can_change_from_null: can_change_from_null
+    )
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the minimum of all values from the `from`
+  # field on the source type.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::MinOrMaxValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseStartDate", "Date"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.min_value "firstOfferedDate", from: "courseStartDate"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "firstOfferedDate", "Date"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def min_value(field_name, from:)
+    fields << DerivedFields::MinOrMaxValue.new(field_name, from, :min)
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the maximum of all values from the `from`
+  # field on the source type.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::MinOrMaxValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseStartDate", "Date"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.max_value "mostRecentlyOfferedDate", from: "courseStartDate"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "mostRecentlyOfferedDate", "Date"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def max_value(field_name, from:)
+    fields << DerivedFields::MinOrMaxValue.new(field_name, from, :max)
+  end
+
+  # @return [Scripting::Script] Painless script that will maintain the derived fields
+  # @api private
+  def painless_script
+    Scripting::Script.new(
+      source: generate_script.strip,
+      name: "#{destination_type_ref}_from_#{source_type.name}",
+      language: "painless",
+      context: "update"
+    )
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::UpdateTarget] runtime metadata for the source type
+  # @api private
+  def 
+    SchemaArtifacts::RuntimeMetadata::UpdateTarget.new(
+      type: destination_type_ref.name,
+      relationship: nil,
+      script_id: painless_script.id,
+      id_source: id_source,
+      routing_value_source: routing_value_source,
+      rollover_timestamp_value_source: rollover_timestamp_value_source,
+      metadata_params: {},
+      data_params: fields.map(&:source_field).to_h do |f|
+        [f, SchemaArtifacts::RuntimeMetadata::DynamicParam.new(source_path: f, cardinality: :many)]
+      end
+    )
+  end
+
+  private
+
+  def generate_script
+    if fields.empty?
+      raise Errors::SchemaError, "`derive_indexed_type_fields` definition for #{destination_type_ref} (from #{source_type.name}) " \
+        "has no derived field definitions."
+    end
+
+    sorted_fields = fields.sort_by(&:destination_field)
+
+    # We use `uniq` here to avoid re-doing the same setup multiple times, since multiple fields can sometimes
+    # need the same setup (such as initializing a common parent field to an empty map).
+    function_defs = sorted_fields.flat_map(&:function_definitions).uniq.map(&:strip).sort
+
+    setup_statements = [STATIC_SETUP_STATEMENTS] + sorted_fields.flat_map(&:setup_statements).uniq.map(&:strip)
+
+    apply_update_statements = sorted_fields.map { |f| apply_update_statement(f).strip }
+
+    # Note: comments in the script are effectively "free" since:
+    #
+    #   - The compiler will strip them out.
+    #   - We only send the script to the datastore once (when configuring the cluster), and later
+    #     reference it only by id--so we don't pay for the larger payload on each indexing request.
+    <<~EOS
+      #{function_defs.join("\n\n")}
+
+      #{setup_statements.join("\n")}
+
+      #{apply_update_statements.join("\n")}
+
+      if (!#{SCRIPT_ERRORS_VAR}.isEmpty()) {
+        throw new IllegalArgumentException("#{DERIVED_INDEX_FAILURE_MESSAGE_PREAMBLE}: " + #{SCRIPT_ERRORS_VAR}.join(" "));
+      }
+
+      // For records with no new values to index, only skip the update if the document itself doesn't already exist.
+      // Otherwise create an (empty) document to reflect the fact that the id has been seen.
+      if (ctx._source.id != null && #{sorted_fields.map { |f| was_noop_variable(f) }.join(" && ")}) {
+        ctx.op = 'none';
+      } else {
+        // Here we set `_source.id` because if we don't, it'll never be set, making these docs subtly
+        // different from docs indexed the normal way.
+        //
+        // Note also that we MUST use `params.id` instead of `ctx._id`. The latter works on an update
+        // of an existing document, but is unavailable when we are inserting the document for the first time.
+        ctx._source.id = params.id;
+      }
+    EOS
+  end
+
+  def apply_update_statement(field)
+    "boolean #{was_noop_variable(field)} = !#{field.apply_operation_returning_update_status};"
+  end
+
+  def was_noop_variable(field)
+    "#{field.destination_field.gsub(".", "__")}_was_noop"
+  end
+
+  SCRIPT_ERRORS_VAR = "scriptErrors"
+
+  STATIC_SETUP_STATEMENTS = <<~EOS.strip
+    Map data = params.data;
+    // A variable to accumulate script errors so that we can surface _all_ issues and not just the first.
+    List #{SCRIPT_ERRORS_VAR} = new ArrayList();
+  EOS
+end
+
+
+ + + +
+

+ + #routing_value_sourceString? + + + + + +

+
+

Returns path to field on the source type used for shard routing.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String, nil) + + + + — +

    path to field on the source type used for shard routing

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb', line 67
+
+class DerivedIndexedType < ::Struct.new(
+  :source_type,
+  :destination_type_ref,
+  :id_source,
+  :routing_value_source,
+  :rollover_timestamp_value_source,
+  :fields
+)
+  # @param source_type [SchemaElements::ObjectType] the type used as a source for this derive type
+  # @param destination_type_ref [SchemaElements::TypeReference] the derived type
+  # @param id_source [String] path to field on the source type used as `id` on the derived type
+  # @param routing_value_source [String, nil] path to field on the source type used for shard routing
+  # @param rollover_timestamp_value_source [String, nil] path to field on the source type used as the timestamp field for rollover
+  # @yield [DerivedIndexedType] the `DerivedIndexedType` instance
+  # @api private
+  def initialize(
+    source_type:,
+    destination_type_ref:,
+    id_source:,
+    routing_value_source:,
+    rollover_timestamp_value_source:
+  )
+    fields = [] # : ::Array[_DerivedField]
+    super(
+      source_type: source_type,
+      destination_type_ref: destination_type_ref,
+      id_source: id_source,
+      routing_value_source: routing_value_source,
+      rollover_timestamp_value_source: rollover_timestamp_value_source,
+      fields: fields
+    )
+    yield self
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the set union of all values from
+  # the `from` field on the source type. Values are only ever appended to the set, so the field will
+  # act as an append-only set.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived set
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::AppendOnlySet]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "studentName", "String"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.append_only_set "students", from: "studentName"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "students", "[String!]!"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def append_only_set(field_name, from:)
+    fields << DerivedFields::AppendOnlySet.new(field_name, from)
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain a single immutable value from the
+  # `from` field on the source type. Immutability is enforced by triggering an indexing failure with a
+  # clear error if any event's source value is different from the value already indexed on this field.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @param nullable [Boolean] whether the field is allowed to be set to `null`. When set to false, events
+  #   that contain a `null` value in the `from` field will be rejected instead of setting the field’s value
+  #   to `null`.
+  # @param can_change_from_null [Boolean] whether a one-time mutation of the field value is allowed from
+  #   `null` to a non-`null` value. This can be useful when dealing with a field that may not have a value
+  #   on all source events. For example, if the source field was not initially part of the schema of your
+  #   source dataset, you may have old records that lack a value for this field. When set, this option
+  #   allows a one-time mutation of the field value from `null` to a non-`null` value. Once set to a
+  #   non-`null` value, any additional `null` values that are encountered will be ignored (ensuring that
+  #   the indexed data converges on the same state regardless of the order the events are ingested in).
+  #   Note: this option cannot be enabled when `nullable: false` has been set.
+  # @return [DerivedFields::ImmutableValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseName", "String"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.immutable_value "name", from: "courseName"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "name", "String"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def immutable_value(field_name, from:, nullable: true, can_change_from_null: false)
+    if !nullable && can_change_from_null
+      raise Errors::SchemaError, "`can_change_from_null: true` is not allowed with `nullable: false` (as there would be no `null` values to change from)."
+    end
+
+    fields << DerivedFields::ImmutableValue.new(
+      destination_field: field_name,
+      source_field: from,
+      nullable: nullable,
+      can_change_from_null: can_change_from_null
+    )
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the minimum of all values from the `from`
+  # field on the source type.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::MinOrMaxValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseStartDate", "Date"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.min_value "firstOfferedDate", from: "courseStartDate"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "firstOfferedDate", "Date"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def min_value(field_name, from:)
+    fields << DerivedFields::MinOrMaxValue.new(field_name, from, :min)
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the maximum of all values from the `from`
+  # field on the source type.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::MinOrMaxValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseStartDate", "Date"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.max_value "mostRecentlyOfferedDate", from: "courseStartDate"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "mostRecentlyOfferedDate", "Date"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def max_value(field_name, from:)
+    fields << DerivedFields::MinOrMaxValue.new(field_name, from, :max)
+  end
+
+  # @return [Scripting::Script] Painless script that will maintain the derived fields
+  # @api private
+  def painless_script
+    Scripting::Script.new(
+      source: generate_script.strip,
+      name: "#{destination_type_ref}_from_#{source_type.name}",
+      language: "painless",
+      context: "update"
+    )
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::UpdateTarget] runtime metadata for the source type
+  # @api private
+  def 
+    SchemaArtifacts::RuntimeMetadata::UpdateTarget.new(
+      type: destination_type_ref.name,
+      relationship: nil,
+      script_id: painless_script.id,
+      id_source: id_source,
+      routing_value_source: routing_value_source,
+      rollover_timestamp_value_source: rollover_timestamp_value_source,
+      metadata_params: {},
+      data_params: fields.map(&:source_field).to_h do |f|
+        [f, SchemaArtifacts::RuntimeMetadata::DynamicParam.new(source_path: f, cardinality: :many)]
+      end
+    )
+  end
+
+  private
+
+  def generate_script
+    if fields.empty?
+      raise Errors::SchemaError, "`derive_indexed_type_fields` definition for #{destination_type_ref} (from #{source_type.name}) " \
+        "has no derived field definitions."
+    end
+
+    sorted_fields = fields.sort_by(&:destination_field)
+
+    # We use `uniq` here to avoid re-doing the same setup multiple times, since multiple fields can sometimes
+    # need the same setup (such as initializing a common parent field to an empty map).
+    function_defs = sorted_fields.flat_map(&:function_definitions).uniq.map(&:strip).sort
+
+    setup_statements = [STATIC_SETUP_STATEMENTS] + sorted_fields.flat_map(&:setup_statements).uniq.map(&:strip)
+
+    apply_update_statements = sorted_fields.map { |f| apply_update_statement(f).strip }
+
+    # Note: comments in the script are effectively "free" since:
+    #
+    #   - The compiler will strip them out.
+    #   - We only send the script to the datastore once (when configuring the cluster), and later
+    #     reference it only by id--so we don't pay for the larger payload on each indexing request.
+    <<~EOS
+      #{function_defs.join("\n\n")}
+
+      #{setup_statements.join("\n")}
+
+      #{apply_update_statements.join("\n")}
+
+      if (!#{SCRIPT_ERRORS_VAR}.isEmpty()) {
+        throw new IllegalArgumentException("#{DERIVED_INDEX_FAILURE_MESSAGE_PREAMBLE}: " + #{SCRIPT_ERRORS_VAR}.join(" "));
+      }
+
+      // For records with no new values to index, only skip the update if the document itself doesn't already exist.
+      // Otherwise create an (empty) document to reflect the fact that the id has been seen.
+      if (ctx._source.id != null && #{sorted_fields.map { |f| was_noop_variable(f) }.join(" && ")}) {
+        ctx.op = 'none';
+      } else {
+        // Here we set `_source.id` because if we don't, it'll never be set, making these docs subtly
+        // different from docs indexed the normal way.
+        //
+        // Note also that we MUST use `params.id` instead of `ctx._id`. The latter works on an update
+        // of an existing document, but is unavailable when we are inserting the document for the first time.
+        ctx._source.id = params.id;
+      }
+    EOS
+  end
+
+  def apply_update_statement(field)
+    "boolean #{was_noop_variable(field)} = !#{field.apply_operation_returning_update_status};"
+  end
+
+  def was_noop_variable(field)
+    "#{field.destination_field.gsub(".", "__")}_was_noop"
+  end
+
+  SCRIPT_ERRORS_VAR = "scriptErrors"
+
+  STATIC_SETUP_STATEMENTS = <<~EOS.strip
+    Map data = params.data;
+    // A variable to accumulate script errors so that we can surface _all_ issues and not just the first.
+    List #{SCRIPT_ERRORS_VAR} = new ArrayList();
+  EOS
+end
+
+
+ + + +
+

+ + #source_typeSchemaElements::ObjectType + + + + + +

+
+

Returns the type used as a source for this derive type.

+ + +
+
+
+ +

Returns:

+ + +
+ + + + +
+
+
+
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb', line 67
+
+class DerivedIndexedType < ::Struct.new(
+  :source_type,
+  :destination_type_ref,
+  :id_source,
+  :routing_value_source,
+  :rollover_timestamp_value_source,
+  :fields
+)
+  # @param source_type [SchemaElements::ObjectType] the type used as a source for this derive type
+  # @param destination_type_ref [SchemaElements::TypeReference] the derived type
+  # @param id_source [String] path to field on the source type used as `id` on the derived type
+  # @param routing_value_source [String, nil] path to field on the source type used for shard routing
+  # @param rollover_timestamp_value_source [String, nil] path to field on the source type used as the timestamp field for rollover
+  # @yield [DerivedIndexedType] the `DerivedIndexedType` instance
+  # @api private
+  def initialize(
+    source_type:,
+    destination_type_ref:,
+    id_source:,
+    routing_value_source:,
+    rollover_timestamp_value_source:
+  )
+    fields = [] # : ::Array[_DerivedField]
+    super(
+      source_type: source_type,
+      destination_type_ref: destination_type_ref,
+      id_source: id_source,
+      routing_value_source: routing_value_source,
+      rollover_timestamp_value_source: rollover_timestamp_value_source,
+      fields: fields
+    )
+    yield self
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the set union of all values from
+  # the `from` field on the source type. Values are only ever appended to the set, so the field will
+  # act as an append-only set.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived set
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::AppendOnlySet]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "studentName", "String"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.append_only_set "students", from: "studentName"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "students", "[String!]!"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def append_only_set(field_name, from:)
+    fields << DerivedFields::AppendOnlySet.new(field_name, from)
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain a single immutable value from the
+  # `from` field on the source type. Immutability is enforced by triggering an indexing failure with a
+  # clear error if any event's source value is different from the value already indexed on this field.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @param nullable [Boolean] whether the field is allowed to be set to `null`. When set to false, events
+  #   that contain a `null` value in the `from` field will be rejected instead of setting the field’s value
+  #   to `null`.
+  # @param can_change_from_null [Boolean] whether a one-time mutation of the field value is allowed from
+  #   `null` to a non-`null` value. This can be useful when dealing with a field that may not have a value
+  #   on all source events. For example, if the source field was not initially part of the schema of your
+  #   source dataset, you may have old records that lack a value for this field. When set, this option
+  #   allows a one-time mutation of the field value from `null` to a non-`null` value. Once set to a
+  #   non-`null` value, any additional `null` values that are encountered will be ignored (ensuring that
+  #   the indexed data converges on the same state regardless of the order the events are ingested in).
+  #   Note: this option cannot be enabled when `nullable: false` has been set.
+  # @return [DerivedFields::ImmutableValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseName", "String"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.immutable_value "name", from: "courseName"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "name", "String"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def immutable_value(field_name, from:, nullable: true, can_change_from_null: false)
+    if !nullable && can_change_from_null
+      raise Errors::SchemaError, "`can_change_from_null: true` is not allowed with `nullable: false` (as there would be no `null` values to change from)."
+    end
+
+    fields << DerivedFields::ImmutableValue.new(
+      destination_field: field_name,
+      source_field: from,
+      nullable: nullable,
+      can_change_from_null: can_change_from_null
+    )
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the minimum of all values from the `from`
+  # field on the source type.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::MinOrMaxValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseStartDate", "Date"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.min_value "firstOfferedDate", from: "courseStartDate"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "firstOfferedDate", "Date"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def min_value(field_name, from:)
+    fields << DerivedFields::MinOrMaxValue.new(field_name, from, :min)
+  end
+
+  # Configures `field_name` (on the derived indexing type) to contain the maximum of all values from the `from`
+  # field on the source type.
+  #
+  # @param field_name [String] name of field on the derived indexing type to store the derived value
+  # @param from [String] path to field on the source type to source values from
+  # @return [DerivedIndexedType::MinOrMaxValue]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "StudentCourseEnrollment" do |t|
+  #       t.field "id", "ID"
+  #       t.field "courseId", "ID"
+  #       t.field "courseStartDate", "Date"
+  #
+  #       t.index "student_course_enrollments"
+  #
+  #       t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+  #         derive.max_value "mostRecentlyOfferedDate", from: "courseStartDate"
+  #       end
+  #     end
+  #
+  #     schema.object_type "Course" do |t|
+  #       t.field "id", "ID"
+  #       t.field "mostRecentlyOfferedDate", "Date"
+  #
+  #       t.index "courses"
+  #     end
+  #   end
+  def max_value(field_name, from:)
+    fields << DerivedFields::MinOrMaxValue.new(field_name, from, :max)
+  end
+
+  # @return [Scripting::Script] Painless script that will maintain the derived fields
+  # @api private
+  def painless_script
+    Scripting::Script.new(
+      source: generate_script.strip,
+      name: "#{destination_type_ref}_from_#{source_type.name}",
+      language: "painless",
+      context: "update"
+    )
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::UpdateTarget] runtime metadata for the source type
+  # @api private
+  def 
+    SchemaArtifacts::RuntimeMetadata::UpdateTarget.new(
+      type: destination_type_ref.name,
+      relationship: nil,
+      script_id: painless_script.id,
+      id_source: id_source,
+      routing_value_source: routing_value_source,
+      rollover_timestamp_value_source: rollover_timestamp_value_source,
+      metadata_params: {},
+      data_params: fields.map(&:source_field).to_h do |f|
+        [f, SchemaArtifacts::RuntimeMetadata::DynamicParam.new(source_path: f, cardinality: :many)]
+      end
+    )
+  end
+
+  private
+
+  def generate_script
+    if fields.empty?
+      raise Errors::SchemaError, "`derive_indexed_type_fields` definition for #{destination_type_ref} (from #{source_type.name}) " \
+        "has no derived field definitions."
+    end
+
+    sorted_fields = fields.sort_by(&:destination_field)
+
+    # We use `uniq` here to avoid re-doing the same setup multiple times, since multiple fields can sometimes
+    # need the same setup (such as initializing a common parent field to an empty map).
+    function_defs = sorted_fields.flat_map(&:function_definitions).uniq.map(&:strip).sort
+
+    setup_statements = [STATIC_SETUP_STATEMENTS] + sorted_fields.flat_map(&:setup_statements).uniq.map(&:strip)
+
+    apply_update_statements = sorted_fields.map { |f| apply_update_statement(f).strip }
+
+    # Note: comments in the script are effectively "free" since:
+    #
+    #   - The compiler will strip them out.
+    #   - We only send the script to the datastore once (when configuring the cluster), and later
+    #     reference it only by id--so we don't pay for the larger payload on each indexing request.
+    <<~EOS
+      #{function_defs.join("\n\n")}
+
+      #{setup_statements.join("\n")}
+
+      #{apply_update_statements.join("\n")}
+
+      if (!#{SCRIPT_ERRORS_VAR}.isEmpty()) {
+        throw new IllegalArgumentException("#{DERIVED_INDEX_FAILURE_MESSAGE_PREAMBLE}: " + #{SCRIPT_ERRORS_VAR}.join(" "));
+      }
+
+      // For records with no new values to index, only skip the update if the document itself doesn't already exist.
+      // Otherwise create an (empty) document to reflect the fact that the id has been seen.
+      if (ctx._source.id != null && #{sorted_fields.map { |f| was_noop_variable(f) }.join(" && ")}) {
+        ctx.op = 'none';
+      } else {
+        // Here we set `_source.id` because if we don't, it'll never be set, making these docs subtly
+        // different from docs indexed the normal way.
+        //
+        // Note also that we MUST use `params.id` instead of `ctx._id`. The latter works on an update
+        // of an existing document, but is unavailable when we are inserting the document for the first time.
+        ctx._source.id = params.id;
+      }
+    EOS
+  end
+
+  def apply_update_statement(field)
+    "boolean #{was_noop_variable(field)} = !#{field.apply_operation_returning_update_status};"
+  end
+
+  def was_noop_variable(field)
+    "#{field.destination_field.gsub(".", "__")}_was_noop"
+  end
+
+  SCRIPT_ERRORS_VAR = "scriptErrors"
+
+  STATIC_SETUP_STATEMENTS = <<~EOS.strip
+    Map data = params.data;
+    // A variable to accumulate script errors so that we can surface _all_ issues and not just the first.
+    List #{SCRIPT_ERRORS_VAR} = new ArrayList();
+  EOS
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #append_only_set(field_name, from:) ⇒ DerivedIndexedType::AppendOnlySet + + + + + +

+
+

Configures field_name (on the derived indexing type) to contain the set union of all values from +the from field on the source type. Values are only ever appended to the set, so the field will +act as an append-only set.

+ + +
+
+
+ +
+

Examples:

+ + +
ElasticGraph.define_schema do |schema|
+  schema.object_type "StudentCourseEnrollment" do |t|
+    t.field "id", "ID"
+    t.field "courseId", "ID"
+    t.field "studentName", "String"
+
+    t.index "student_course_enrollments"
+
+    t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+      derive.append_only_set "students", from: "studentName"
+    end
+  end
+
+  schema.object_type "Course" do |t|
+    t.field "id", "ID"
+    t.field "students", "[String!]!"
+
+    t.index "courses"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + field_name + + + (String) + + + + — +

    name of field on the derived indexing type to store the derived set

    +
    + +
  • + +
  • + + from + + + (String) + + + + — +

    path to field on the source type to source values from

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (DerivedIndexedType::AppendOnlySet) + + + +
  • + +
+ +
+ + + + +
+
+
+
+130
+131
+132
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb', line 130
+
+def append_only_set(field_name, from:)
+  fields << DerivedFields::AppendOnlySet.new(field_name, from)
+end
+
+
+ +
+

+ + #immutable_value(field_name, from:, nullable: true, can_change_from_null: false) ⇒ DerivedFields::ImmutableValue + + + + + +

+
+

Configures field_name (on the derived indexing type) to contain a single immutable value from the +from field on the source type. Immutability is enforced by triggering an indexing failure with a +clear error if any event’s source value is different from the value already indexed on this field.

+ + +
+
+
+ +
+

Examples:

+ + +
ElasticGraph.define_schema do |schema|
+  schema.object_type "StudentCourseEnrollment" do |t|
+    t.field "id", "ID"
+    t.field "courseId", "ID"
+    t.field "courseName", "String"
+
+    t.index "student_course_enrollments"
+
+    t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+      derive.immutable_value "name", from: "courseName"
+    end
+  end
+
+  schema.object_type "Course" do |t|
+    t.field "id", "ID"
+    t.field "name", "String"
+
+    t.index "courses"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + field_name + + + (String) + + + + — +

    name of field on the derived indexing type to store the derived value

    +
    + +
  • + +
  • + + from + + + (String) + + + + — +

    path to field on the source type to source values from

    +
    + +
  • + +
  • + + nullable + + + (Boolean) + + + (defaults to: true) + + + — +

    whether the field is allowed to be set to null. When set to false, events +that contain a null value in the from field will be rejected instead of setting the field’s value +to null.

    +
    + +
  • + +
  • + + can_change_from_null + + + (Boolean) + + + (defaults to: false) + + + — +

    whether a one-time mutation of the field value is allowed from +null to a non-null value. This can be useful when dealing with a field that may not have a value +on all source events. For example, if the source field was not initially part of the schema of your +source dataset, you may have old records that lack a value for this field. When set, this option +allows a one-time mutation of the field value from null to a non-null value. Once set to a +non-null value, any additional null values that are encountered will be ignored (ensuring that +the indexed data converges on the same state regardless of the order the events are ingested in). +Note: this option cannot be enabled when nullable: false has been set.

    +
    + +
  • + +
+ +

Returns:

+ + +
+ + + + +
+
+
+
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb', line 174
+
+def immutable_value(field_name, from:, nullable: true, can_change_from_null: false)
+  if !nullable && can_change_from_null
+    raise Errors::SchemaError, "`can_change_from_null: true` is not allowed with `nullable: false` (as there would be no `null` values to change from)."
+  end
+
+  fields << DerivedFields::ImmutableValue.new(
+    destination_field: field_name,
+    source_field: from,
+    nullable: nullable,
+    can_change_from_null: can_change_from_null
+  )
+end
+
+
+ +
+

+ + #max_value(field_name, from:) ⇒ DerivedIndexedType::MinOrMaxValue + + + + + +

+
+

Configures field_name (on the derived indexing type) to contain the maximum of all values from the from +field on the source type.

+ + +
+
+
+ +
+

Examples:

+ + +
ElasticGraph.define_schema do |schema|
+  schema.object_type "StudentCourseEnrollment" do |t|
+    t.field "id", "ID"
+    t.field "courseId", "ID"
+    t.field "courseStartDate", "Date"
+
+    t.index "student_course_enrollments"
+
+    t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+      derive.max_value "mostRecentlyOfferedDate", from: "courseStartDate"
+    end
+  end
+
+  schema.object_type "Course" do |t|
+    t.field "id", "ID"
+    t.field "mostRecentlyOfferedDate", "Date"
+
+    t.index "courses"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + field_name + + + (String) + + + + — +

    name of field on the derived indexing type to store the derived value

    +
    + +
  • + +
  • + + from + + + (String) + + + + — +

    path to field on the source type to source values from

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (DerivedIndexedType::MinOrMaxValue) + + + +
  • + +
+ +
+ + + + +
+
+
+
+247
+248
+249
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb', line 247
+
+def max_value(field_name, from:)
+  fields << DerivedFields::MinOrMaxValue.new(field_name, from, :max)
+end
+
+
+ +
+

+ + #min_value(field_name, from:) ⇒ DerivedIndexedType::MinOrMaxValue + + + + + +

+
+

Configures field_name (on the derived indexing type) to contain the minimum of all values from the from +field on the source type.

+ + +
+
+
+ +
+

Examples:

+ + +
ElasticGraph.define_schema do |schema|
+  schema.object_type "StudentCourseEnrollment" do |t|
+    t.field "id", "ID"
+    t.field "courseId", "ID"
+    t.field "courseStartDate", "Date"
+
+    t.index "student_course_enrollments"
+
+    t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+      derive.min_value "firstOfferedDate", from: "courseStartDate"
+    end
+  end
+
+  schema.object_type "Course" do |t|
+    t.field "id", "ID"
+    t.field "firstOfferedDate", "Date"
+
+    t.index "courses"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + field_name + + + (String) + + + + — +

    name of field on the derived indexing type to store the derived value

    +
    + +
  • + +
  • + + from + + + (String) + + + + — +

    path to field on the source type to source values from

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (DerivedIndexedType::MinOrMaxValue) + + + +
  • + +
+ +
+ + + + +
+
+
+
+215
+216
+217
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb', line 215
+
+def min_value(field_name, from:)
+  fields << DerivedFields::MinOrMaxValue.new(field_name, from, :min)
+end
+
+
+ +
+

+ + #painless_scriptScripting::Script + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns Painless script that will maintain the derived fields.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Scripting::Script) + + + + — +

    Painless script that will maintain the derived fields

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+253
+254
+255
+256
+257
+258
+259
+260
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb', line 253
+
+def painless_script
+  Scripting::Script.new(
+    source: generate_script.strip,
+    name: "#{destination_type_ref}_from_#{source_type.name}",
+    language: "painless",
+    context: "update"
+  )
+end
+
+
+ +
+

+ + #runtime_metadata_for_source_typeSchemaArtifacts::RuntimeMetadata::UpdateTarget + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns runtime metadata for the source type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (SchemaArtifacts::RuntimeMetadata::UpdateTarget) + + + + — +

    runtime metadata for the source type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb', line 264
+
+def 
+  SchemaArtifacts::RuntimeMetadata::UpdateTarget.new(
+    type: destination_type_ref.name,
+    relationship: nil,
+    script_id: painless_script.id,
+    id_source: id_source,
+    routing_value_source: routing_value_source,
+    rollover_timestamp_value_source: rollover_timestamp_value_source,
+    metadata_params: {},
+    data_params: fields.map(&:source_field).to_h do |f|
+      [f, SchemaArtifacts::RuntimeMetadata::DynamicParam.new(source_path: f, cardinality: :many)]
+    end
+  )
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/EventEnvelope.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/EventEnvelope.html new file mode 100644 index 00000000..b0d7dc87 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/EventEnvelope.html @@ -0,0 +1,348 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Indexing::EventEnvelope + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Indexing::EventEnvelope + + + Private +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/event_envelope.rb
+
+ +
+ +

Overview

+
+

+ This module is part of a private API. + You should avoid using this module if possible, as it may be removed or be changed in the future. +

+

Contains logic related to “event envelope”–the layer of metadata that wraps all indexing events.

+ + +
+
+
+ + +
+ + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .json_schema(indexed_type_names, json_schema_version) ⇒ Hash<String, Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns the JSON schema for the ElasticGraph event envelope for the given indexed_type_names.

+ + +
+
+
+

Parameters:

+
    + +
  • + + indexed_type_names + + + (Array<String>) + + + + — +

    names of the indexed types

    +
    + +
  • + +
  • + + json_schema_version + + + (Integer) + + + + — +

    the version of the JSON schema

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash<String, Object>) + + + + — +

    the JSON schema for the ElasticGraph event envelope for the given indexed_type_names.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/event_envelope.rb', line 21
+
+def self.json_schema(indexed_type_names, json_schema_version)
+  {
+    "type" => "object",
+    "properties" => {
+      "op" => {
+        "type" => "string",
+        "enum" => %w[upsert]
+      },
+      "type" => {
+        "type" => "string",
+        # Sorting doesn't really matter here, but it's nice for the output in the schema artifact to be consistent.
+        "enum" => indexed_type_names.sort
+      },
+      "id" => {
+        "type" => "string",
+        "maxLength" => DEFAULT_MAX_KEYWORD_LENGTH
+      },
+      "version" => {
+        "type" => "integer",
+        "minimum" => 0,
+        "maximum" => (2**63) - 1
+      },
+      "record" => {
+        "type" => "object"
+      },
+      "latency_timestamps" => {
+        "type" => "object",
+        "additionalProperties" => false,
+        "patternProperties" => {
+          "^\\w+_at$" => {"type" => "string", "format" => "date-time"}
+        }
+      },
+      JSON_SCHEMA_VERSION_KEY => {
+        "const" => json_schema_version
+      },
+      "message_id" => {
+        "type" => "string",
+        "description" => "The optional ID of the message containing this event from whatever messaging system is being used between the publisher and the ElasticGraph indexer."
+      }
+    },
+    "additionalProperties" => false,
+    "required" => ["op", "type", "id", "version", JSON_SCHEMA_VERSION_KEY],
+    "if" => {
+      "properties" => {
+        "op" => {"const" => "upsert"}
+      }
+    },
+    "then" => {"required" => ["record"]}
+  }
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/Field.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/Field.html new file mode 100644 index 00000000..5db5b780 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/Field.html @@ -0,0 +1,656 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::Indexing::Field + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::Indexing::Field + + + Private +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field.rb
+
+ +
+ +

Overview

+
+

+ This class is part of a private API. + You should avoid using this class if possible, as it may be removed or be changed in the future. +

+

Represents a field in a JSON document during indexing.

+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
JSON_SCHEMA_OVERRIDES_BY_MAPPING_TYPE = +
+
+

+ This constant is part of a private API. + You should avoid using this constant if possible, as it may be removed or be changed in the future. +

+ +
+ Note: +

We don’t handle integer here because it’s the default numeric type (handled by our definition of the Int scalar type).

+
+
+ +
+ Note: +

Likewise, we don’t handle long here because a custom scalar type must be used for that since GraphQL’s Int type can’t handle long values.

+
+
+ +

JSON schema overrides that automatically apply to specific mapping types so that the JSON schema +validation will reject values which cannot be indexed into fields of a specific mapping type.

+ + +
+
+
+ + +

See Also:

+ + +
+
+
{
+  "byte" => {"minimum" => -(2**7), "maximum" => (2**7) - 1},
+  "short" => {"minimum" => -(2**15), "maximum" => (2**15) - 1},
+  "keyword" => {"maxLength" => DEFAULT_MAX_KEYWORD_LENGTH},
+  "text" => {"maxLength" => DEFAULT_MAX_TEXT_LENGTH}
+}
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .normalized_mapping_hash_for(fields) ⇒ Hash<String, Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Builds a hash containing the mapping for the provided fields, normalizing it in the same way that the +datastore does so that consistency checks between our index configuration and what’s in the datastore +work properly.

+ + +
+
+
+

Parameters:

+
    + +
  • + + fields + + + (Array<Field>) + + + + — +

    fields to generate a mapping hash from

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash<String, Object>) + + + + — +

    generated mapping hash

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field.rb', line 87
+
+def self.normalized_mapping_hash_for(fields)
+  # When an object field has `properties`, the datastore normalizes the mapping by dropping
+  # the `type => object` (it's implicit, as `properties` are only valid on an object...).
+  # OTOH, when there are no properties, the datastore normalizes the mapping by dropping the
+  # empty `properties` entry and instead returning `type => object`.
+  return {"type" => "object"} if fields.empty?
+
+  # Partition the fields into runtime fields and normal fields based on the presence of runtime_script
+  runtime_fields, normal_fields = fields.partition(&:runtime_field_script)
+
+  mapping_hash = {
+    "properties" => normal_fields.to_h { |f| [f.name_in_index, f.mapping] }
+  }
+  unless runtime_fields.empty?
+    mapping_hash["runtime"] = runtime_fields.to_h do |f|
+      [f.name_in_index, f.mapping.merge({"script" => {"source" => f.runtime_field_script}})]
+    end
+  end
+
+  mapping_hash
+end
+
+
+ +
+ +
+

Instance Method Details

+ + +
+

+ + #json_schemaHash<String, Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns the JSON schema definition for this field. The returned object should +be composed entirely of Ruby primitives that, when converted to a JSON string, match the +requirements of the JSON schema spec.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, Object>) + + + + — +

    the JSON schema definition for this field. The returned object should +be composed entirely of Ruby primitives that, when converted to a JSON string, match the +requirements of the JSON schema spec.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+68
+69
+70
+71
+72
+73
+74
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field.rb', line 68
+
+def json_schema
+  json_schema_layers
+    .reverse # resolve layers from innermost to outermost wrappings
+    .reduce(inner_json_schema) { |acc, layer| process_layer(layer, acc) }
+    .merge(outer_json_schema_customizations)
+    .then { |h| Support::HashUtil.stringify_keys(h) }
+end
+
+
+ +
+

+ + #json_schema_metadataJSONSchemaFieldMetadata + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns additional ElasticGraph metadata to be stored in the JSON schema for this field.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (JSONSchemaFieldMetadata) + + + + — +

    additional ElasticGraph metadata to be stored in the JSON schema for this field.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+77
+78
+79
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field.rb', line 77
+
+def 
+  JSONSchemaFieldMetadata.new(type: type.name, name_in_index: name_in_index)
+end
+
+
+ +
+

+ + #mappingHash<String, Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns the mapping for this field. The returned hash should be composed entirely +of Ruby primitives that, when converted to a JSON string, match the structure required by +Elasticsearch.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, Object>) + + + + — +

    the mapping for this field. The returned hash should be composed entirely +of Ruby primitives that, when converted to a JSON string, match the structure required by +Elasticsearch.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field.rb', line 49
+
+def mapping
+  @mapping ||= begin
+    raw_mapping = indexing_field_type
+      .to_mapping
+      .merge(Support::HashUtil.stringify_keys(mapping_customizations))
+
+    if (object_type = type.fully_unwrapped.as_object_type) && type.list? && mapping_customizations[:type] == "nested"
+      # If it's an object list field using the `nested` type, we need to add a `__counts` field to
+      # the mapping for all of its subfields which are lists.
+      ListCountsMapping.merged_into(raw_mapping, for_type: object_type)
+    else
+      raw_mapping
+    end
+  end
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldReference.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldReference.html new file mode 100644 index 00000000..8bac3c6d --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldReference.html @@ -0,0 +1,268 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::Indexing::FieldReference + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::Indexing::FieldReference + + + Private +

+
+ +
+
Inherits:
+
+ Data + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_reference.rb,
+ elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_reference.rb
+
+
+ +
+ +

Overview

+
+

+ This class is part of a private API. + You should avoid using this class if possible, as it may be removed or be changed in the future. +

+

A lazy reference to a Field. It contains all attributes needed to build a Field, but the referenced type may not be +resolvable yet (which is why this exists).

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + + +
+

Instance Method Details

+ + +
+

+ + #resolveField? + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns the ElasticGraph::SchemaDefinition::Indexing::Field this reference resolves to (if it can be resolved).

+ + +
+
+
+ +

Returns:

+ + +
+ + + + +
+
+
+
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_reference.rb', line 30
+
+def resolve
+  return nil unless (resolved_type = type.fully_unwrapped.resolved)
+
+  Indexing::Field.new(
+    name: name,
+    name_in_index: name_in_index,
+    type: type,
+    json_schema_layers: type.json_schema_layers,
+    indexing_field_type: resolved_type.to_indexing_field_type,
+    accuracy_confidence: accuracy_confidence,
+    json_schema_customizations: json_schema_options,
+    mapping_customizations: mapping_options,
+    source: source,
+    runtime_field_script: runtime_field_script
+  )
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType.html new file mode 100644 index 00000000..dde14c37 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType.html @@ -0,0 +1,131 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Indexing::FieldType + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Indexing::FieldType + + + Private +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb,
+ elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/union.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/object.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb
+
+
+ +
+ +

Overview

+
+

+ This module is part of a private API. + You should avoid using this module if possible, as it may be removed or be changed in the future. +

+

Contains implementation logic for the different types of indexing fields.

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + + + Classes: Enum, Object, Scalar, Union + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType/Enum.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType/Enum.html new file mode 100644 index 00000000..4ac922a3 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType/Enum.html @@ -0,0 +1,703 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::Indexing::FieldType::Enum + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::Indexing::FieldType::Enum + + + Private +

+
+ +
+
Inherits:
+
+ Data + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb,
+ elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb
+
+
+ +
+ +

Overview

+
+

+ This class is part of a private API. + You should avoid using this class if possible, as it may be removed or be changed in the future. +

+

Responsible for the JSON schema and mapping of a SchemaElements::EnumType.

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Attribute Details

+ + + +
+

+ + #enum_value_namesArray<String> (readonly) + + + + + +

+
+

Returns list of names of values in this enum type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Array<String>) + + + + — +

    list of names of values in this enum type.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb', line 25
+
+class Enum < ::Data
+  # @return [Hash<String, ::Object>] the JSON schema for this enum type.
+  def to_json_schema
+    {"type" => "string", "enum" => enum_value_names}
+  end
+
+  # @return [Hash<String, ::Object>] the datastore mapping for this enum type.
+  def to_mapping
+    {"type" => "keyword"}
+  end
+
+  # @return [Hash<String, ::Object>] additional ElasticGraph metadata to put in the JSON schema for this enum type.
+  def 
+    {}
+  end
+
+  # @param customizations [Hash<String, ::Object>] JSON schema customizations
+  # @return [Hash<String, ::Object>] formatted customizations.
+  def format_field_json_schema_customizations(customizations)
+    # Since an enum type already restricts the values to a small set of allowed values, we do not need to keep
+    # other customizations (such as the `maxLength` field customization EG automatically applies to fields
+    # indexed as a `keyword`--we don't allow enum values to exceed that length, anyway).
+    #
+    # It's desirable to restrict what customizations are applied because when a publisher uses the JSON schema
+    # to generate code using a library such as https://github.com/pwall567/json-kotlin-schema-codegen, we found
+    # that the presence of extra field customizations inhibits the library's ability to generate code in the way
+    # we want (it causes the type of the enum to change since the JSON schema changes from a direct `$ref` to
+    # being wrapped in an `allOf`).
+    #
+    # However, we still want to apply `enum` customizations--this allows a user to "narrow" the set of allowed
+    # values for a field. For example, a `Currency` enum could contain every currency, and a user may want to
+    # restrict a specific `currency` field to a subset of currencies (e.g. to just USD, CAD, and EUR).
+    customizations.slice("enum")
+  end
+
+  # @dynamic initialize, enum_value_names
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #format_field_json_schema_customizations(customizations) ⇒ Hash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns formatted customizations.

+ + +
+
+
+

Parameters:

+
    + +
  • + + customizations + + + (Hash<String, ::Object>) + + + + — +

    JSON schema customizations

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    formatted customizations.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb', line 43
+
+def format_field_json_schema_customizations(customizations)
+  # Since an enum type already restricts the values to a small set of allowed values, we do not need to keep
+  # other customizations (such as the `maxLength` field customization EG automatically applies to fields
+  # indexed as a `keyword`--we don't allow enum values to exceed that length, anyway).
+  #
+  # It's desirable to restrict what customizations are applied because when a publisher uses the JSON schema
+  # to generate code using a library such as https://github.com/pwall567/json-kotlin-schema-codegen, we found
+  # that the presence of extra field customizations inhibits the library's ability to generate code in the way
+  # we want (it causes the type of the enum to change since the JSON schema changes from a direct `$ref` to
+  # being wrapped in an `allOf`).
+  #
+  # However, we still want to apply `enum` customizations--this allows a user to "narrow" the set of allowed
+  # values for a field. For example, a `Currency` enum could contain every currency, and a user may want to
+  # restrict a specific `currency` field to a subset of currencies (e.g. to just USD, CAD, and EUR).
+  customizations.slice("enum")
+end
+
+
+ +
+

+ + #json_schema_field_metadata_by_field_nameHash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns additional ElasticGraph metadata to put in the JSON schema for this enum type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    additional ElasticGraph metadata to put in the JSON schema for this enum type.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+37
+38
+39
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb', line 37
+
+def 
+  {}
+end
+
+
+ +
+

+ + #to_json_schemaHash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns the JSON schema for this enum type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    the JSON schema for this enum type.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+27
+28
+29
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb', line 27
+
+def to_json_schema
+  {"type" => "string", "enum" => enum_value_names}
+end
+
+
+ +
+

+ + #to_mappingHash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns the datastore mapping for this enum type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    the datastore mapping for this enum type.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+32
+33
+34
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb', line 32
+
+def to_mapping
+  {"type" => "keyword"}
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType/Object.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType/Object.html new file mode 100644 index 00000000..53055791 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType/Object.html @@ -0,0 +1,1539 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::Indexing::FieldType::Object + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::Indexing::FieldType::Object + + + Private +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/object.rb
+
+ +
+ +

Overview

+
+

+ This class is part of a private API. + You should avoid using this class if possible, as it may be removed or be changed in the future. +

+

Responsible for the JSON schema and mapping of a SchemaElements::ObjectType.

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + + +
+

Instance Attribute Details

+ + + +
+

+ + #json_schema_optionsHash<String, ::Object> (readonly) + + + + + +

+
+

Returns options to be included in the JSON schema.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    options to be included in the JSON schema

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/object.rb', line 29
+
+class Object < Support::MemoizableData.define(:type_name, :subfields, :mapping_options, :json_schema_options)
+  # @return [Hash<String, ::Object>] the datastore mapping for this object type.
+  def to_mapping
+    @to_mapping ||= begin
+      base_mapping = Field.normalized_mapping_hash_for(subfields)
+      # When a custom mapping type is used, we need to omit `properties`, because custom mapping
+      # types generally don't use `properties` (and if you need to use `properties` with a custom
+      # type, you're responsible for defining the properties).
+      base_mapping = base_mapping.except("properties") if (mapping_options[:type] || "object") != "object"
+      base_mapping.merge(Support::HashUtil.stringify_keys(mapping_options))
+    end
+  end
+
+  # @return [Hash<String, ::Object>] the JSON schema for this object type.
+  def to_json_schema
+    @to_json_schema ||=
+      if json_schema_options.empty?
+        # Fields that are `sourced_from` an alternate type must not be included in this types JSON schema,
+        # since events of this type won't include them.
+        other_source_subfields, json_schema_candidate_subfields = subfields.partition(&:source)
+        validate_sourced_fields_have_no_json_schema_overrides(other_source_subfields)
+        json_schema_subfields = json_schema_candidate_subfields.reject(&:runtime_field_script)
+
+        {
+          "type" => "object",
+          "properties" => json_schema_subfields.to_h { |f| [f.name, f.json_schema] }.merge(json_schema_typename_field),
+          # Note: `__typename` is intentionally not included in the `required` list. If `__typename` is present
+          # we want it validated (as we do by merging in `json_schema_typename_field`) but we only want
+          # to require it in the context of a union type. The union's json schema requires the field.
+          "required" => json_schema_subfields.map(&:name).freeze
+        }.freeze
+      else
+        Support::HashUtil.stringify_keys(json_schema_options)
+      end
+  end
+
+  # @return [Hash<String, ::Object>] additional ElasticGraph metadata to put in the JSON schema for this object type.
+  def 
+    subfields.to_h { |f| [f.name, f.] }
+  end
+
+  # @param customizations [Hash<String, ::Object>] JSON schema customizations
+  # @return [Hash<String, ::Object>] formatted customizations.
+  def format_field_json_schema_customizations(customizations)
+    customizations
+  end
+
+  private
+
+  def after_initialize
+    subfields.freeze
+  end
+
+  # Returns a __typename property which we use for union types.
+  #
+  # This must always be set to the name of the type (thus the const value).
+  #
+  # We also add a "default" value. This does not impact validation, but rather
+  # aids tools like our kotlin codegen to save publishers from having to set the
+  # property explicitly when creating events.
+  def json_schema_typename_field
+    {
+      "__typename" => {
+        "type" => "string",
+        "const" => type_name,
+        "default" => type_name
+      }
+    }
+  end
+
+  def validate_sourced_fields_have_no_json_schema_overrides(other_source_subfields)
+    problem_fields = other_source_subfields.reject { |f| f.json_schema_customizations.empty? }
+    return if problem_fields.empty?
+
+    field_descriptions = problem_fields.map(&:name).sort.map { |f| "`#{f}`" }.join(", ")
+    raise Errors::SchemaError,
+      "`#{type_name}` has #{problem_fields.size} field(s) (#{field_descriptions}) that are `sourced_from` " \
+      "another type and also have JSON schema customizations. Instead, put the JSON schema " \
+      "customizations on the source type's field definitions."
+  end
+end
+
+
+ + + +
+

+ + #mapping_optionsHash<String, ::Object> (readonly) + + + + + +

+
+

Returns options to be included in the mapping.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    options to be included in the mapping

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/object.rb', line 29
+
+class Object < Support::MemoizableData.define(:type_name, :subfields, :mapping_options, :json_schema_options)
+  # @return [Hash<String, ::Object>] the datastore mapping for this object type.
+  def to_mapping
+    @to_mapping ||= begin
+      base_mapping = Field.normalized_mapping_hash_for(subfields)
+      # When a custom mapping type is used, we need to omit `properties`, because custom mapping
+      # types generally don't use `properties` (and if you need to use `properties` with a custom
+      # type, you're responsible for defining the properties).
+      base_mapping = base_mapping.except("properties") if (mapping_options[:type] || "object") != "object"
+      base_mapping.merge(Support::HashUtil.stringify_keys(mapping_options))
+    end
+  end
+
+  # @return [Hash<String, ::Object>] the JSON schema for this object type.
+  def to_json_schema
+    @to_json_schema ||=
+      if json_schema_options.empty?
+        # Fields that are `sourced_from` an alternate type must not be included in this types JSON schema,
+        # since events of this type won't include them.
+        other_source_subfields, json_schema_candidate_subfields = subfields.partition(&:source)
+        validate_sourced_fields_have_no_json_schema_overrides(other_source_subfields)
+        json_schema_subfields = json_schema_candidate_subfields.reject(&:runtime_field_script)
+
+        {
+          "type" => "object",
+          "properties" => json_schema_subfields.to_h { |f| [f.name, f.json_schema] }.merge(json_schema_typename_field),
+          # Note: `__typename` is intentionally not included in the `required` list. If `__typename` is present
+          # we want it validated (as we do by merging in `json_schema_typename_field`) but we only want
+          # to require it in the context of a union type. The union's json schema requires the field.
+          "required" => json_schema_subfields.map(&:name).freeze
+        }.freeze
+      else
+        Support::HashUtil.stringify_keys(json_schema_options)
+      end
+  end
+
+  # @return [Hash<String, ::Object>] additional ElasticGraph metadata to put in the JSON schema for this object type.
+  def 
+    subfields.to_h { |f| [f.name, f.] }
+  end
+
+  # @param customizations [Hash<String, ::Object>] JSON schema customizations
+  # @return [Hash<String, ::Object>] formatted customizations.
+  def format_field_json_schema_customizations(customizations)
+    customizations
+  end
+
+  private
+
+  def after_initialize
+    subfields.freeze
+  end
+
+  # Returns a __typename property which we use for union types.
+  #
+  # This must always be set to the name of the type (thus the const value).
+  #
+  # We also add a "default" value. This does not impact validation, but rather
+  # aids tools like our kotlin codegen to save publishers from having to set the
+  # property explicitly when creating events.
+  def json_schema_typename_field
+    {
+      "__typename" => {
+        "type" => "string",
+        "const" => type_name,
+        "default" => type_name
+      }
+    }
+  end
+
+  def validate_sourced_fields_have_no_json_schema_overrides(other_source_subfields)
+    problem_fields = other_source_subfields.reject { |f| f.json_schema_customizations.empty? }
+    return if problem_fields.empty?
+
+    field_descriptions = problem_fields.map(&:name).sort.map { |f| "`#{f}`" }.join(", ")
+    raise Errors::SchemaError,
+      "`#{type_name}` has #{problem_fields.size} field(s) (#{field_descriptions}) that are `sourced_from` " \
+      "another type and also have JSON schema customizations. Instead, put the JSON schema " \
+      "customizations on the source type's field definitions."
+  end
+end
+
+
+ + + +
+

+ + #subfieldsArray<Field> (readonly) + + + + + +

+
+

Returns the subfields of this object type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Array<Field>) + + + + — +

    the subfields of this object type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/object.rb', line 29
+
+class Object < Support::MemoizableData.define(:type_name, :subfields, :mapping_options, :json_schema_options)
+  # @return [Hash<String, ::Object>] the datastore mapping for this object type.
+  def to_mapping
+    @to_mapping ||= begin
+      base_mapping = Field.normalized_mapping_hash_for(subfields)
+      # When a custom mapping type is used, we need to omit `properties`, because custom mapping
+      # types generally don't use `properties` (and if you need to use `properties` with a custom
+      # type, you're responsible for defining the properties).
+      base_mapping = base_mapping.except("properties") if (mapping_options[:type] || "object") != "object"
+      base_mapping.merge(Support::HashUtil.stringify_keys(mapping_options))
+    end
+  end
+
+  # @return [Hash<String, ::Object>] the JSON schema for this object type.
+  def to_json_schema
+    @to_json_schema ||=
+      if json_schema_options.empty?
+        # Fields that are `sourced_from` an alternate type must not be included in this types JSON schema,
+        # since events of this type won't include them.
+        other_source_subfields, json_schema_candidate_subfields = subfields.partition(&:source)
+        validate_sourced_fields_have_no_json_schema_overrides(other_source_subfields)
+        json_schema_subfields = json_schema_candidate_subfields.reject(&:runtime_field_script)
+
+        {
+          "type" => "object",
+          "properties" => json_schema_subfields.to_h { |f| [f.name, f.json_schema] }.merge(json_schema_typename_field),
+          # Note: `__typename` is intentionally not included in the `required` list. If `__typename` is present
+          # we want it validated (as we do by merging in `json_schema_typename_field`) but we only want
+          # to require it in the context of a union type. The union's json schema requires the field.
+          "required" => json_schema_subfields.map(&:name).freeze
+        }.freeze
+      else
+        Support::HashUtil.stringify_keys(json_schema_options)
+      end
+  end
+
+  # @return [Hash<String, ::Object>] additional ElasticGraph metadata to put in the JSON schema for this object type.
+  def 
+    subfields.to_h { |f| [f.name, f.] }
+  end
+
+  # @param customizations [Hash<String, ::Object>] JSON schema customizations
+  # @return [Hash<String, ::Object>] formatted customizations.
+  def format_field_json_schema_customizations(customizations)
+    customizations
+  end
+
+  private
+
+  def after_initialize
+    subfields.freeze
+  end
+
+  # Returns a __typename property which we use for union types.
+  #
+  # This must always be set to the name of the type (thus the const value).
+  #
+  # We also add a "default" value. This does not impact validation, but rather
+  # aids tools like our kotlin codegen to save publishers from having to set the
+  # property explicitly when creating events.
+  def json_schema_typename_field
+    {
+      "__typename" => {
+        "type" => "string",
+        "const" => type_name,
+        "default" => type_name
+      }
+    }
+  end
+
+  def validate_sourced_fields_have_no_json_schema_overrides(other_source_subfields)
+    problem_fields = other_source_subfields.reject { |f| f.json_schema_customizations.empty? }
+    return if problem_fields.empty?
+
+    field_descriptions = problem_fields.map(&:name).sort.map { |f| "`#{f}`" }.join(", ")
+    raise Errors::SchemaError,
+      "`#{type_name}` has #{problem_fields.size} field(s) (#{field_descriptions}) that are `sourced_from` " \
+      "another type and also have JSON schema customizations. Instead, put the JSON schema " \
+      "customizations on the source type's field definitions."
+  end
+end
+
+
+ + + +
+

+ + #type_nameString (readonly) + + + + + +

+
+

Returns name of the object type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    name of the object type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/object.rb', line 29
+
+class Object < Support::MemoizableData.define(:type_name, :subfields, :mapping_options, :json_schema_options)
+  # @return [Hash<String, ::Object>] the datastore mapping for this object type.
+  def to_mapping
+    @to_mapping ||= begin
+      base_mapping = Field.normalized_mapping_hash_for(subfields)
+      # When a custom mapping type is used, we need to omit `properties`, because custom mapping
+      # types generally don't use `properties` (and if you need to use `properties` with a custom
+      # type, you're responsible for defining the properties).
+      base_mapping = base_mapping.except("properties") if (mapping_options[:type] || "object") != "object"
+      base_mapping.merge(Support::HashUtil.stringify_keys(mapping_options))
+    end
+  end
+
+  # @return [Hash<String, ::Object>] the JSON schema for this object type.
+  def to_json_schema
+    @to_json_schema ||=
+      if json_schema_options.empty?
+        # Fields that are `sourced_from` an alternate type must not be included in this types JSON schema,
+        # since events of this type won't include them.
+        other_source_subfields, json_schema_candidate_subfields = subfields.partition(&:source)
+        validate_sourced_fields_have_no_json_schema_overrides(other_source_subfields)
+        json_schema_subfields = json_schema_candidate_subfields.reject(&:runtime_field_script)
+
+        {
+          "type" => "object",
+          "properties" => json_schema_subfields.to_h { |f| [f.name, f.json_schema] }.merge(json_schema_typename_field),
+          # Note: `__typename` is intentionally not included in the `required` list. If `__typename` is present
+          # we want it validated (as we do by merging in `json_schema_typename_field`) but we only want
+          # to require it in the context of a union type. The union's json schema requires the field.
+          "required" => json_schema_subfields.map(&:name).freeze
+        }.freeze
+      else
+        Support::HashUtil.stringify_keys(json_schema_options)
+      end
+  end
+
+  # @return [Hash<String, ::Object>] additional ElasticGraph metadata to put in the JSON schema for this object type.
+  def 
+    subfields.to_h { |f| [f.name, f.] }
+  end
+
+  # @param customizations [Hash<String, ::Object>] JSON schema customizations
+  # @return [Hash<String, ::Object>] formatted customizations.
+  def format_field_json_schema_customizations(customizations)
+    customizations
+  end
+
+  private
+
+  def after_initialize
+    subfields.freeze
+  end
+
+  # Returns a __typename property which we use for union types.
+  #
+  # This must always be set to the name of the type (thus the const value).
+  #
+  # We also add a "default" value. This does not impact validation, but rather
+  # aids tools like our kotlin codegen to save publishers from having to set the
+  # property explicitly when creating events.
+  def json_schema_typename_field
+    {
+      "__typename" => {
+        "type" => "string",
+        "const" => type_name,
+        "default" => type_name
+      }
+    }
+  end
+
+  def validate_sourced_fields_have_no_json_schema_overrides(other_source_subfields)
+    problem_fields = other_source_subfields.reject { |f| f.json_schema_customizations.empty? }
+    return if problem_fields.empty?
+
+    field_descriptions = problem_fields.map(&:name).sort.map { |f| "`#{f}`" }.join(", ")
+    raise Errors::SchemaError,
+      "`#{type_name}` has #{problem_fields.size} field(s) (#{field_descriptions}) that are `sourced_from` " \
+      "another type and also have JSON schema customizations. Instead, put the JSON schema " \
+      "customizations on the source type's field definitions."
+  end
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #format_field_json_schema_customizations(customizations) ⇒ Hash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns formatted customizations.

+ + +
+
+
+

Parameters:

+
    + +
  • + + customizations + + + (Hash<String, ::Object>) + + + + — +

    JSON schema customizations

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    formatted customizations.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+72
+73
+74
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/object.rb', line 72
+
+def format_field_json_schema_customizations(customizations)
+  customizations
+end
+
+
+ +
+

+ + #json_schema_field_metadata_by_field_nameHash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns additional ElasticGraph metadata to put in the JSON schema for this object type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    additional ElasticGraph metadata to put in the JSON schema for this object type.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+66
+67
+68
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/object.rb', line 66
+
+def 
+  subfields.to_h { |f| [f.name, f.] }
+end
+
+
+ +
+

+ + #to_json_schemaHash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns the JSON schema for this object type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    the JSON schema for this object type.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/object.rb', line 43
+
+def to_json_schema
+  @to_json_schema ||=
+    if json_schema_options.empty?
+      # Fields that are `sourced_from` an alternate type must not be included in this types JSON schema,
+      # since events of this type won't include them.
+      other_source_subfields, json_schema_candidate_subfields = subfields.partition(&:source)
+      validate_sourced_fields_have_no_json_schema_overrides(other_source_subfields)
+      json_schema_subfields = json_schema_candidate_subfields.reject(&:runtime_field_script)
+
+      {
+        "type" => "object",
+        "properties" => json_schema_subfields.to_h { |f| [f.name, f.json_schema] }.merge(json_schema_typename_field),
+        # Note: `__typename` is intentionally not included in the `required` list. If `__typename` is present
+        # we want it validated (as we do by merging in `json_schema_typename_field`) but we only want
+        # to require it in the context of a union type. The union's json schema requires the field.
+        "required" => json_schema_subfields.map(&:name).freeze
+      }.freeze
+    else
+      Support::HashUtil.stringify_keys(json_schema_options)
+    end
+end
+
+
+ +
+

+ + #to_mappingHash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns the datastore mapping for this object type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    the datastore mapping for this object type.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/object.rb', line 31
+
+def to_mapping
+  @to_mapping ||= begin
+    base_mapping = Field.normalized_mapping_hash_for(subfields)
+    # When a custom mapping type is used, we need to omit `properties`, because custom mapping
+    # types generally don't use `properties` (and if you need to use `properties` with a custom
+    # type, you're responsible for defining the properties).
+    base_mapping = base_mapping.except("properties") if (mapping_options[:type] || "object") != "object"
+    base_mapping.merge(Support::HashUtil.stringify_keys(mapping_options))
+  end
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType/Scalar.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType/Scalar.html new file mode 100644 index 00000000..be5659ad --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType/Scalar.html @@ -0,0 +1,651 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::Indexing::FieldType::Scalar + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::Indexing::FieldType::Scalar + + + Private +

+
+ +
+
Inherits:
+
+ Data + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb,
+ elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb
+
+
+ +
+ +

Overview

+
+

+ This class is part of a private API. + You should avoid using this class if possible, as it may be removed or be changed in the future. +

+

Responsible for the JSON schema and mapping of a SchemaElements::ScalarType.

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Attribute Details

+ + + +
+

+ + #scalar_typeSchemaElements::ScalarType (readonly) + + + + + +

+
+

Returns the scalar type.

+ + +
+
+
+ +

Returns:

+ + +
+ + + + +
+
+
+
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb', line 24
+
+class Scalar < ::Data
+  # @return [Hash<String, ::Object>] the datastore mapping for this scalar type.
+  def to_mapping
+    Support::HashUtil.stringify_keys(scalar_type.mapping_options)
+  end
+
+  # @return [Hash<String, ::Object>] the JSON schema for this scalar type.
+  def to_json_schema
+    Support::HashUtil.stringify_keys(scalar_type.json_schema_options)
+  end
+
+  # @return [Hash<String, ::Object>] additional ElasticGraph metadata to put in the JSON schema for this scalar type.
+  def 
+    {}
+  end
+
+  # @param customizations [Hash<String, ::Object>] JSON schema customizations
+  # @return [Hash<String, ::Object>] formatted customizations.
+  def format_field_json_schema_customizations(customizations)
+    customizations
+  end
+
+  # @dynamic initialize, scalar_type
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #format_field_json_schema_customizations(customizations) ⇒ Hash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns formatted customizations.

+ + +
+
+
+

Parameters:

+
    + +
  • + + customizations + + + (Hash<String, ::Object>) + + + + — +

    JSON schema customizations

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    formatted customizations.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+42
+43
+44
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb', line 42
+
+def format_field_json_schema_customizations(customizations)
+  customizations
+end
+
+
+ +
+

+ + #json_schema_field_metadata_by_field_nameHash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns additional ElasticGraph metadata to put in the JSON schema for this scalar type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    additional ElasticGraph metadata to put in the JSON schema for this scalar type.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+36
+37
+38
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb', line 36
+
+def 
+  {}
+end
+
+
+ +
+

+ + #to_json_schemaHash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns the JSON schema for this scalar type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    the JSON schema for this scalar type.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+31
+32
+33
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb', line 31
+
+def to_json_schema
+  Support::HashUtil.stringify_keys(scalar_type.json_schema_options)
+end
+
+
+ +
+

+ + #to_mappingHash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns the datastore mapping for this scalar type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    the datastore mapping for this scalar type.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+26
+27
+28
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb', line 26
+
+def to_mapping
+  Support::HashUtil.stringify_keys(scalar_type.mapping_options)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType/Union.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType/Union.html new file mode 100644 index 00000000..fc4a383d --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/FieldType/Union.html @@ -0,0 +1,732 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::Indexing::FieldType::Union + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::Indexing::FieldType::Union + + + Private +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/union.rb
+
+ +
+ +

Overview

+
+

+ This class is part of a private API. + You should avoid using this class if possible, as it may be removed or be changed in the future. +

+ +
+ Note: +

In JSON schema, we model this with a oneOf, and a __typename field on each subtype.

+
+
+ +
+ Note: +

Within the mapping, we have a single object type that has a set union of the properties +of the subtypes (and also a __typename keyword field).

+
+
+ +

Responsible for the JSON schema and mapping of a SchemaElements::UnionType.

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + + +
+

Instance Attribute Details

+ + + +
+

+ + #subtypes_by_nameHash<String, Object> (readonly) + + + + + +

+
+

Returns the subtypes of the union, keyed by name.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, Object>) + + + + — +

    the subtypes of the union, keyed by name.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/union.rb', line 26
+
+class Union < ::Data.define(:subtypes_by_name)
+  # @return [Hash<String, ::Object>] the JSON schema for this union type.
+  def to_json_schema
+    subtype_json_schemas = subtypes_by_name.keys.map { |name| {"$ref" => "#/$defs/#{name}"} }
+
+    # A union type can represent multiple subtypes, referenced by the "anyOf" clause below.
+    # We also add a requirement for the presence of __typename to indicate which type
+    # is being referenced (this property is pre-defined on the type itself as a constant).
+    #
+    # Note: Although both "oneOf" and "anyOf" keywords are valid for combining schemas
+    # to form a union, and validate equivalently when no object can satisfy multiple of the
+    # subschemas (which is the case here given the __typename requirements are mutually
+    # exclusive), we chose to use "oneOf" here because it works better with this library:
+    # https://github.com/pwall567/json-kotlin-schema-codegen
+    {
+      "required" => %w[__typename],
+      "oneOf" => subtype_json_schemas
+    }
+  end
+
+  # @return [Hash<String, ::Object>] the datastore mapping for this union type.
+  def to_mapping
+    mapping_subfields = subtypes_by_name.values.map(&:subfields).reduce([], :union)
+
+    Support::HashUtil.deep_merge(
+      Field.normalized_mapping_hash_for(mapping_subfields),
+      {"properties" => {"__typename" => {"type" => "keyword"}}}
+    )
+  end
+
+  # @return [Hash<String, ::Object>] additional ElasticGraph metadata to put in the JSON schema for this union type.
+  def 
+    {}
+  end
+
+  # @param customizations [Hash<String, ::Object>] JSON schema customizations
+  # @return [Hash<String, ::Object>] formatted customizations.
+  def format_field_json_schema_customizations(customizations)
+    customizations
+  end
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #format_field_json_schema_customizations(customizations) ⇒ Hash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns formatted customizations.

+ + +
+
+
+

Parameters:

+
    + +
  • + + customizations + + + (Hash<String, ::Object>) + + + + — +

    JSON schema customizations

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    formatted customizations.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+63
+64
+65
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/union.rb', line 63
+
+def format_field_json_schema_customizations(customizations)
+  customizations
+end
+
+
+ +
+

+ + #json_schema_field_metadata_by_field_nameHash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns additional ElasticGraph metadata to put in the JSON schema for this union type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    additional ElasticGraph metadata to put in the JSON schema for this union type.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+57
+58
+59
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/union.rb', line 57
+
+def 
+  {}
+end
+
+
+ +
+

+ + #to_json_schemaHash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns the JSON schema for this union type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    the JSON schema for this union type.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/union.rb', line 28
+
+def to_json_schema
+  subtype_json_schemas = subtypes_by_name.keys.map { |name| {"$ref" => "#/$defs/#{name}"} }
+
+  # A union type can represent multiple subtypes, referenced by the "anyOf" clause below.
+  # We also add a requirement for the presence of __typename to indicate which type
+  # is being referenced (this property is pre-defined on the type itself as a constant).
+  #
+  # Note: Although both "oneOf" and "anyOf" keywords are valid for combining schemas
+  # to form a union, and validate equivalently when no object can satisfy multiple of the
+  # subschemas (which is the case here given the __typename requirements are mutually
+  # exclusive), we chose to use "oneOf" here because it works better with this library:
+  # https://github.com/pwall567/json-kotlin-schema-codegen
+  {
+    "required" => %w[__typename],
+    "oneOf" => subtype_json_schemas
+  }
+end
+
+
+ +
+

+ + #to_mappingHash<String, ::Object> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns the datastore mapping for this union type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, ::Object>) + + + + — +

    the datastore mapping for this union type.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+47
+48
+49
+50
+51
+52
+53
+54
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/field_type/union.rb', line 47
+
+def to_mapping
+  mapping_subfields = subtypes_by_name.values.map(&:subfields).reduce([], :union)
+
+  Support::HashUtil.deep_merge(
+    Field.normalized_mapping_hash_for(mapping_subfields),
+    {"properties" => {"__typename" => {"type" => "keyword"}}}
+  )
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/Index.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/Index.html new file mode 100644 index 00000000..74cbe1e8 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/Index.html @@ -0,0 +1,5597 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::Indexing::Index + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::Indexing::Index + + + +

+
+ +
+
Inherits:
+
+ Struct + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb
+
+ +
+ +

Overview

+
+

Represents an index in a datastore. Defined within an indexed type. Modeled as a separate object to facilitate +further customization of the index.

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + + +
+

Constructor Details

+ +
+

+ + #initialize(name, settings, schema_def_state, indexed_type) {|Index| ... } ⇒ Index + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns a new instance of Index.

+ + +
+
+
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    name of the index

    +
    + +
  • + +
  • + + settings + + + (Hash<(String, Object)>) + + + + — +

    datastore settings for the index

    +
    + +
  • + +
  • + + schema_def_state + + + (State) + + + + — +

    schema definition state

    +
    + +
  • + +
  • + + indexed_type + + + (SchemaElements::ObjectType, SchemaElements::InterfaceType, SchemaElements::UnionType) + + + + — +

    type backed by this index

    +
    + +
  • + +
+ +

Yields:

+
    + +
  • + + + (Index) + + + + — +

    the index, for further customization

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 48
+
+def initialize(name, settings, schema_def_state, indexed_type)
+  if name.include?(ROLLOVER_INDEX_INFIX_MARKER)
+    raise Errors::SchemaError, "`#{name}` is an invalid index definition name since it contains " \
+      "`#{ROLLOVER_INDEX_INFIX_MARKER}` which ElasticGraph treats as special."
+  end
+
+  settings = DEFAULT_SETTINGS.merge(Support::HashUtil.flatten_and_stringify_keys(settings, prefix: "index"))
+
+  super(name, [], settings, schema_def_state, indexed_type, [], nil)
+
+  # `id` is the field Elasticsearch/OpenSearch use for routing by default:
+  # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-routing-field.html
+  # By using it here, it will cause queries to pass a `routing` parameter when
+  # searching with id filtering on an index that does not use custom shard routing, giving
+  # us a nice efficiency boost.
+  self.routing_field_path = public_field_path("id", explanation: "indexed types must have an `id` field")
+
+  yield self if block_given?
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #default_sort_pairsArray<(String, Symbol)> (readonly) + + + + + +

+
+

Returns (field name, direction) pairs for the default sort.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Array<(String, Symbol)>) + + + + — +

    (field name, direction) pairs for the default sort

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 39
+
+class Index < Struct.new(:name, :default_sort_pairs, :settings, :schema_def_state, :indexed_type, :routing_field_path, :rollover_config)
+  include Mixins::HasReadableToSAndInspect.new { |i| i.name }
+
+  # @param name [String] name of the index
+  # @param settings [Hash<(String, Object)>] datastore settings for the index
+  # @param schema_def_state [State] schema definition state
+  # @param indexed_type [SchemaElements::ObjectType, SchemaElements::InterfaceType, SchemaElements::UnionType] type backed by this index
+  # @yield [Index] the index, for further customization
+  # @api private
+  def initialize(name, settings, schema_def_state, indexed_type)
+    if name.include?(ROLLOVER_INDEX_INFIX_MARKER)
+      raise Errors::SchemaError, "`#{name}` is an invalid index definition name since it contains " \
+        "`#{ROLLOVER_INDEX_INFIX_MARKER}` which ElasticGraph treats as special."
+    end
+
+    settings = DEFAULT_SETTINGS.merge(Support::HashUtil.flatten_and_stringify_keys(settings, prefix: "index"))
+
+    super(name, [], settings, schema_def_state, indexed_type, [], nil)
+
+    # `id` is the field Elasticsearch/OpenSearch use for routing by default:
+    # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-routing-field.html
+    # By using it here, it will cause queries to pass a `routing` parameter when
+    # searching with id filtering on an index that does not use custom shard routing, giving
+    # us a nice efficiency boost.
+    self.routing_field_path = public_field_path("id", explanation: "indexed types must have an `id` field")
+
+    yield self if block_given?
+  end
+
+  # Specifies how documents in this index should sort by default, when no `orderBy` argument is provided to the GraphQL query.
+  #
+  # @note the field name strings can be a dot-separated nested fields, but all referenced
+  #   fields must exist when this is called.
+  #
+  # @param field_name_direction_pairs [Array<(String, Symbol)>] pairs of field names and `:asc` or `:desc`
+  # @return [void]
+  #
+  # @example Sort on `name` (ascending) with `createdAt` (descending) as a tie-breaker
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "createdAt", "DateTime"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.default_sort "name", :asc, "createdAt", :desc
+  #       end
+  #     end
+  #   end
+  def default_sort(*field_name_direction_pairs)
+    self.default_sort_pairs = field_name_direction_pairs
+  end
+
+  # Causes this index to "rollover" at the provided `frequency` based on the value of the provided `timestamp_field_path_name`.
+  # This is particularly useful for time-series data. Partitioning the data into `hourly`, `daily`, `monthly` or `yearly` buckets
+  # allows for different index configurations, and can be necessary when a dataset is too large to fit in one dataset given
+  # Elasticsearch/OpenSearch limitations on the number of shards in one index. In addition, ElasticGraph optimizes queries which
+  # filter on the timestamp field to target the subset of the indices in which matching documents could reside.
+  #
+  # @note the timestamp field specified here **must be immutable**. To understand why, consider a `:yearly` rollover
+  #   index used for data based on `createdAt`; if ElasticGraph ingests record `123` with a createdAt of `2023-12-31T23:59:59Z`, it
+  #   will be indexed in the `2023` index. Later if it receives an update event for record `123` with a `createdAt` of
+  #   `2024-01-01T00:00:00Z` (a mere one second later!), ElasticGraph will store the new version of the payment in the `2024` index,
+  #   and leave the old copy of the payment in the `2023` index unchanged. It’ll have duplicates for that document.
+  # @note changing the `rollover` configuration on an existing index that already has data will result in duplicate documents
+  #
+  # @param frequency [:yearly, :monthly, :daily, :hourly] how often to rollover the index
+  # @param timestamp_field_path_name [String] dot-separated path to the timestamp field used for rollover. Note: all referenced
+  #   fields must exist when this is called.
+  # @return [void]
+  #
+  # @example Define a `campaigns` index to rollover yearly based on `createdAt`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "createdAt", "DateTime"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.rollover :yearly, "createdAt"
+  #       end
+  #     end
+  #   end
+  def rollover(frequency, timestamp_field_path_name)
+    timestamp_field_path = public_field_path(timestamp_field_path_name, explanation: "it is referenced as an index `rollover` field")
+
+    unless date_and_datetime_types.include?(timestamp_field_path.type.fully_unwrapped.name)
+      date_or_datetime_description = date_and_datetime_types.map { |t| "`#{t}`" }.join(" or ")
+      raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is not a #{date_or_datetime_description} field."
+    end
+
+    if timestamp_field_path.type.list?
+      raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is a list field."
+    end
+
+    timestamp_field_path.path_parts.each { |f| f.json_schema nullable: false }
+
+    self.rollover_config = RolloverConfig.new(
+      frequency: frequency,
+      timestamp_field_path: timestamp_field_path
+    )
+  end
+
+  # Configures the index to [route documents to shards](https://www.elastic.co/guide/en/elasticsearch/reference/8.15/mapping-routing-field.html)
+  # based on the specified field. ElasticGraph optimizes queries that filter on the shard routing field so that they only run on a
+  # subset of nodes instead of all nodes. This can make a big difference in query performance if queries usually filter on a certain
+  # field. Using an appropriate field for shard routing is often essential for horizontal scaling, as it avoids having every query
+  # hit every node, allowing additional nodes to increase query throughput.
+  #
+  # @note it is essential that the shards are well-balanced. If the data’s distribution is lopsided, using this feature can make
+  #   performance worse.
+  # @note the routing field specified here **must be immutable**. If ElasticGraph receives an updated version of a document with a
+  #   different routing value, it’ll write the new version of the document to a different shard and leave the copy on the old shard
+  #   unchanged, leading to duplicates.
+  # @note changing the shard routing configuration on an existing index that already has data will result in duplicate documents
+  #
+  # @param routing_field_path_name [String] dot-separated path to the field used for shard routing. Note: all referenced
+  #   fields must exist when this is called.
+  # @return [void]
+  #
+  # @example Define a `campaigns` index to shard on `organizationId`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "organizationId", "ID"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.route_with "organizationId"
+  #       end
+  #     end
+  #   end
+  def route_with(routing_field_path_name)
+    routing_field_path = public_field_path(routing_field_path_name, explanation: "it is referenced as an index `route_with` field")
+
+    unless routing_field_path.type.leaf?
+      raise Errors::SchemaError, "shard routing field `#{routing_field_path.full_description}` cannot be used for routing since it is not a leaf field."
+    end
+
+    self.routing_field_path = routing_field_path
+
+    routing_field_path.path_parts[0..-2].each { |f| f.json_schema nullable: false }
+    routing_field_path.last_part.json_schema nullable: false, pattern: HAS_NON_WHITE_SPACE_REGEX
+    indexed_type.append_to_documentation "For more performant queries on this type, please filter on `#{routing_field_path_name}` if possible."
+  end
+
+  # @see #route_with
+  # @return [Boolean] whether or not this index uses custom shard routing
+  def uses_custom_routing?
+    routing_field_path.path_in_index != "id"
+  end
+
+  # @return [Hash<String, Object>] datastore configuration for this index for when it does not use rollover
+  def to_index_config
+    {
+      "aliases" => {},
+      "mappings" => mappings,
+      "settings" => settings
+    }.compact
+  end
+
+  # @return [Hash<String, Object>] datastore configuration for the index template that will be defined if rollover is used
+  def to_index_template_config
+    {
+      "index_patterns" => ["#{name}#{ROLLOVER_INDEX_INFIX_MARKER}*"],
+      "template" => {
+        "aliases" => {},
+        "mappings" => mappings,
+        "settings" => settings
+      }
+    }
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::IndexDefinition] runtime metadata for this index
+  def 
+    SchemaArtifacts::RuntimeMetadata::IndexDefinition.new(
+      route_with: routing_field_path.path_in_index,
+      rollover: rollover_config&.,
+      current_sources: indexed_type.current_sources,
+      fields_by_path: indexed_type..to_h,
+      default_sort_fields: default_sort_pairs.each_slice(2).map do |(graphql_field_path_name, direction)|
+        SchemaArtifacts::RuntimeMetadata::SortField.new(
+          field_path: public_field_path(graphql_field_path_name, explanation: "it is referenced as an index `default_sort` field").path_in_index,
+          direction: direction
+        )
+      end
+    )
+  end
+
+  private
+
+  # A regex that requires at least one non-whitespace character.
+  # Note: this does not use the `/S` character class because it's recommended to use a small subset
+  # of Regex syntax:
+  #
+  # > The regular expression syntax used is from JavaScript (ECMA 262, specifically). However, that
+  # > complete syntax is not widely supported, therefore it is recommended that you stick to the subset
+  # > of that syntax described below.
+  #
+  # (From https://json-schema.org/understanding-json-schema/reference/regular_expressions.html)
+  HAS_NON_WHITE_SPACE_REGEX = "[^ \t\n]+"
+
+  DEFAULT_SETTINGS = {
+    "index.mapping.ignore_malformed" => false,
+    "index.mapping.coerce" => false,
+    "index.number_of_replicas" => 1,
+    "index.number_of_shards" => 1
+  }
+
+  def mappings
+    field_mappings = indexed_type
+      .to_indexing_field_type
+      .to_mapping
+      .except("type") # `type` is invalid at the mapping root because it always has to be an object.
+      .then { |mapping| ListCountsMapping.merged_into(mapping, for_type: indexed_type) }
+      .then do |fm|
+        Support::HashUtil.deep_merge(fm, {"properties" => {
+          "__sources" => {"type" => "keyword"},
+          "__versions" => {
+            "type" => "object",
+            # __versions is map keyed by relationship name, with values that are maps keyed by id. Since it's not
+            # a static object with known fields, we need to use dynamic here. Passing `false` allows some level
+            # of dynamicness. As per https://www.elastic.co/guide/en/elasticsearch/reference/8.7/dynamic.html#dynamic-parameters:
+            #
+            # > New fields are ignored. These fields will not be indexed or searchable, but will still appear in the _source
+            # > field of returned hits. These fields will not be added to the mapping, and new fields must be added explicitly.
+            #
+            # We need `__versions` to be in `_source` (so that our update scripts can operate on it), but
+            # have no need for it to be searchable (as it's just an internal data structure used for indexing).
+            #
+            # Note: we intentionally set false as a string here, because that's how the datastore echoes it back
+            # to us when you query the mapping (even if you set it as a boolean). Our checks for index mapping
+            # consistency fail validation if we set it as a boolean since the datastore doesn't echo it back as
+            # a boolean.
+            "dynamic" => "false"
+          }
+        }})
+      end
+
+    {"dynamic" => "strict"}.merge(field_mappings).tap do |hash|
+      # If we are using custom shard routing, we want to require a `routing` value to be provided
+      # in every single index, get, delete or update request; otherwise the request might be
+      # made against the wrong shard.
+      hash["_routing"] = {"required" => true} if uses_custom_routing?
+      hash["_size"] = {"enabled" => true} if schema_def_state.index_document_sizes?
+    end
+  end
+
+  def public_field_path(public_path_string, explanation:)
+    parent_is_not_list = ->(parent_field) { !parent_field.type.list? }
+    resolver = SchemaElements::FieldPath::Resolver.new
+    resolved_path = resolver.resolve_public_path(indexed_type, public_path_string, &parent_is_not_list)
+    return resolved_path if resolved_path
+
+    path_parts = public_path_string.split(".")
+    error_msg = "Field `#{indexed_type.name}.#{public_path_string}` cannot be resolved, but #{explanation}."
+
+    # If it is a nested field path, the problem could be that a type has been referenced which does not exist, so mention that.
+    if path_parts.size > 1
+      error_msg += " Verify that all fields and types referenced by `#{public_path_string}` are defined."
+    end
+
+    # If the first part of the path doesn't resolve, the problem could be that the field is defined after the `index` call
+    # but it needs to be defined before it, so mention that.
+    if resolver.resolve_public_path(indexed_type, path_parts.first, &parent_is_not_list).nil?
+      error_msg += " Note: the `#{indexed_type.name}.#{path_parts.first}` definition must come before the `index` call."
+    end
+
+    raise Errors::SchemaError, error_msg
+  end
+
+  def date_and_datetime_types
+    @date_and_datetime_types ||= %w[Date DateTime].map do |type|
+      schema_def_state.type_namer.name_for(type)
+    end
+  end
+end
+
+
+ + + +
+

+ + #indexed_typeSchemaElements::ObjectType, ... (readonly) + + + + + +

+
+

Returns type backed by this index.

+ + +
+
+
+ +

Returns:

+ + +
+ + + + +
+
+
+
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 39
+
+class Index < Struct.new(:name, :default_sort_pairs, :settings, :schema_def_state, :indexed_type, :routing_field_path, :rollover_config)
+  include Mixins::HasReadableToSAndInspect.new { |i| i.name }
+
+  # @param name [String] name of the index
+  # @param settings [Hash<(String, Object)>] datastore settings for the index
+  # @param schema_def_state [State] schema definition state
+  # @param indexed_type [SchemaElements::ObjectType, SchemaElements::InterfaceType, SchemaElements::UnionType] type backed by this index
+  # @yield [Index] the index, for further customization
+  # @api private
+  def initialize(name, settings, schema_def_state, indexed_type)
+    if name.include?(ROLLOVER_INDEX_INFIX_MARKER)
+      raise Errors::SchemaError, "`#{name}` is an invalid index definition name since it contains " \
+        "`#{ROLLOVER_INDEX_INFIX_MARKER}` which ElasticGraph treats as special."
+    end
+
+    settings = DEFAULT_SETTINGS.merge(Support::HashUtil.flatten_and_stringify_keys(settings, prefix: "index"))
+
+    super(name, [], settings, schema_def_state, indexed_type, [], nil)
+
+    # `id` is the field Elasticsearch/OpenSearch use for routing by default:
+    # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-routing-field.html
+    # By using it here, it will cause queries to pass a `routing` parameter when
+    # searching with id filtering on an index that does not use custom shard routing, giving
+    # us a nice efficiency boost.
+    self.routing_field_path = public_field_path("id", explanation: "indexed types must have an `id` field")
+
+    yield self if block_given?
+  end
+
+  # Specifies how documents in this index should sort by default, when no `orderBy` argument is provided to the GraphQL query.
+  #
+  # @note the field name strings can be a dot-separated nested fields, but all referenced
+  #   fields must exist when this is called.
+  #
+  # @param field_name_direction_pairs [Array<(String, Symbol)>] pairs of field names and `:asc` or `:desc`
+  # @return [void]
+  #
+  # @example Sort on `name` (ascending) with `createdAt` (descending) as a tie-breaker
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "createdAt", "DateTime"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.default_sort "name", :asc, "createdAt", :desc
+  #       end
+  #     end
+  #   end
+  def default_sort(*field_name_direction_pairs)
+    self.default_sort_pairs = field_name_direction_pairs
+  end
+
+  # Causes this index to "rollover" at the provided `frequency` based on the value of the provided `timestamp_field_path_name`.
+  # This is particularly useful for time-series data. Partitioning the data into `hourly`, `daily`, `monthly` or `yearly` buckets
+  # allows for different index configurations, and can be necessary when a dataset is too large to fit in one dataset given
+  # Elasticsearch/OpenSearch limitations on the number of shards in one index. In addition, ElasticGraph optimizes queries which
+  # filter on the timestamp field to target the subset of the indices in which matching documents could reside.
+  #
+  # @note the timestamp field specified here **must be immutable**. To understand why, consider a `:yearly` rollover
+  #   index used for data based on `createdAt`; if ElasticGraph ingests record `123` with a createdAt of `2023-12-31T23:59:59Z`, it
+  #   will be indexed in the `2023` index. Later if it receives an update event for record `123` with a `createdAt` of
+  #   `2024-01-01T00:00:00Z` (a mere one second later!), ElasticGraph will store the new version of the payment in the `2024` index,
+  #   and leave the old copy of the payment in the `2023` index unchanged. It’ll have duplicates for that document.
+  # @note changing the `rollover` configuration on an existing index that already has data will result in duplicate documents
+  #
+  # @param frequency [:yearly, :monthly, :daily, :hourly] how often to rollover the index
+  # @param timestamp_field_path_name [String] dot-separated path to the timestamp field used for rollover. Note: all referenced
+  #   fields must exist when this is called.
+  # @return [void]
+  #
+  # @example Define a `campaigns` index to rollover yearly based on `createdAt`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "createdAt", "DateTime"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.rollover :yearly, "createdAt"
+  #       end
+  #     end
+  #   end
+  def rollover(frequency, timestamp_field_path_name)
+    timestamp_field_path = public_field_path(timestamp_field_path_name, explanation: "it is referenced as an index `rollover` field")
+
+    unless date_and_datetime_types.include?(timestamp_field_path.type.fully_unwrapped.name)
+      date_or_datetime_description = date_and_datetime_types.map { |t| "`#{t}`" }.join(" or ")
+      raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is not a #{date_or_datetime_description} field."
+    end
+
+    if timestamp_field_path.type.list?
+      raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is a list field."
+    end
+
+    timestamp_field_path.path_parts.each { |f| f.json_schema nullable: false }
+
+    self.rollover_config = RolloverConfig.new(
+      frequency: frequency,
+      timestamp_field_path: timestamp_field_path
+    )
+  end
+
+  # Configures the index to [route documents to shards](https://www.elastic.co/guide/en/elasticsearch/reference/8.15/mapping-routing-field.html)
+  # based on the specified field. ElasticGraph optimizes queries that filter on the shard routing field so that they only run on a
+  # subset of nodes instead of all nodes. This can make a big difference in query performance if queries usually filter on a certain
+  # field. Using an appropriate field for shard routing is often essential for horizontal scaling, as it avoids having every query
+  # hit every node, allowing additional nodes to increase query throughput.
+  #
+  # @note it is essential that the shards are well-balanced. If the data’s distribution is lopsided, using this feature can make
+  #   performance worse.
+  # @note the routing field specified here **must be immutable**. If ElasticGraph receives an updated version of a document with a
+  #   different routing value, it’ll write the new version of the document to a different shard and leave the copy on the old shard
+  #   unchanged, leading to duplicates.
+  # @note changing the shard routing configuration on an existing index that already has data will result in duplicate documents
+  #
+  # @param routing_field_path_name [String] dot-separated path to the field used for shard routing. Note: all referenced
+  #   fields must exist when this is called.
+  # @return [void]
+  #
+  # @example Define a `campaigns` index to shard on `organizationId`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "organizationId", "ID"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.route_with "organizationId"
+  #       end
+  #     end
+  #   end
+  def route_with(routing_field_path_name)
+    routing_field_path = public_field_path(routing_field_path_name, explanation: "it is referenced as an index `route_with` field")
+
+    unless routing_field_path.type.leaf?
+      raise Errors::SchemaError, "shard routing field `#{routing_field_path.full_description}` cannot be used for routing since it is not a leaf field."
+    end
+
+    self.routing_field_path = routing_field_path
+
+    routing_field_path.path_parts[0..-2].each { |f| f.json_schema nullable: false }
+    routing_field_path.last_part.json_schema nullable: false, pattern: HAS_NON_WHITE_SPACE_REGEX
+    indexed_type.append_to_documentation "For more performant queries on this type, please filter on `#{routing_field_path_name}` if possible."
+  end
+
+  # @see #route_with
+  # @return [Boolean] whether or not this index uses custom shard routing
+  def uses_custom_routing?
+    routing_field_path.path_in_index != "id"
+  end
+
+  # @return [Hash<String, Object>] datastore configuration for this index for when it does not use rollover
+  def to_index_config
+    {
+      "aliases" => {},
+      "mappings" => mappings,
+      "settings" => settings
+    }.compact
+  end
+
+  # @return [Hash<String, Object>] datastore configuration for the index template that will be defined if rollover is used
+  def to_index_template_config
+    {
+      "index_patterns" => ["#{name}#{ROLLOVER_INDEX_INFIX_MARKER}*"],
+      "template" => {
+        "aliases" => {},
+        "mappings" => mappings,
+        "settings" => settings
+      }
+    }
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::IndexDefinition] runtime metadata for this index
+  def 
+    SchemaArtifacts::RuntimeMetadata::IndexDefinition.new(
+      route_with: routing_field_path.path_in_index,
+      rollover: rollover_config&.,
+      current_sources: indexed_type.current_sources,
+      fields_by_path: indexed_type..to_h,
+      default_sort_fields: default_sort_pairs.each_slice(2).map do |(graphql_field_path_name, direction)|
+        SchemaArtifacts::RuntimeMetadata::SortField.new(
+          field_path: public_field_path(graphql_field_path_name, explanation: "it is referenced as an index `default_sort` field").path_in_index,
+          direction: direction
+        )
+      end
+    )
+  end
+
+  private
+
+  # A regex that requires at least one non-whitespace character.
+  # Note: this does not use the `/S` character class because it's recommended to use a small subset
+  # of Regex syntax:
+  #
+  # > The regular expression syntax used is from JavaScript (ECMA 262, specifically). However, that
+  # > complete syntax is not widely supported, therefore it is recommended that you stick to the subset
+  # > of that syntax described below.
+  #
+  # (From https://json-schema.org/understanding-json-schema/reference/regular_expressions.html)
+  HAS_NON_WHITE_SPACE_REGEX = "[^ \t\n]+"
+
+  DEFAULT_SETTINGS = {
+    "index.mapping.ignore_malformed" => false,
+    "index.mapping.coerce" => false,
+    "index.number_of_replicas" => 1,
+    "index.number_of_shards" => 1
+  }
+
+  def mappings
+    field_mappings = indexed_type
+      .to_indexing_field_type
+      .to_mapping
+      .except("type") # `type` is invalid at the mapping root because it always has to be an object.
+      .then { |mapping| ListCountsMapping.merged_into(mapping, for_type: indexed_type) }
+      .then do |fm|
+        Support::HashUtil.deep_merge(fm, {"properties" => {
+          "__sources" => {"type" => "keyword"},
+          "__versions" => {
+            "type" => "object",
+            # __versions is map keyed by relationship name, with values that are maps keyed by id. Since it's not
+            # a static object with known fields, we need to use dynamic here. Passing `false` allows some level
+            # of dynamicness. As per https://www.elastic.co/guide/en/elasticsearch/reference/8.7/dynamic.html#dynamic-parameters:
+            #
+            # > New fields are ignored. These fields will not be indexed or searchable, but will still appear in the _source
+            # > field of returned hits. These fields will not be added to the mapping, and new fields must be added explicitly.
+            #
+            # We need `__versions` to be in `_source` (so that our update scripts can operate on it), but
+            # have no need for it to be searchable (as it's just an internal data structure used for indexing).
+            #
+            # Note: we intentionally set false as a string here, because that's how the datastore echoes it back
+            # to us when you query the mapping (even if you set it as a boolean). Our checks for index mapping
+            # consistency fail validation if we set it as a boolean since the datastore doesn't echo it back as
+            # a boolean.
+            "dynamic" => "false"
+          }
+        }})
+      end
+
+    {"dynamic" => "strict"}.merge(field_mappings).tap do |hash|
+      # If we are using custom shard routing, we want to require a `routing` value to be provided
+      # in every single index, get, delete or update request; otherwise the request might be
+      # made against the wrong shard.
+      hash["_routing"] = {"required" => true} if uses_custom_routing?
+      hash["_size"] = {"enabled" => true} if schema_def_state.index_document_sizes?
+    end
+  end
+
+  def public_field_path(public_path_string, explanation:)
+    parent_is_not_list = ->(parent_field) { !parent_field.type.list? }
+    resolver = SchemaElements::FieldPath::Resolver.new
+    resolved_path = resolver.resolve_public_path(indexed_type, public_path_string, &parent_is_not_list)
+    return resolved_path if resolved_path
+
+    path_parts = public_path_string.split(".")
+    error_msg = "Field `#{indexed_type.name}.#{public_path_string}` cannot be resolved, but #{explanation}."
+
+    # If it is a nested field path, the problem could be that a type has been referenced which does not exist, so mention that.
+    if path_parts.size > 1
+      error_msg += " Verify that all fields and types referenced by `#{public_path_string}` are defined."
+    end
+
+    # If the first part of the path doesn't resolve, the problem could be that the field is defined after the `index` call
+    # but it needs to be defined before it, so mention that.
+    if resolver.resolve_public_path(indexed_type, path_parts.first, &parent_is_not_list).nil?
+      error_msg += " Note: the `#{indexed_type.name}.#{path_parts.first}` definition must come before the `index` call."
+    end
+
+    raise Errors::SchemaError, error_msg
+  end
+
+  def date_and_datetime_types
+    @date_and_datetime_types ||= %w[Date DateTime].map do |type|
+      schema_def_state.type_namer.name_for(type)
+    end
+  end
+end
+
+
+ + + +
+

+ + #nameString (readonly) + + + + + +

+
+

Returns name of the index.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    name of the index

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 39
+
+class Index < Struct.new(:name, :default_sort_pairs, :settings, :schema_def_state, :indexed_type, :routing_field_path, :rollover_config)
+  include Mixins::HasReadableToSAndInspect.new { |i| i.name }
+
+  # @param name [String] name of the index
+  # @param settings [Hash<(String, Object)>] datastore settings for the index
+  # @param schema_def_state [State] schema definition state
+  # @param indexed_type [SchemaElements::ObjectType, SchemaElements::InterfaceType, SchemaElements::UnionType] type backed by this index
+  # @yield [Index] the index, for further customization
+  # @api private
+  def initialize(name, settings, schema_def_state, indexed_type)
+    if name.include?(ROLLOVER_INDEX_INFIX_MARKER)
+      raise Errors::SchemaError, "`#{name}` is an invalid index definition name since it contains " \
+        "`#{ROLLOVER_INDEX_INFIX_MARKER}` which ElasticGraph treats as special."
+    end
+
+    settings = DEFAULT_SETTINGS.merge(Support::HashUtil.flatten_and_stringify_keys(settings, prefix: "index"))
+
+    super(name, [], settings, schema_def_state, indexed_type, [], nil)
+
+    # `id` is the field Elasticsearch/OpenSearch use for routing by default:
+    # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-routing-field.html
+    # By using it here, it will cause queries to pass a `routing` parameter when
+    # searching with id filtering on an index that does not use custom shard routing, giving
+    # us a nice efficiency boost.
+    self.routing_field_path = public_field_path("id", explanation: "indexed types must have an `id` field")
+
+    yield self if block_given?
+  end
+
+  # Specifies how documents in this index should sort by default, when no `orderBy` argument is provided to the GraphQL query.
+  #
+  # @note the field name strings can be a dot-separated nested fields, but all referenced
+  #   fields must exist when this is called.
+  #
+  # @param field_name_direction_pairs [Array<(String, Symbol)>] pairs of field names and `:asc` or `:desc`
+  # @return [void]
+  #
+  # @example Sort on `name` (ascending) with `createdAt` (descending) as a tie-breaker
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "createdAt", "DateTime"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.default_sort "name", :asc, "createdAt", :desc
+  #       end
+  #     end
+  #   end
+  def default_sort(*field_name_direction_pairs)
+    self.default_sort_pairs = field_name_direction_pairs
+  end
+
+  # Causes this index to "rollover" at the provided `frequency` based on the value of the provided `timestamp_field_path_name`.
+  # This is particularly useful for time-series data. Partitioning the data into `hourly`, `daily`, `monthly` or `yearly` buckets
+  # allows for different index configurations, and can be necessary when a dataset is too large to fit in one dataset given
+  # Elasticsearch/OpenSearch limitations on the number of shards in one index. In addition, ElasticGraph optimizes queries which
+  # filter on the timestamp field to target the subset of the indices in which matching documents could reside.
+  #
+  # @note the timestamp field specified here **must be immutable**. To understand why, consider a `:yearly` rollover
+  #   index used for data based on `createdAt`; if ElasticGraph ingests record `123` with a createdAt of `2023-12-31T23:59:59Z`, it
+  #   will be indexed in the `2023` index. Later if it receives an update event for record `123` with a `createdAt` of
+  #   `2024-01-01T00:00:00Z` (a mere one second later!), ElasticGraph will store the new version of the payment in the `2024` index,
+  #   and leave the old copy of the payment in the `2023` index unchanged. It’ll have duplicates for that document.
+  # @note changing the `rollover` configuration on an existing index that already has data will result in duplicate documents
+  #
+  # @param frequency [:yearly, :monthly, :daily, :hourly] how often to rollover the index
+  # @param timestamp_field_path_name [String] dot-separated path to the timestamp field used for rollover. Note: all referenced
+  #   fields must exist when this is called.
+  # @return [void]
+  #
+  # @example Define a `campaigns` index to rollover yearly based on `createdAt`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "createdAt", "DateTime"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.rollover :yearly, "createdAt"
+  #       end
+  #     end
+  #   end
+  def rollover(frequency, timestamp_field_path_name)
+    timestamp_field_path = public_field_path(timestamp_field_path_name, explanation: "it is referenced as an index `rollover` field")
+
+    unless date_and_datetime_types.include?(timestamp_field_path.type.fully_unwrapped.name)
+      date_or_datetime_description = date_and_datetime_types.map { |t| "`#{t}`" }.join(" or ")
+      raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is not a #{date_or_datetime_description} field."
+    end
+
+    if timestamp_field_path.type.list?
+      raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is a list field."
+    end
+
+    timestamp_field_path.path_parts.each { |f| f.json_schema nullable: false }
+
+    self.rollover_config = RolloverConfig.new(
+      frequency: frequency,
+      timestamp_field_path: timestamp_field_path
+    )
+  end
+
+  # Configures the index to [route documents to shards](https://www.elastic.co/guide/en/elasticsearch/reference/8.15/mapping-routing-field.html)
+  # based on the specified field. ElasticGraph optimizes queries that filter on the shard routing field so that they only run on a
+  # subset of nodes instead of all nodes. This can make a big difference in query performance if queries usually filter on a certain
+  # field. Using an appropriate field for shard routing is often essential for horizontal scaling, as it avoids having every query
+  # hit every node, allowing additional nodes to increase query throughput.
+  #
+  # @note it is essential that the shards are well-balanced. If the data’s distribution is lopsided, using this feature can make
+  #   performance worse.
+  # @note the routing field specified here **must be immutable**. If ElasticGraph receives an updated version of a document with a
+  #   different routing value, it’ll write the new version of the document to a different shard and leave the copy on the old shard
+  #   unchanged, leading to duplicates.
+  # @note changing the shard routing configuration on an existing index that already has data will result in duplicate documents
+  #
+  # @param routing_field_path_name [String] dot-separated path to the field used for shard routing. Note: all referenced
+  #   fields must exist when this is called.
+  # @return [void]
+  #
+  # @example Define a `campaigns` index to shard on `organizationId`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "organizationId", "ID"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.route_with "organizationId"
+  #       end
+  #     end
+  #   end
+  def route_with(routing_field_path_name)
+    routing_field_path = public_field_path(routing_field_path_name, explanation: "it is referenced as an index `route_with` field")
+
+    unless routing_field_path.type.leaf?
+      raise Errors::SchemaError, "shard routing field `#{routing_field_path.full_description}` cannot be used for routing since it is not a leaf field."
+    end
+
+    self.routing_field_path = routing_field_path
+
+    routing_field_path.path_parts[0..-2].each { |f| f.json_schema nullable: false }
+    routing_field_path.last_part.json_schema nullable: false, pattern: HAS_NON_WHITE_SPACE_REGEX
+    indexed_type.append_to_documentation "For more performant queries on this type, please filter on `#{routing_field_path_name}` if possible."
+  end
+
+  # @see #route_with
+  # @return [Boolean] whether or not this index uses custom shard routing
+  def uses_custom_routing?
+    routing_field_path.path_in_index != "id"
+  end
+
+  # @return [Hash<String, Object>] datastore configuration for this index for when it does not use rollover
+  def to_index_config
+    {
+      "aliases" => {},
+      "mappings" => mappings,
+      "settings" => settings
+    }.compact
+  end
+
+  # @return [Hash<String, Object>] datastore configuration for the index template that will be defined if rollover is used
+  def to_index_template_config
+    {
+      "index_patterns" => ["#{name}#{ROLLOVER_INDEX_INFIX_MARKER}*"],
+      "template" => {
+        "aliases" => {},
+        "mappings" => mappings,
+        "settings" => settings
+      }
+    }
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::IndexDefinition] runtime metadata for this index
+  def 
+    SchemaArtifacts::RuntimeMetadata::IndexDefinition.new(
+      route_with: routing_field_path.path_in_index,
+      rollover: rollover_config&.,
+      current_sources: indexed_type.current_sources,
+      fields_by_path: indexed_type..to_h,
+      default_sort_fields: default_sort_pairs.each_slice(2).map do |(graphql_field_path_name, direction)|
+        SchemaArtifacts::RuntimeMetadata::SortField.new(
+          field_path: public_field_path(graphql_field_path_name, explanation: "it is referenced as an index `default_sort` field").path_in_index,
+          direction: direction
+        )
+      end
+    )
+  end
+
+  private
+
+  # A regex that requires at least one non-whitespace character.
+  # Note: this does not use the `/S` character class because it's recommended to use a small subset
+  # of Regex syntax:
+  #
+  # > The regular expression syntax used is from JavaScript (ECMA 262, specifically). However, that
+  # > complete syntax is not widely supported, therefore it is recommended that you stick to the subset
+  # > of that syntax described below.
+  #
+  # (From https://json-schema.org/understanding-json-schema/reference/regular_expressions.html)
+  HAS_NON_WHITE_SPACE_REGEX = "[^ \t\n]+"
+
+  DEFAULT_SETTINGS = {
+    "index.mapping.ignore_malformed" => false,
+    "index.mapping.coerce" => false,
+    "index.number_of_replicas" => 1,
+    "index.number_of_shards" => 1
+  }
+
+  def mappings
+    field_mappings = indexed_type
+      .to_indexing_field_type
+      .to_mapping
+      .except("type") # `type` is invalid at the mapping root because it always has to be an object.
+      .then { |mapping| ListCountsMapping.merged_into(mapping, for_type: indexed_type) }
+      .then do |fm|
+        Support::HashUtil.deep_merge(fm, {"properties" => {
+          "__sources" => {"type" => "keyword"},
+          "__versions" => {
+            "type" => "object",
+            # __versions is map keyed by relationship name, with values that are maps keyed by id. Since it's not
+            # a static object with known fields, we need to use dynamic here. Passing `false` allows some level
+            # of dynamicness. As per https://www.elastic.co/guide/en/elasticsearch/reference/8.7/dynamic.html#dynamic-parameters:
+            #
+            # > New fields are ignored. These fields will not be indexed or searchable, but will still appear in the _source
+            # > field of returned hits. These fields will not be added to the mapping, and new fields must be added explicitly.
+            #
+            # We need `__versions` to be in `_source` (so that our update scripts can operate on it), but
+            # have no need for it to be searchable (as it's just an internal data structure used for indexing).
+            #
+            # Note: we intentionally set false as a string here, because that's how the datastore echoes it back
+            # to us when you query the mapping (even if you set it as a boolean). Our checks for index mapping
+            # consistency fail validation if we set it as a boolean since the datastore doesn't echo it back as
+            # a boolean.
+            "dynamic" => "false"
+          }
+        }})
+      end
+
+    {"dynamic" => "strict"}.merge(field_mappings).tap do |hash|
+      # If we are using custom shard routing, we want to require a `routing` value to be provided
+      # in every single index, get, delete or update request; otherwise the request might be
+      # made against the wrong shard.
+      hash["_routing"] = {"required" => true} if uses_custom_routing?
+      hash["_size"] = {"enabled" => true} if schema_def_state.index_document_sizes?
+    end
+  end
+
+  def public_field_path(public_path_string, explanation:)
+    parent_is_not_list = ->(parent_field) { !parent_field.type.list? }
+    resolver = SchemaElements::FieldPath::Resolver.new
+    resolved_path = resolver.resolve_public_path(indexed_type, public_path_string, &parent_is_not_list)
+    return resolved_path if resolved_path
+
+    path_parts = public_path_string.split(".")
+    error_msg = "Field `#{indexed_type.name}.#{public_path_string}` cannot be resolved, but #{explanation}."
+
+    # If it is a nested field path, the problem could be that a type has been referenced which does not exist, so mention that.
+    if path_parts.size > 1
+      error_msg += " Verify that all fields and types referenced by `#{public_path_string}` are defined."
+    end
+
+    # If the first part of the path doesn't resolve, the problem could be that the field is defined after the `index` call
+    # but it needs to be defined before it, so mention that.
+    if resolver.resolve_public_path(indexed_type, path_parts.first, &parent_is_not_list).nil?
+      error_msg += " Note: the `#{indexed_type.name}.#{path_parts.first}` definition must come before the `index` call."
+    end
+
+    raise Errors::SchemaError, error_msg
+  end
+
+  def date_and_datetime_types
+    @date_and_datetime_types ||= %w[Date DateTime].map do |type|
+      schema_def_state.type_namer.name_for(type)
+    end
+  end
+end
+
+
+ + + +
+

+ + #rollover_configRolloverConfig? (readonly) + + + + + +

+
+

Returns rollover configuration for the index.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (RolloverConfig, nil) + + + + — +

    rollover configuration for the index

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 39
+
+class Index < Struct.new(:name, :default_sort_pairs, :settings, :schema_def_state, :indexed_type, :routing_field_path, :rollover_config)
+  include Mixins::HasReadableToSAndInspect.new { |i| i.name }
+
+  # @param name [String] name of the index
+  # @param settings [Hash<(String, Object)>] datastore settings for the index
+  # @param schema_def_state [State] schema definition state
+  # @param indexed_type [SchemaElements::ObjectType, SchemaElements::InterfaceType, SchemaElements::UnionType] type backed by this index
+  # @yield [Index] the index, for further customization
+  # @api private
+  def initialize(name, settings, schema_def_state, indexed_type)
+    if name.include?(ROLLOVER_INDEX_INFIX_MARKER)
+      raise Errors::SchemaError, "`#{name}` is an invalid index definition name since it contains " \
+        "`#{ROLLOVER_INDEX_INFIX_MARKER}` which ElasticGraph treats as special."
+    end
+
+    settings = DEFAULT_SETTINGS.merge(Support::HashUtil.flatten_and_stringify_keys(settings, prefix: "index"))
+
+    super(name, [], settings, schema_def_state, indexed_type, [], nil)
+
+    # `id` is the field Elasticsearch/OpenSearch use for routing by default:
+    # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-routing-field.html
+    # By using it here, it will cause queries to pass a `routing` parameter when
+    # searching with id filtering on an index that does not use custom shard routing, giving
+    # us a nice efficiency boost.
+    self.routing_field_path = public_field_path("id", explanation: "indexed types must have an `id` field")
+
+    yield self if block_given?
+  end
+
+  # Specifies how documents in this index should sort by default, when no `orderBy` argument is provided to the GraphQL query.
+  #
+  # @note the field name strings can be a dot-separated nested fields, but all referenced
+  #   fields must exist when this is called.
+  #
+  # @param field_name_direction_pairs [Array<(String, Symbol)>] pairs of field names and `:asc` or `:desc`
+  # @return [void]
+  #
+  # @example Sort on `name` (ascending) with `createdAt` (descending) as a tie-breaker
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "createdAt", "DateTime"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.default_sort "name", :asc, "createdAt", :desc
+  #       end
+  #     end
+  #   end
+  def default_sort(*field_name_direction_pairs)
+    self.default_sort_pairs = field_name_direction_pairs
+  end
+
+  # Causes this index to "rollover" at the provided `frequency` based on the value of the provided `timestamp_field_path_name`.
+  # This is particularly useful for time-series data. Partitioning the data into `hourly`, `daily`, `monthly` or `yearly` buckets
+  # allows for different index configurations, and can be necessary when a dataset is too large to fit in one dataset given
+  # Elasticsearch/OpenSearch limitations on the number of shards in one index. In addition, ElasticGraph optimizes queries which
+  # filter on the timestamp field to target the subset of the indices in which matching documents could reside.
+  #
+  # @note the timestamp field specified here **must be immutable**. To understand why, consider a `:yearly` rollover
+  #   index used for data based on `createdAt`; if ElasticGraph ingests record `123` with a createdAt of `2023-12-31T23:59:59Z`, it
+  #   will be indexed in the `2023` index. Later if it receives an update event for record `123` with a `createdAt` of
+  #   `2024-01-01T00:00:00Z` (a mere one second later!), ElasticGraph will store the new version of the payment in the `2024` index,
+  #   and leave the old copy of the payment in the `2023` index unchanged. It’ll have duplicates for that document.
+  # @note changing the `rollover` configuration on an existing index that already has data will result in duplicate documents
+  #
+  # @param frequency [:yearly, :monthly, :daily, :hourly] how often to rollover the index
+  # @param timestamp_field_path_name [String] dot-separated path to the timestamp field used for rollover. Note: all referenced
+  #   fields must exist when this is called.
+  # @return [void]
+  #
+  # @example Define a `campaigns` index to rollover yearly based on `createdAt`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "createdAt", "DateTime"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.rollover :yearly, "createdAt"
+  #       end
+  #     end
+  #   end
+  def rollover(frequency, timestamp_field_path_name)
+    timestamp_field_path = public_field_path(timestamp_field_path_name, explanation: "it is referenced as an index `rollover` field")
+
+    unless date_and_datetime_types.include?(timestamp_field_path.type.fully_unwrapped.name)
+      date_or_datetime_description = date_and_datetime_types.map { |t| "`#{t}`" }.join(" or ")
+      raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is not a #{date_or_datetime_description} field."
+    end
+
+    if timestamp_field_path.type.list?
+      raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is a list field."
+    end
+
+    timestamp_field_path.path_parts.each { |f| f.json_schema nullable: false }
+
+    self.rollover_config = RolloverConfig.new(
+      frequency: frequency,
+      timestamp_field_path: timestamp_field_path
+    )
+  end
+
+  # Configures the index to [route documents to shards](https://www.elastic.co/guide/en/elasticsearch/reference/8.15/mapping-routing-field.html)
+  # based on the specified field. ElasticGraph optimizes queries that filter on the shard routing field so that they only run on a
+  # subset of nodes instead of all nodes. This can make a big difference in query performance if queries usually filter on a certain
+  # field. Using an appropriate field for shard routing is often essential for horizontal scaling, as it avoids having every query
+  # hit every node, allowing additional nodes to increase query throughput.
+  #
+  # @note it is essential that the shards are well-balanced. If the data’s distribution is lopsided, using this feature can make
+  #   performance worse.
+  # @note the routing field specified here **must be immutable**. If ElasticGraph receives an updated version of a document with a
+  #   different routing value, it’ll write the new version of the document to a different shard and leave the copy on the old shard
+  #   unchanged, leading to duplicates.
+  # @note changing the shard routing configuration on an existing index that already has data will result in duplicate documents
+  #
+  # @param routing_field_path_name [String] dot-separated path to the field used for shard routing. Note: all referenced
+  #   fields must exist when this is called.
+  # @return [void]
+  #
+  # @example Define a `campaigns` index to shard on `organizationId`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "organizationId", "ID"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.route_with "organizationId"
+  #       end
+  #     end
+  #   end
+  def route_with(routing_field_path_name)
+    routing_field_path = public_field_path(routing_field_path_name, explanation: "it is referenced as an index `route_with` field")
+
+    unless routing_field_path.type.leaf?
+      raise Errors::SchemaError, "shard routing field `#{routing_field_path.full_description}` cannot be used for routing since it is not a leaf field."
+    end
+
+    self.routing_field_path = routing_field_path
+
+    routing_field_path.path_parts[0..-2].each { |f| f.json_schema nullable: false }
+    routing_field_path.last_part.json_schema nullable: false, pattern: HAS_NON_WHITE_SPACE_REGEX
+    indexed_type.append_to_documentation "For more performant queries on this type, please filter on `#{routing_field_path_name}` if possible."
+  end
+
+  # @see #route_with
+  # @return [Boolean] whether or not this index uses custom shard routing
+  def uses_custom_routing?
+    routing_field_path.path_in_index != "id"
+  end
+
+  # @return [Hash<String, Object>] datastore configuration for this index for when it does not use rollover
+  def to_index_config
+    {
+      "aliases" => {},
+      "mappings" => mappings,
+      "settings" => settings
+    }.compact
+  end
+
+  # @return [Hash<String, Object>] datastore configuration for the index template that will be defined if rollover is used
+  def to_index_template_config
+    {
+      "index_patterns" => ["#{name}#{ROLLOVER_INDEX_INFIX_MARKER}*"],
+      "template" => {
+        "aliases" => {},
+        "mappings" => mappings,
+        "settings" => settings
+      }
+    }
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::IndexDefinition] runtime metadata for this index
+  def 
+    SchemaArtifacts::RuntimeMetadata::IndexDefinition.new(
+      route_with: routing_field_path.path_in_index,
+      rollover: rollover_config&.,
+      current_sources: indexed_type.current_sources,
+      fields_by_path: indexed_type..to_h,
+      default_sort_fields: default_sort_pairs.each_slice(2).map do |(graphql_field_path_name, direction)|
+        SchemaArtifacts::RuntimeMetadata::SortField.new(
+          field_path: public_field_path(graphql_field_path_name, explanation: "it is referenced as an index `default_sort` field").path_in_index,
+          direction: direction
+        )
+      end
+    )
+  end
+
+  private
+
+  # A regex that requires at least one non-whitespace character.
+  # Note: this does not use the `/S` character class because it's recommended to use a small subset
+  # of Regex syntax:
+  #
+  # > The regular expression syntax used is from JavaScript (ECMA 262, specifically). However, that
+  # > complete syntax is not widely supported, therefore it is recommended that you stick to the subset
+  # > of that syntax described below.
+  #
+  # (From https://json-schema.org/understanding-json-schema/reference/regular_expressions.html)
+  HAS_NON_WHITE_SPACE_REGEX = "[^ \t\n]+"
+
+  DEFAULT_SETTINGS = {
+    "index.mapping.ignore_malformed" => false,
+    "index.mapping.coerce" => false,
+    "index.number_of_replicas" => 1,
+    "index.number_of_shards" => 1
+  }
+
+  def mappings
+    field_mappings = indexed_type
+      .to_indexing_field_type
+      .to_mapping
+      .except("type") # `type` is invalid at the mapping root because it always has to be an object.
+      .then { |mapping| ListCountsMapping.merged_into(mapping, for_type: indexed_type) }
+      .then do |fm|
+        Support::HashUtil.deep_merge(fm, {"properties" => {
+          "__sources" => {"type" => "keyword"},
+          "__versions" => {
+            "type" => "object",
+            # __versions is map keyed by relationship name, with values that are maps keyed by id. Since it's not
+            # a static object with known fields, we need to use dynamic here. Passing `false` allows some level
+            # of dynamicness. As per https://www.elastic.co/guide/en/elasticsearch/reference/8.7/dynamic.html#dynamic-parameters:
+            #
+            # > New fields are ignored. These fields will not be indexed or searchable, but will still appear in the _source
+            # > field of returned hits. These fields will not be added to the mapping, and new fields must be added explicitly.
+            #
+            # We need `__versions` to be in `_source` (so that our update scripts can operate on it), but
+            # have no need for it to be searchable (as it's just an internal data structure used for indexing).
+            #
+            # Note: we intentionally set false as a string here, because that's how the datastore echoes it back
+            # to us when you query the mapping (even if you set it as a boolean). Our checks for index mapping
+            # consistency fail validation if we set it as a boolean since the datastore doesn't echo it back as
+            # a boolean.
+            "dynamic" => "false"
+          }
+        }})
+      end
+
+    {"dynamic" => "strict"}.merge(field_mappings).tap do |hash|
+      # If we are using custom shard routing, we want to require a `routing` value to be provided
+      # in every single index, get, delete or update request; otherwise the request might be
+      # made against the wrong shard.
+      hash["_routing"] = {"required" => true} if uses_custom_routing?
+      hash["_size"] = {"enabled" => true} if schema_def_state.index_document_sizes?
+    end
+  end
+
+  def public_field_path(public_path_string, explanation:)
+    parent_is_not_list = ->(parent_field) { !parent_field.type.list? }
+    resolver = SchemaElements::FieldPath::Resolver.new
+    resolved_path = resolver.resolve_public_path(indexed_type, public_path_string, &parent_is_not_list)
+    return resolved_path if resolved_path
+
+    path_parts = public_path_string.split(".")
+    error_msg = "Field `#{indexed_type.name}.#{public_path_string}` cannot be resolved, but #{explanation}."
+
+    # If it is a nested field path, the problem could be that a type has been referenced which does not exist, so mention that.
+    if path_parts.size > 1
+      error_msg += " Verify that all fields and types referenced by `#{public_path_string}` are defined."
+    end
+
+    # If the first part of the path doesn't resolve, the problem could be that the field is defined after the `index` call
+    # but it needs to be defined before it, so mention that.
+    if resolver.resolve_public_path(indexed_type, path_parts.first, &parent_is_not_list).nil?
+      error_msg += " Note: the `#{indexed_type.name}.#{path_parts.first}` definition must come before the `index` call."
+    end
+
+    raise Errors::SchemaError, error_msg
+  end
+
+  def date_and_datetime_types
+    @date_and_datetime_types ||= %w[Date DateTime].map do |type|
+      schema_def_state.type_namer.name_for(type)
+    end
+  end
+end
+
+
+ + + +
+

+ + #routing_field_pathArray<String> (readonly) + + + + + +

+
+

Returns path to the field used for shard routing.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Array<String>) + + + + — +

    path to the field used for shard routing

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 39
+
+class Index < Struct.new(:name, :default_sort_pairs, :settings, :schema_def_state, :indexed_type, :routing_field_path, :rollover_config)
+  include Mixins::HasReadableToSAndInspect.new { |i| i.name }
+
+  # @param name [String] name of the index
+  # @param settings [Hash<(String, Object)>] datastore settings for the index
+  # @param schema_def_state [State] schema definition state
+  # @param indexed_type [SchemaElements::ObjectType, SchemaElements::InterfaceType, SchemaElements::UnionType] type backed by this index
+  # @yield [Index] the index, for further customization
+  # @api private
+  def initialize(name, settings, schema_def_state, indexed_type)
+    if name.include?(ROLLOVER_INDEX_INFIX_MARKER)
+      raise Errors::SchemaError, "`#{name}` is an invalid index definition name since it contains " \
+        "`#{ROLLOVER_INDEX_INFIX_MARKER}` which ElasticGraph treats as special."
+    end
+
+    settings = DEFAULT_SETTINGS.merge(Support::HashUtil.flatten_and_stringify_keys(settings, prefix: "index"))
+
+    super(name, [], settings, schema_def_state, indexed_type, [], nil)
+
+    # `id` is the field Elasticsearch/OpenSearch use for routing by default:
+    # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-routing-field.html
+    # By using it here, it will cause queries to pass a `routing` parameter when
+    # searching with id filtering on an index that does not use custom shard routing, giving
+    # us a nice efficiency boost.
+    self.routing_field_path = public_field_path("id", explanation: "indexed types must have an `id` field")
+
+    yield self if block_given?
+  end
+
+  # Specifies how documents in this index should sort by default, when no `orderBy` argument is provided to the GraphQL query.
+  #
+  # @note the field name strings can be a dot-separated nested fields, but all referenced
+  #   fields must exist when this is called.
+  #
+  # @param field_name_direction_pairs [Array<(String, Symbol)>] pairs of field names and `:asc` or `:desc`
+  # @return [void]
+  #
+  # @example Sort on `name` (ascending) with `createdAt` (descending) as a tie-breaker
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "createdAt", "DateTime"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.default_sort "name", :asc, "createdAt", :desc
+  #       end
+  #     end
+  #   end
+  def default_sort(*field_name_direction_pairs)
+    self.default_sort_pairs = field_name_direction_pairs
+  end
+
+  # Causes this index to "rollover" at the provided `frequency` based on the value of the provided `timestamp_field_path_name`.
+  # This is particularly useful for time-series data. Partitioning the data into `hourly`, `daily`, `monthly` or `yearly` buckets
+  # allows for different index configurations, and can be necessary when a dataset is too large to fit in one dataset given
+  # Elasticsearch/OpenSearch limitations on the number of shards in one index. In addition, ElasticGraph optimizes queries which
+  # filter on the timestamp field to target the subset of the indices in which matching documents could reside.
+  #
+  # @note the timestamp field specified here **must be immutable**. To understand why, consider a `:yearly` rollover
+  #   index used for data based on `createdAt`; if ElasticGraph ingests record `123` with a createdAt of `2023-12-31T23:59:59Z`, it
+  #   will be indexed in the `2023` index. Later if it receives an update event for record `123` with a `createdAt` of
+  #   `2024-01-01T00:00:00Z` (a mere one second later!), ElasticGraph will store the new version of the payment in the `2024` index,
+  #   and leave the old copy of the payment in the `2023` index unchanged. It’ll have duplicates for that document.
+  # @note changing the `rollover` configuration on an existing index that already has data will result in duplicate documents
+  #
+  # @param frequency [:yearly, :monthly, :daily, :hourly] how often to rollover the index
+  # @param timestamp_field_path_name [String] dot-separated path to the timestamp field used for rollover. Note: all referenced
+  #   fields must exist when this is called.
+  # @return [void]
+  #
+  # @example Define a `campaigns` index to rollover yearly based on `createdAt`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "createdAt", "DateTime"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.rollover :yearly, "createdAt"
+  #       end
+  #     end
+  #   end
+  def rollover(frequency, timestamp_field_path_name)
+    timestamp_field_path = public_field_path(timestamp_field_path_name, explanation: "it is referenced as an index `rollover` field")
+
+    unless date_and_datetime_types.include?(timestamp_field_path.type.fully_unwrapped.name)
+      date_or_datetime_description = date_and_datetime_types.map { |t| "`#{t}`" }.join(" or ")
+      raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is not a #{date_or_datetime_description} field."
+    end
+
+    if timestamp_field_path.type.list?
+      raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is a list field."
+    end
+
+    timestamp_field_path.path_parts.each { |f| f.json_schema nullable: false }
+
+    self.rollover_config = RolloverConfig.new(
+      frequency: frequency,
+      timestamp_field_path: timestamp_field_path
+    )
+  end
+
+  # Configures the index to [route documents to shards](https://www.elastic.co/guide/en/elasticsearch/reference/8.15/mapping-routing-field.html)
+  # based on the specified field. ElasticGraph optimizes queries that filter on the shard routing field so that they only run on a
+  # subset of nodes instead of all nodes. This can make a big difference in query performance if queries usually filter on a certain
+  # field. Using an appropriate field for shard routing is often essential for horizontal scaling, as it avoids having every query
+  # hit every node, allowing additional nodes to increase query throughput.
+  #
+  # @note it is essential that the shards are well-balanced. If the data’s distribution is lopsided, using this feature can make
+  #   performance worse.
+  # @note the routing field specified here **must be immutable**. If ElasticGraph receives an updated version of a document with a
+  #   different routing value, it’ll write the new version of the document to a different shard and leave the copy on the old shard
+  #   unchanged, leading to duplicates.
+  # @note changing the shard routing configuration on an existing index that already has data will result in duplicate documents
+  #
+  # @param routing_field_path_name [String] dot-separated path to the field used for shard routing. Note: all referenced
+  #   fields must exist when this is called.
+  # @return [void]
+  #
+  # @example Define a `campaigns` index to shard on `organizationId`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "organizationId", "ID"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.route_with "organizationId"
+  #       end
+  #     end
+  #   end
+  def route_with(routing_field_path_name)
+    routing_field_path = public_field_path(routing_field_path_name, explanation: "it is referenced as an index `route_with` field")
+
+    unless routing_field_path.type.leaf?
+      raise Errors::SchemaError, "shard routing field `#{routing_field_path.full_description}` cannot be used for routing since it is not a leaf field."
+    end
+
+    self.routing_field_path = routing_field_path
+
+    routing_field_path.path_parts[0..-2].each { |f| f.json_schema nullable: false }
+    routing_field_path.last_part.json_schema nullable: false, pattern: HAS_NON_WHITE_SPACE_REGEX
+    indexed_type.append_to_documentation "For more performant queries on this type, please filter on `#{routing_field_path_name}` if possible."
+  end
+
+  # @see #route_with
+  # @return [Boolean] whether or not this index uses custom shard routing
+  def uses_custom_routing?
+    routing_field_path.path_in_index != "id"
+  end
+
+  # @return [Hash<String, Object>] datastore configuration for this index for when it does not use rollover
+  def to_index_config
+    {
+      "aliases" => {},
+      "mappings" => mappings,
+      "settings" => settings
+    }.compact
+  end
+
+  # @return [Hash<String, Object>] datastore configuration for the index template that will be defined if rollover is used
+  def to_index_template_config
+    {
+      "index_patterns" => ["#{name}#{ROLLOVER_INDEX_INFIX_MARKER}*"],
+      "template" => {
+        "aliases" => {},
+        "mappings" => mappings,
+        "settings" => settings
+      }
+    }
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::IndexDefinition] runtime metadata for this index
+  def 
+    SchemaArtifacts::RuntimeMetadata::IndexDefinition.new(
+      route_with: routing_field_path.path_in_index,
+      rollover: rollover_config&.,
+      current_sources: indexed_type.current_sources,
+      fields_by_path: indexed_type..to_h,
+      default_sort_fields: default_sort_pairs.each_slice(2).map do |(graphql_field_path_name, direction)|
+        SchemaArtifacts::RuntimeMetadata::SortField.new(
+          field_path: public_field_path(graphql_field_path_name, explanation: "it is referenced as an index `default_sort` field").path_in_index,
+          direction: direction
+        )
+      end
+    )
+  end
+
+  private
+
+  # A regex that requires at least one non-whitespace character.
+  # Note: this does not use the `/S` character class because it's recommended to use a small subset
+  # of Regex syntax:
+  #
+  # > The regular expression syntax used is from JavaScript (ECMA 262, specifically). However, that
+  # > complete syntax is not widely supported, therefore it is recommended that you stick to the subset
+  # > of that syntax described below.
+  #
+  # (From https://json-schema.org/understanding-json-schema/reference/regular_expressions.html)
+  HAS_NON_WHITE_SPACE_REGEX = "[^ \t\n]+"
+
+  DEFAULT_SETTINGS = {
+    "index.mapping.ignore_malformed" => false,
+    "index.mapping.coerce" => false,
+    "index.number_of_replicas" => 1,
+    "index.number_of_shards" => 1
+  }
+
+  def mappings
+    field_mappings = indexed_type
+      .to_indexing_field_type
+      .to_mapping
+      .except("type") # `type` is invalid at the mapping root because it always has to be an object.
+      .then { |mapping| ListCountsMapping.merged_into(mapping, for_type: indexed_type) }
+      .then do |fm|
+        Support::HashUtil.deep_merge(fm, {"properties" => {
+          "__sources" => {"type" => "keyword"},
+          "__versions" => {
+            "type" => "object",
+            # __versions is map keyed by relationship name, with values that are maps keyed by id. Since it's not
+            # a static object with known fields, we need to use dynamic here. Passing `false` allows some level
+            # of dynamicness. As per https://www.elastic.co/guide/en/elasticsearch/reference/8.7/dynamic.html#dynamic-parameters:
+            #
+            # > New fields are ignored. These fields will not be indexed or searchable, but will still appear in the _source
+            # > field of returned hits. These fields will not be added to the mapping, and new fields must be added explicitly.
+            #
+            # We need `__versions` to be in `_source` (so that our update scripts can operate on it), but
+            # have no need for it to be searchable (as it's just an internal data structure used for indexing).
+            #
+            # Note: we intentionally set false as a string here, because that's how the datastore echoes it back
+            # to us when you query the mapping (even if you set it as a boolean). Our checks for index mapping
+            # consistency fail validation if we set it as a boolean since the datastore doesn't echo it back as
+            # a boolean.
+            "dynamic" => "false"
+          }
+        }})
+      end
+
+    {"dynamic" => "strict"}.merge(field_mappings).tap do |hash|
+      # If we are using custom shard routing, we want to require a `routing` value to be provided
+      # in every single index, get, delete or update request; otherwise the request might be
+      # made against the wrong shard.
+      hash["_routing"] = {"required" => true} if uses_custom_routing?
+      hash["_size"] = {"enabled" => true} if schema_def_state.index_document_sizes?
+    end
+  end
+
+  def public_field_path(public_path_string, explanation:)
+    parent_is_not_list = ->(parent_field) { !parent_field.type.list? }
+    resolver = SchemaElements::FieldPath::Resolver.new
+    resolved_path = resolver.resolve_public_path(indexed_type, public_path_string, &parent_is_not_list)
+    return resolved_path if resolved_path
+
+    path_parts = public_path_string.split(".")
+    error_msg = "Field `#{indexed_type.name}.#{public_path_string}` cannot be resolved, but #{explanation}."
+
+    # If it is a nested field path, the problem could be that a type has been referenced which does not exist, so mention that.
+    if path_parts.size > 1
+      error_msg += " Verify that all fields and types referenced by `#{public_path_string}` are defined."
+    end
+
+    # If the first part of the path doesn't resolve, the problem could be that the field is defined after the `index` call
+    # but it needs to be defined before it, so mention that.
+    if resolver.resolve_public_path(indexed_type, path_parts.first, &parent_is_not_list).nil?
+      error_msg += " Note: the `#{indexed_type.name}.#{path_parts.first}` definition must come before the `index` call."
+    end
+
+    raise Errors::SchemaError, error_msg
+  end
+
+  def date_and_datetime_types
+    @date_and_datetime_types ||= %w[Date DateTime].map do |type|
+      schema_def_state.type_namer.name_for(type)
+    end
+  end
+end
+
+
+ + + +
+

+ + #schema_def_stateState (readonly) + + + + + +

+
+

Returns schema definition state.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (State) + + + + — +

    schema definition state

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 39
+
+class Index < Struct.new(:name, :default_sort_pairs, :settings, :schema_def_state, :indexed_type, :routing_field_path, :rollover_config)
+  include Mixins::HasReadableToSAndInspect.new { |i| i.name }
+
+  # @param name [String] name of the index
+  # @param settings [Hash<(String, Object)>] datastore settings for the index
+  # @param schema_def_state [State] schema definition state
+  # @param indexed_type [SchemaElements::ObjectType, SchemaElements::InterfaceType, SchemaElements::UnionType] type backed by this index
+  # @yield [Index] the index, for further customization
+  # @api private
+  def initialize(name, settings, schema_def_state, indexed_type)
+    if name.include?(ROLLOVER_INDEX_INFIX_MARKER)
+      raise Errors::SchemaError, "`#{name}` is an invalid index definition name since it contains " \
+        "`#{ROLLOVER_INDEX_INFIX_MARKER}` which ElasticGraph treats as special."
+    end
+
+    settings = DEFAULT_SETTINGS.merge(Support::HashUtil.flatten_and_stringify_keys(settings, prefix: "index"))
+
+    super(name, [], settings, schema_def_state, indexed_type, [], nil)
+
+    # `id` is the field Elasticsearch/OpenSearch use for routing by default:
+    # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-routing-field.html
+    # By using it here, it will cause queries to pass a `routing` parameter when
+    # searching with id filtering on an index that does not use custom shard routing, giving
+    # us a nice efficiency boost.
+    self.routing_field_path = public_field_path("id", explanation: "indexed types must have an `id` field")
+
+    yield self if block_given?
+  end
+
+  # Specifies how documents in this index should sort by default, when no `orderBy` argument is provided to the GraphQL query.
+  #
+  # @note the field name strings can be a dot-separated nested fields, but all referenced
+  #   fields must exist when this is called.
+  #
+  # @param field_name_direction_pairs [Array<(String, Symbol)>] pairs of field names and `:asc` or `:desc`
+  # @return [void]
+  #
+  # @example Sort on `name` (ascending) with `createdAt` (descending) as a tie-breaker
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "createdAt", "DateTime"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.default_sort "name", :asc, "createdAt", :desc
+  #       end
+  #     end
+  #   end
+  def default_sort(*field_name_direction_pairs)
+    self.default_sort_pairs = field_name_direction_pairs
+  end
+
+  # Causes this index to "rollover" at the provided `frequency` based on the value of the provided `timestamp_field_path_name`.
+  # This is particularly useful for time-series data. Partitioning the data into `hourly`, `daily`, `monthly` or `yearly` buckets
+  # allows for different index configurations, and can be necessary when a dataset is too large to fit in one dataset given
+  # Elasticsearch/OpenSearch limitations on the number of shards in one index. In addition, ElasticGraph optimizes queries which
+  # filter on the timestamp field to target the subset of the indices in which matching documents could reside.
+  #
+  # @note the timestamp field specified here **must be immutable**. To understand why, consider a `:yearly` rollover
+  #   index used for data based on `createdAt`; if ElasticGraph ingests record `123` with a createdAt of `2023-12-31T23:59:59Z`, it
+  #   will be indexed in the `2023` index. Later if it receives an update event for record `123` with a `createdAt` of
+  #   `2024-01-01T00:00:00Z` (a mere one second later!), ElasticGraph will store the new version of the payment in the `2024` index,
+  #   and leave the old copy of the payment in the `2023` index unchanged. It’ll have duplicates for that document.
+  # @note changing the `rollover` configuration on an existing index that already has data will result in duplicate documents
+  #
+  # @param frequency [:yearly, :monthly, :daily, :hourly] how often to rollover the index
+  # @param timestamp_field_path_name [String] dot-separated path to the timestamp field used for rollover. Note: all referenced
+  #   fields must exist when this is called.
+  # @return [void]
+  #
+  # @example Define a `campaigns` index to rollover yearly based on `createdAt`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "createdAt", "DateTime"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.rollover :yearly, "createdAt"
+  #       end
+  #     end
+  #   end
+  def rollover(frequency, timestamp_field_path_name)
+    timestamp_field_path = public_field_path(timestamp_field_path_name, explanation: "it is referenced as an index `rollover` field")
+
+    unless date_and_datetime_types.include?(timestamp_field_path.type.fully_unwrapped.name)
+      date_or_datetime_description = date_and_datetime_types.map { |t| "`#{t}`" }.join(" or ")
+      raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is not a #{date_or_datetime_description} field."
+    end
+
+    if timestamp_field_path.type.list?
+      raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is a list field."
+    end
+
+    timestamp_field_path.path_parts.each { |f| f.json_schema nullable: false }
+
+    self.rollover_config = RolloverConfig.new(
+      frequency: frequency,
+      timestamp_field_path: timestamp_field_path
+    )
+  end
+
+  # Configures the index to [route documents to shards](https://www.elastic.co/guide/en/elasticsearch/reference/8.15/mapping-routing-field.html)
+  # based on the specified field. ElasticGraph optimizes queries that filter on the shard routing field so that they only run on a
+  # subset of nodes instead of all nodes. This can make a big difference in query performance if queries usually filter on a certain
+  # field. Using an appropriate field for shard routing is often essential for horizontal scaling, as it avoids having every query
+  # hit every node, allowing additional nodes to increase query throughput.
+  #
+  # @note it is essential that the shards are well-balanced. If the data’s distribution is lopsided, using this feature can make
+  #   performance worse.
+  # @note the routing field specified here **must be immutable**. If ElasticGraph receives an updated version of a document with a
+  #   different routing value, it’ll write the new version of the document to a different shard and leave the copy on the old shard
+  #   unchanged, leading to duplicates.
+  # @note changing the shard routing configuration on an existing index that already has data will result in duplicate documents
+  #
+  # @param routing_field_path_name [String] dot-separated path to the field used for shard routing. Note: all referenced
+  #   fields must exist when this is called.
+  # @return [void]
+  #
+  # @example Define a `campaigns` index to shard on `organizationId`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "organizationId", "ID"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.route_with "organizationId"
+  #       end
+  #     end
+  #   end
+  def route_with(routing_field_path_name)
+    routing_field_path = public_field_path(routing_field_path_name, explanation: "it is referenced as an index `route_with` field")
+
+    unless routing_field_path.type.leaf?
+      raise Errors::SchemaError, "shard routing field `#{routing_field_path.full_description}` cannot be used for routing since it is not a leaf field."
+    end
+
+    self.routing_field_path = routing_field_path
+
+    routing_field_path.path_parts[0..-2].each { |f| f.json_schema nullable: false }
+    routing_field_path.last_part.json_schema nullable: false, pattern: HAS_NON_WHITE_SPACE_REGEX
+    indexed_type.append_to_documentation "For more performant queries on this type, please filter on `#{routing_field_path_name}` if possible."
+  end
+
+  # @see #route_with
+  # @return [Boolean] whether or not this index uses custom shard routing
+  def uses_custom_routing?
+    routing_field_path.path_in_index != "id"
+  end
+
+  # @return [Hash<String, Object>] datastore configuration for this index for when it does not use rollover
+  def to_index_config
+    {
+      "aliases" => {},
+      "mappings" => mappings,
+      "settings" => settings
+    }.compact
+  end
+
+  # @return [Hash<String, Object>] datastore configuration for the index template that will be defined if rollover is used
+  def to_index_template_config
+    {
+      "index_patterns" => ["#{name}#{ROLLOVER_INDEX_INFIX_MARKER}*"],
+      "template" => {
+        "aliases" => {},
+        "mappings" => mappings,
+        "settings" => settings
+      }
+    }
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::IndexDefinition] runtime metadata for this index
+  def 
+    SchemaArtifacts::RuntimeMetadata::IndexDefinition.new(
+      route_with: routing_field_path.path_in_index,
+      rollover: rollover_config&.,
+      current_sources: indexed_type.current_sources,
+      fields_by_path: indexed_type..to_h,
+      default_sort_fields: default_sort_pairs.each_slice(2).map do |(graphql_field_path_name, direction)|
+        SchemaArtifacts::RuntimeMetadata::SortField.new(
+          field_path: public_field_path(graphql_field_path_name, explanation: "it is referenced as an index `default_sort` field").path_in_index,
+          direction: direction
+        )
+      end
+    )
+  end
+
+  private
+
+  # A regex that requires at least one non-whitespace character.
+  # Note: this does not use the `/S` character class because it's recommended to use a small subset
+  # of Regex syntax:
+  #
+  # > The regular expression syntax used is from JavaScript (ECMA 262, specifically). However, that
+  # > complete syntax is not widely supported, therefore it is recommended that you stick to the subset
+  # > of that syntax described below.
+  #
+  # (From https://json-schema.org/understanding-json-schema/reference/regular_expressions.html)
+  HAS_NON_WHITE_SPACE_REGEX = "[^ \t\n]+"
+
+  DEFAULT_SETTINGS = {
+    "index.mapping.ignore_malformed" => false,
+    "index.mapping.coerce" => false,
+    "index.number_of_replicas" => 1,
+    "index.number_of_shards" => 1
+  }
+
+  def mappings
+    field_mappings = indexed_type
+      .to_indexing_field_type
+      .to_mapping
+      .except("type") # `type` is invalid at the mapping root because it always has to be an object.
+      .then { |mapping| ListCountsMapping.merged_into(mapping, for_type: indexed_type) }
+      .then do |fm|
+        Support::HashUtil.deep_merge(fm, {"properties" => {
+          "__sources" => {"type" => "keyword"},
+          "__versions" => {
+            "type" => "object",
+            # __versions is map keyed by relationship name, with values that are maps keyed by id. Since it's not
+            # a static object with known fields, we need to use dynamic here. Passing `false` allows some level
+            # of dynamicness. As per https://www.elastic.co/guide/en/elasticsearch/reference/8.7/dynamic.html#dynamic-parameters:
+            #
+            # > New fields are ignored. These fields will not be indexed or searchable, but will still appear in the _source
+            # > field of returned hits. These fields will not be added to the mapping, and new fields must be added explicitly.
+            #
+            # We need `__versions` to be in `_source` (so that our update scripts can operate on it), but
+            # have no need for it to be searchable (as it's just an internal data structure used for indexing).
+            #
+            # Note: we intentionally set false as a string here, because that's how the datastore echoes it back
+            # to us when you query the mapping (even if you set it as a boolean). Our checks for index mapping
+            # consistency fail validation if we set it as a boolean since the datastore doesn't echo it back as
+            # a boolean.
+            "dynamic" => "false"
+          }
+        }})
+      end
+
+    {"dynamic" => "strict"}.merge(field_mappings).tap do |hash|
+      # If we are using custom shard routing, we want to require a `routing` value to be provided
+      # in every single index, get, delete or update request; otherwise the request might be
+      # made against the wrong shard.
+      hash["_routing"] = {"required" => true} if uses_custom_routing?
+      hash["_size"] = {"enabled" => true} if schema_def_state.index_document_sizes?
+    end
+  end
+
+  def public_field_path(public_path_string, explanation:)
+    parent_is_not_list = ->(parent_field) { !parent_field.type.list? }
+    resolver = SchemaElements::FieldPath::Resolver.new
+    resolved_path = resolver.resolve_public_path(indexed_type, public_path_string, &parent_is_not_list)
+    return resolved_path if resolved_path
+
+    path_parts = public_path_string.split(".")
+    error_msg = "Field `#{indexed_type.name}.#{public_path_string}` cannot be resolved, but #{explanation}."
+
+    # If it is a nested field path, the problem could be that a type has been referenced which does not exist, so mention that.
+    if path_parts.size > 1
+      error_msg += " Verify that all fields and types referenced by `#{public_path_string}` are defined."
+    end
+
+    # If the first part of the path doesn't resolve, the problem could be that the field is defined after the `index` call
+    # but it needs to be defined before it, so mention that.
+    if resolver.resolve_public_path(indexed_type, path_parts.first, &parent_is_not_list).nil?
+      error_msg += " Note: the `#{indexed_type.name}.#{path_parts.first}` definition must come before the `index` call."
+    end
+
+    raise Errors::SchemaError, error_msg
+  end
+
+  def date_and_datetime_types
+    @date_and_datetime_types ||= %w[Date DateTime].map do |type|
+      schema_def_state.type_namer.name_for(type)
+    end
+  end
+end
+
+
+ + + +
+

+ + #settingsHash<(String, Object)> (readonly) + + + + + +

+
+

Returns datastore settings for the index.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<(String, Object)>) + + + + — +

    datastore settings for the index

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 39
+
+class Index < Struct.new(:name, :default_sort_pairs, :settings, :schema_def_state, :indexed_type, :routing_field_path, :rollover_config)
+  include Mixins::HasReadableToSAndInspect.new { |i| i.name }
+
+  # @param name [String] name of the index
+  # @param settings [Hash<(String, Object)>] datastore settings for the index
+  # @param schema_def_state [State] schema definition state
+  # @param indexed_type [SchemaElements::ObjectType, SchemaElements::InterfaceType, SchemaElements::UnionType] type backed by this index
+  # @yield [Index] the index, for further customization
+  # @api private
+  def initialize(name, settings, schema_def_state, indexed_type)
+    if name.include?(ROLLOVER_INDEX_INFIX_MARKER)
+      raise Errors::SchemaError, "`#{name}` is an invalid index definition name since it contains " \
+        "`#{ROLLOVER_INDEX_INFIX_MARKER}` which ElasticGraph treats as special."
+    end
+
+    settings = DEFAULT_SETTINGS.merge(Support::HashUtil.flatten_and_stringify_keys(settings, prefix: "index"))
+
+    super(name, [], settings, schema_def_state, indexed_type, [], nil)
+
+    # `id` is the field Elasticsearch/OpenSearch use for routing by default:
+    # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-routing-field.html
+    # By using it here, it will cause queries to pass a `routing` parameter when
+    # searching with id filtering on an index that does not use custom shard routing, giving
+    # us a nice efficiency boost.
+    self.routing_field_path = public_field_path("id", explanation: "indexed types must have an `id` field")
+
+    yield self if block_given?
+  end
+
+  # Specifies how documents in this index should sort by default, when no `orderBy` argument is provided to the GraphQL query.
+  #
+  # @note the field name strings can be a dot-separated nested fields, but all referenced
+  #   fields must exist when this is called.
+  #
+  # @param field_name_direction_pairs [Array<(String, Symbol)>] pairs of field names and `:asc` or `:desc`
+  # @return [void]
+  #
+  # @example Sort on `name` (ascending) with `createdAt` (descending) as a tie-breaker
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "createdAt", "DateTime"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.default_sort "name", :asc, "createdAt", :desc
+  #       end
+  #     end
+  #   end
+  def default_sort(*field_name_direction_pairs)
+    self.default_sort_pairs = field_name_direction_pairs
+  end
+
+  # Causes this index to "rollover" at the provided `frequency` based on the value of the provided `timestamp_field_path_name`.
+  # This is particularly useful for time-series data. Partitioning the data into `hourly`, `daily`, `monthly` or `yearly` buckets
+  # allows for different index configurations, and can be necessary when a dataset is too large to fit in one dataset given
+  # Elasticsearch/OpenSearch limitations on the number of shards in one index. In addition, ElasticGraph optimizes queries which
+  # filter on the timestamp field to target the subset of the indices in which matching documents could reside.
+  #
+  # @note the timestamp field specified here **must be immutable**. To understand why, consider a `:yearly` rollover
+  #   index used for data based on `createdAt`; if ElasticGraph ingests record `123` with a createdAt of `2023-12-31T23:59:59Z`, it
+  #   will be indexed in the `2023` index. Later if it receives an update event for record `123` with a `createdAt` of
+  #   `2024-01-01T00:00:00Z` (a mere one second later!), ElasticGraph will store the new version of the payment in the `2024` index,
+  #   and leave the old copy of the payment in the `2023` index unchanged. It’ll have duplicates for that document.
+  # @note changing the `rollover` configuration on an existing index that already has data will result in duplicate documents
+  #
+  # @param frequency [:yearly, :monthly, :daily, :hourly] how often to rollover the index
+  # @param timestamp_field_path_name [String] dot-separated path to the timestamp field used for rollover. Note: all referenced
+  #   fields must exist when this is called.
+  # @return [void]
+  #
+  # @example Define a `campaigns` index to rollover yearly based on `createdAt`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "createdAt", "DateTime"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.rollover :yearly, "createdAt"
+  #       end
+  #     end
+  #   end
+  def rollover(frequency, timestamp_field_path_name)
+    timestamp_field_path = public_field_path(timestamp_field_path_name, explanation: "it is referenced as an index `rollover` field")
+
+    unless date_and_datetime_types.include?(timestamp_field_path.type.fully_unwrapped.name)
+      date_or_datetime_description = date_and_datetime_types.map { |t| "`#{t}`" }.join(" or ")
+      raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is not a #{date_or_datetime_description} field."
+    end
+
+    if timestamp_field_path.type.list?
+      raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is a list field."
+    end
+
+    timestamp_field_path.path_parts.each { |f| f.json_schema nullable: false }
+
+    self.rollover_config = RolloverConfig.new(
+      frequency: frequency,
+      timestamp_field_path: timestamp_field_path
+    )
+  end
+
+  # Configures the index to [route documents to shards](https://www.elastic.co/guide/en/elasticsearch/reference/8.15/mapping-routing-field.html)
+  # based on the specified field. ElasticGraph optimizes queries that filter on the shard routing field so that they only run on a
+  # subset of nodes instead of all nodes. This can make a big difference in query performance if queries usually filter on a certain
+  # field. Using an appropriate field for shard routing is often essential for horizontal scaling, as it avoids having every query
+  # hit every node, allowing additional nodes to increase query throughput.
+  #
+  # @note it is essential that the shards are well-balanced. If the data’s distribution is lopsided, using this feature can make
+  #   performance worse.
+  # @note the routing field specified here **must be immutable**. If ElasticGraph receives an updated version of a document with a
+  #   different routing value, it’ll write the new version of the document to a different shard and leave the copy on the old shard
+  #   unchanged, leading to duplicates.
+  # @note changing the shard routing configuration on an existing index that already has data will result in duplicate documents
+  #
+  # @param routing_field_path_name [String] dot-separated path to the field used for shard routing. Note: all referenced
+  #   fields must exist when this is called.
+  # @return [void]
+  #
+  # @example Define a `campaigns` index to shard on `organizationId`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID!"
+  #       t.field "name", "String"
+  #       t.field "organizationId", "ID"
+  #
+  #       t.index "campaigns"do |i|
+  #         i.route_with "organizationId"
+  #       end
+  #     end
+  #   end
+  def route_with(routing_field_path_name)
+    routing_field_path = public_field_path(routing_field_path_name, explanation: "it is referenced as an index `route_with` field")
+
+    unless routing_field_path.type.leaf?
+      raise Errors::SchemaError, "shard routing field `#{routing_field_path.full_description}` cannot be used for routing since it is not a leaf field."
+    end
+
+    self.routing_field_path = routing_field_path
+
+    routing_field_path.path_parts[0..-2].each { |f| f.json_schema nullable: false }
+    routing_field_path.last_part.json_schema nullable: false, pattern: HAS_NON_WHITE_SPACE_REGEX
+    indexed_type.append_to_documentation "For more performant queries on this type, please filter on `#{routing_field_path_name}` if possible."
+  end
+
+  # @see #route_with
+  # @return [Boolean] whether or not this index uses custom shard routing
+  def uses_custom_routing?
+    routing_field_path.path_in_index != "id"
+  end
+
+  # @return [Hash<String, Object>] datastore configuration for this index for when it does not use rollover
+  def to_index_config
+    {
+      "aliases" => {},
+      "mappings" => mappings,
+      "settings" => settings
+    }.compact
+  end
+
+  # @return [Hash<String, Object>] datastore configuration for the index template that will be defined if rollover is used
+  def to_index_template_config
+    {
+      "index_patterns" => ["#{name}#{ROLLOVER_INDEX_INFIX_MARKER}*"],
+      "template" => {
+        "aliases" => {},
+        "mappings" => mappings,
+        "settings" => settings
+      }
+    }
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::IndexDefinition] runtime metadata for this index
+  def 
+    SchemaArtifacts::RuntimeMetadata::IndexDefinition.new(
+      route_with: routing_field_path.path_in_index,
+      rollover: rollover_config&.,
+      current_sources: indexed_type.current_sources,
+      fields_by_path: indexed_type..to_h,
+      default_sort_fields: default_sort_pairs.each_slice(2).map do |(graphql_field_path_name, direction)|
+        SchemaArtifacts::RuntimeMetadata::SortField.new(
+          field_path: public_field_path(graphql_field_path_name, explanation: "it is referenced as an index `default_sort` field").path_in_index,
+          direction: direction
+        )
+      end
+    )
+  end
+
+  private
+
+  # A regex that requires at least one non-whitespace character.
+  # Note: this does not use the `/S` character class because it's recommended to use a small subset
+  # of Regex syntax:
+  #
+  # > The regular expression syntax used is from JavaScript (ECMA 262, specifically). However, that
+  # > complete syntax is not widely supported, therefore it is recommended that you stick to the subset
+  # > of that syntax described below.
+  #
+  # (From https://json-schema.org/understanding-json-schema/reference/regular_expressions.html)
+  HAS_NON_WHITE_SPACE_REGEX = "[^ \t\n]+"
+
+  DEFAULT_SETTINGS = {
+    "index.mapping.ignore_malformed" => false,
+    "index.mapping.coerce" => false,
+    "index.number_of_replicas" => 1,
+    "index.number_of_shards" => 1
+  }
+
+  def mappings
+    field_mappings = indexed_type
+      .to_indexing_field_type
+      .to_mapping
+      .except("type") # `type` is invalid at the mapping root because it always has to be an object.
+      .then { |mapping| ListCountsMapping.merged_into(mapping, for_type: indexed_type) }
+      .then do |fm|
+        Support::HashUtil.deep_merge(fm, {"properties" => {
+          "__sources" => {"type" => "keyword"},
+          "__versions" => {
+            "type" => "object",
+            # __versions is map keyed by relationship name, with values that are maps keyed by id. Since it's not
+            # a static object with known fields, we need to use dynamic here. Passing `false` allows some level
+            # of dynamicness. As per https://www.elastic.co/guide/en/elasticsearch/reference/8.7/dynamic.html#dynamic-parameters:
+            #
+            # > New fields are ignored. These fields will not be indexed or searchable, but will still appear in the _source
+            # > field of returned hits. These fields will not be added to the mapping, and new fields must be added explicitly.
+            #
+            # We need `__versions` to be in `_source` (so that our update scripts can operate on it), but
+            # have no need for it to be searchable (as it's just an internal data structure used for indexing).
+            #
+            # Note: we intentionally set false as a string here, because that's how the datastore echoes it back
+            # to us when you query the mapping (even if you set it as a boolean). Our checks for index mapping
+            # consistency fail validation if we set it as a boolean since the datastore doesn't echo it back as
+            # a boolean.
+            "dynamic" => "false"
+          }
+        }})
+      end
+
+    {"dynamic" => "strict"}.merge(field_mappings).tap do |hash|
+      # If we are using custom shard routing, we want to require a `routing` value to be provided
+      # in every single index, get, delete or update request; otherwise the request might be
+      # made against the wrong shard.
+      hash["_routing"] = {"required" => true} if uses_custom_routing?
+      hash["_size"] = {"enabled" => true} if schema_def_state.index_document_sizes?
+    end
+  end
+
+  def public_field_path(public_path_string, explanation:)
+    parent_is_not_list = ->(parent_field) { !parent_field.type.list? }
+    resolver = SchemaElements::FieldPath::Resolver.new
+    resolved_path = resolver.resolve_public_path(indexed_type, public_path_string, &parent_is_not_list)
+    return resolved_path if resolved_path
+
+    path_parts = public_path_string.split(".")
+    error_msg = "Field `#{indexed_type.name}.#{public_path_string}` cannot be resolved, but #{explanation}."
+
+    # If it is a nested field path, the problem could be that a type has been referenced which does not exist, so mention that.
+    if path_parts.size > 1
+      error_msg += " Verify that all fields and types referenced by `#{public_path_string}` are defined."
+    end
+
+    # If the first part of the path doesn't resolve, the problem could be that the field is defined after the `index` call
+    # but it needs to be defined before it, so mention that.
+    if resolver.resolve_public_path(indexed_type, path_parts.first, &parent_is_not_list).nil?
+      error_msg += " Note: the `#{indexed_type.name}.#{path_parts.first}` definition must come before the `index` call."
+    end
+
+    raise Errors::SchemaError, error_msg
+  end
+
+  def date_and_datetime_types
+    @date_and_datetime_types ||= %w[Date DateTime].map do |type|
+      schema_def_state.type_namer.name_for(type)
+    end
+  end
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #default_sort(*field_name_direction_pairs) ⇒ void + + + + + +

+
+ +
+ Note: +

the field name strings can be a dot-separated nested fields, but all referenced +fields must exist when this is called.

+
+
+ +

This method returns an undefined value.

Specifies how documents in this index should sort by default, when no orderBy argument is provided to the GraphQL query.

+ + +
+
+
+ +
+

Examples:

+ + +

Sort on name (ascending) with createdAt (descending) as a tie-breaker

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID!"
+    t.field "name", "String"
+    t.field "createdAt", "DateTime"
+
+    t.index "campaigns"do |i|
+      i.default_sort "name", :asc, "createdAt", :desc
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + field_name_direction_pairs + + + (Array<(String, Symbol)>) + + + + — +

    pairs of field names and :asc or :desc

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+88
+89
+90
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 88
+
+def default_sort(*field_name_direction_pairs)
+  self.default_sort_pairs = field_name_direction_pairs
+end
+
+
+ +
+

+ + #rollover(frequency, timestamp_field_path_name) ⇒ void + + + + + +

+
+ +
+ Note: +

the timestamp field specified here must be immutable. To understand why, consider a :yearly rollover +index used for data based on createdAt; if ElasticGraph ingests record 123 with a createdAt of 2023-12-31T23:59:59Z, it +will be indexed in the 2023 index. Later if it receives an update event for record 123 with a createdAt of +2024-01-01T00:00:00Z (a mere one second later!), ElasticGraph will store the new version of the payment in the 2024 index, +and leave the old copy of the payment in the 2023 index unchanged. It’ll have duplicates for that document.

+
+
+ +
+ Note: +

changing the rollover configuration on an existing index that already has data will result in duplicate documents

+
+
+ +

This method returns an undefined value.

Causes this index to “rollover” at the provided frequency based on the value of the provided timestamp_field_path_name. +This is particularly useful for time-series data. Partitioning the data into hourly, daily, monthly or yearly buckets +allows for different index configurations, and can be necessary when a dataset is too large to fit in one dataset given +Elasticsearch/OpenSearch limitations on the number of shards in one index. In addition, ElasticGraph optimizes queries which +filter on the timestamp field to target the subset of the indices in which matching documents could reside.

+ + +
+
+
+ +
+

Examples:

+ + +

Define a campaigns index to rollover yearly based on createdAt

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID!"
+    t.field "name", "String"
+    t.field "createdAt", "DateTime"
+
+    t.index "campaigns"do |i|
+      i.rollover :yearly, "createdAt"
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + frequency + + + (:yearly, :monthly, :daily, :hourly) + + + + — +

    how often to rollover the index

    +
    + +
  • + +
  • + + timestamp_field_path_name + + + (String) + + + + — +

    dot-separated path to the timestamp field used for rollover. Note: all referenced +fields must exist when this is called.

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 122
+
+def rollover(frequency, timestamp_field_path_name)
+  timestamp_field_path = public_field_path(timestamp_field_path_name, explanation: "it is referenced as an index `rollover` field")
+
+  unless date_and_datetime_types.include?(timestamp_field_path.type.fully_unwrapped.name)
+    date_or_datetime_description = date_and_datetime_types.map { |t| "`#{t}`" }.join(" or ")
+    raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is not a #{date_or_datetime_description} field."
+  end
+
+  if timestamp_field_path.type.list?
+    raise Errors::SchemaError, "rollover field `#{timestamp_field_path.full_description}` cannot be used for rollover since it is a list field."
+  end
+
+  timestamp_field_path.path_parts.each { |f| f.json_schema nullable: false }
+
+  self.rollover_config = RolloverConfig.new(
+    frequency: frequency,
+    timestamp_field_path: timestamp_field_path
+  )
+end
+
+
+ +
+

+ + #route_with(routing_field_path_name) ⇒ void + + + + + +

+
+ +
+ Note: +

it is essential that the shards are well-balanced. If the data’s distribution is lopsided, using this feature can make +performance worse.

+
+
+ +
+ Note: +

the routing field specified here must be immutable. If ElasticGraph receives an updated version of a document with a +different routing value, it’ll write the new version of the document to a different shard and leave the copy on the old shard +unchanged, leading to duplicates.

+
+
+ +
+ Note: +

changing the shard routing configuration on an existing index that already has data will result in duplicate documents

+
+
+ +

This method returns an undefined value.

Configures the index to route documents to shards +based on the specified field. ElasticGraph optimizes queries that filter on the shard routing field so that they only run on a +subset of nodes instead of all nodes. This can make a big difference in query performance if queries usually filter on a certain +field. Using an appropriate field for shard routing is often essential for horizontal scaling, as it avoids having every query +hit every node, allowing additional nodes to increase query throughput.

+ + +
+
+
+ +
+

Examples:

+ + +

Define a campaigns index to shard on organizationId

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID!"
+    t.field "name", "String"
+    t.field "organizationId", "ID"
+
+    t.index "campaigns"do |i|
+      i.route_with "organizationId"
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + routing_field_path_name + + + (String) + + + + — +

    dot-separated path to the field used for shard routing. Note: all referenced +fields must exist when this is called.

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 171
+
+def route_with(routing_field_path_name)
+  routing_field_path = public_field_path(routing_field_path_name, explanation: "it is referenced as an index `route_with` field")
+
+  unless routing_field_path.type.leaf?
+    raise Errors::SchemaError, "shard routing field `#{routing_field_path.full_description}` cannot be used for routing since it is not a leaf field."
+  end
+
+  self.routing_field_path = routing_field_path
+
+  routing_field_path.path_parts[0..-2].each { |f| f.json_schema nullable: false }
+  routing_field_path.last_part.json_schema nullable: false, pattern: HAS_NON_WHITE_SPACE_REGEX
+  indexed_type.append_to_documentation "For more performant queries on this type, please filter on `#{routing_field_path_name}` if possible."
+end
+
+
+ +
+

+ + #runtime_metadataSchemaArtifacts::RuntimeMetadata::IndexDefinition + + + + + +

+
+

Returns runtime metadata for this index.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (SchemaArtifacts::RuntimeMetadata::IndexDefinition) + + + + — +

    runtime metadata for this index

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 213
+
+def 
+  SchemaArtifacts::RuntimeMetadata::IndexDefinition.new(
+    route_with: routing_field_path.path_in_index,
+    rollover: rollover_config&.,
+    current_sources: indexed_type.current_sources,
+    fields_by_path: indexed_type..to_h,
+    default_sort_fields: default_sort_pairs.each_slice(2).map do |(graphql_field_path_name, direction)|
+      SchemaArtifacts::RuntimeMetadata::SortField.new(
+        field_path: public_field_path(graphql_field_path_name, explanation: "it is referenced as an index `default_sort` field").path_in_index,
+        direction: direction
+      )
+    end
+  )
+end
+
+
+ +
+

+ + #to_index_configHash<String, Object> + + + + + +

+
+

Returns datastore configuration for this index for when it does not use rollover.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, Object>) + + + + — +

    datastore configuration for this index for when it does not use rollover

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+192
+193
+194
+195
+196
+197
+198
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 192
+
+def to_index_config
+  {
+    "aliases" => {},
+    "mappings" => mappings,
+    "settings" => settings
+  }.compact
+end
+
+
+ +
+

+ + #to_index_template_configHash<String, Object> + + + + + +

+
+

Returns datastore configuration for the index template that will be defined if rollover is used.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, Object>) + + + + — +

    datastore configuration for the index template that will be defined if rollover is used

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 201
+
+def to_index_template_config
+  {
+    "index_patterns" => ["#{name}#{ROLLOVER_INDEX_INFIX_MARKER}*"],
+    "template" => {
+      "aliases" => {},
+      "mappings" => mappings,
+      "settings" => settings
+    }
+  }
+end
+
+
+ +
+

+ + #uses_custom_routing?Boolean + + + + + +

+
+

Returns whether or not this index uses custom shard routing.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + + — +

    whether or not this index uses custom shard routing

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+187
+188
+189
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/index.rb', line 187
+
+def uses_custom_routing?
+  routing_field_path.path_in_index != "id"
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Indexing/JSONSchemaFieldMetadata.html b/docs/main/ElasticGraph/SchemaDefinition/Indexing/JSONSchemaFieldMetadata.html new file mode 100644 index 00000000..485e7d36 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Indexing/JSONSchemaFieldMetadata.html @@ -0,0 +1,446 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::Indexing::JSONSchemaFieldMetadata + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::Indexing::JSONSchemaFieldMetadata + + + Private +

+
+ +
+
Inherits:
+
+ Data + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/json_schema_field_metadata.rb,
+ elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/json_schema_field_metadata.rb
+
+
+ +
+ +

Overview

+
+

+ This class is part of a private API. + You should avoid using this class if possible, as it may be removed or be changed in the future. +

+

Metadata about an ElasticGraph field that needs to be stored in our versioned JSON schemas +alongside the JSON schema fields.

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Attribute Details

+ + + +
+

+ + #name_in_indexString (readonly) + + + + + +

+
+

Returns name of the field in the index.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    name of the field in the index

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+24
+25
+26
+27
+28
+29
+30
+31
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/json_schema_field_metadata.rb', line 24
+
+class JSONSchemaFieldMetadata < ::Data
+  # @return [Hash<String, String>] hash form of the metadata that can be dumped in JSON schema
+  def to_dumpable_hash
+    {"type" => type, "nameInIndex" => name_in_index}
+  end
+
+  # @dynamic initialize, type, name_in_index
+end
+
+
+ + + +
+

+ + #typeString (readonly) + + + + + +

+
+

Returns name of the ElasticGraph type for this field.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    name of the ElasticGraph type for this field

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+24
+25
+26
+27
+28
+29
+30
+31
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/json_schema_field_metadata.rb', line 24
+
+class JSONSchemaFieldMetadata < ::Data
+  # @return [Hash<String, String>] hash form of the metadata that can be dumped in JSON schema
+  def to_dumpable_hash
+    {"type" => type, "nameInIndex" => name_in_index}
+  end
+
+  # @dynamic initialize, type, name_in_index
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #to_dumpable_hashHash<String, String> + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Returns hash form of the metadata that can be dumped in JSON schema.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, String>) + + + + — +

    hash form of the metadata that can be dumped in JSON schema

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+26
+27
+28
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/indexing/json_schema_field_metadata.rb', line 26
+
+def to_dumpable_hash
+  {"type" => type, "nameInIndex" => name_in_index}
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Mixins.html b/docs/main/ElasticGraph/SchemaDefinition/Mixins.html new file mode 100644 index 00000000..7c40a76f --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Mixins.html @@ -0,0 +1,128 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Mixins + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Mixins + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/can_be_graphql_only.rb,
+ elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_indices.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_subtypes.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_type_info.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_directives.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_documentation.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/verifies_graphql_name.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/supports_default_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/supports_filtering_and_aggregation.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_derived_graphql_type_customizations.rb
+
+
+ +
+ +

Overview

+
+

Namespace for modules that are used as mixins. Mixins are used to offer a consistent API for +schema definition features that apply to multiple types of schema elements.

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + Modules: CanBeGraphQLOnly, HasDerivedGraphQLTypeCustomizations, HasDirectives, HasDocumentation, HasIndices, HasTypeInfo, ImplementsInterfaces, SupportsDefaultValue, VerifiesGraphQLName + + + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Mixins/CanBeGraphQLOnly.html b/docs/main/ElasticGraph/SchemaDefinition/Mixins/CanBeGraphQLOnly.html new file mode 100644 index 00000000..67b9e3db --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Mixins/CanBeGraphQLOnly.html @@ -0,0 +1,299 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Mixins::CanBeGraphQLOnly + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Mixins::CanBeGraphQLOnly + + + +

+
+ + + + + + + + + +
+
Included in:
+
SchemaElements::EnumType, SchemaElements::ScalarType, SchemaElements::TypeWithSubfields, SchemaElements::UnionType
+
+ + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/can_be_graphql_only.rb
+
+ +
+ +

Overview

+
+

Used to indicate if a type only exists in the GraphQL schema (e.g. it has no indexing component).

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #graphql_only(value) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Sets whether or not this type only exists in the GraphQL schema

+ + +
+
+
+

Parameters:

+
    + +
  • + + value + + + (Boolean) + + + + — +

    whether or not this type only exists in the GraphQL schema

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+20
+21
+22
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/can_be_graphql_only.rb', line 20
+
+def graphql_only(value)
+  @graphql_only = value
+end
+
+
+ +
+

+ + #graphql_only?Boolean + + + + + +

+
+

Returns whether or not this type only exists in the GraphQL schema.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + + — +

    whether or not this type only exists in the GraphQL schema

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+25
+26
+27
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/can_be_graphql_only.rb', line 25
+
+def graphql_only?
+  !!@graphql_only
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasDerivedGraphQLTypeCustomizations.html b/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasDerivedGraphQLTypeCustomizations.html new file mode 100644 index 00000000..c111558c --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasDerivedGraphQLTypeCustomizations.html @@ -0,0 +1,399 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Mixins::HasDerivedGraphQLTypeCustomizations + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Mixins::HasDerivedGraphQLTypeCustomizations + + + +

+
+ + + + + + + + + +
+
Included in:
+
SchemaElements::EnumType, SchemaElements::ScalarType, SchemaElements::TypeWithSubfields, SchemaElements::UnionType
+
+ + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_derived_graphql_type_customizations.rb
+
+ +
+ +

Overview

+
+

Mixin that supports the customization of derived GraphQL types.

+ +

For each type you define, ElasticGraph generates a number of derived GraphQL types that are needed to facilitate the ElasticGraph +Query API. Methods in this module can be used to customize those derived GraphQL types.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #customize_derived_type_fields(type_name, *field_names, &customization_block) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Registers a customization block for the named fields on the named derived GraphQL type. The provided block will get run on the +named fields of the named derived GraphQL type, allowing them to be customized.

+ + +
+
+
+ +
+

Examples:

+ + +

Customize named fields of a derived GraphQL type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID!"
+    t.index "campaigns"
+
+    t.customize_derived_type_fields "CampaignConnection", "pageInfo", "totalEdgeCount" do |dt|
+      # Add a `@deprecated` directive to `CampaignConnection.pageInfo` and `CampaignConnection.totalEdgeCount`.
+      dt.directive "deprecated"
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + type_name + + + (String) + + + + — +

    name of the derived type containing fields you want to customize

    +
    + +
  • + +
  • + + field_names + + + (Array<String>) + + + + — +

    names of the fields on the derived types that you wish to customize

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+77
+78
+79
+80
+81
+82
+83
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_derived_graphql_type_customizations.rb', line 77
+
+def customize_derived_type_fields(type_name, *field_names, &customization_block)
+  customizations_by_field = derived_field_customizations_by_type_and_field_name[type_name]
+
+  field_names.each do |field_name|
+    customizations_by_field[field_name] << customization_block
+  end
+end
+
+
+ +
+

+ + #customize_derived_types(*type_names, &customization_block) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Registers a customization block for the named derived graphql types. The provided block will get run on the named derived GraphQL +types, allowing them to be customized.

+ + +
+
+
+ +
+

Examples:

+ + +

Customize named derived GraphQL types

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID!"
+    t.index "campaigns"
+
+    t.customize_derived_types "CampaignFilterInput", "CampaignSortOrderInput" do |dt|
+      # Add a `@deprecated` directive to two specific derived types.
+      dt.directive "deprecated"
+    end
+  end
+end
+ + +

Customize all derived GraphQL types

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID!"
+    t.index "campaigns"
+
+    t.customize_derived_types :all do |dt|
+      # Add a `@deprecated` directive to all derived types.
+      dt.directive "deprecated"
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + type_names + + + (Array<String, :all>) + + + + — +

    names of the derived types to customize, or :all to customize all derived types

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+48
+49
+50
+51
+52
+53
+54
+55
+56
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_derived_graphql_type_customizations.rb', line 48
+
+def customize_derived_types(*type_names, &customization_block)
+  if type_names.include?(:all)
+    derived_type_customizations_for_all_types << customization_block
+  else
+    type_names.each do |t|
+      derived_type_customizations_by_name[t.to_s] << customization_block
+    end
+  end
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasDirectives.html b/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasDirectives.html new file mode 100644 index 00000000..4a201d64 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasDirectives.html @@ -0,0 +1,481 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Mixins::HasDirectives + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Mixins::HasDirectives + + + +

+
+ + + + + + + + + +
+
Included in:
+
SchemaElements::Argument, SchemaElements::EnumType, SchemaElements::EnumValue, SchemaElements::Field, SchemaElements::ScalarType, SchemaElements::TypeWithSubfields, SchemaElements::UnionType
+
+ + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_directives.rb
+
+ +
+ +

Overview

+
+

Provides support for annotating any schema element with a GraphQL directive.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #directive(name, arguments = {}) ⇒ void + + + + + +

+
+ +
+ Note: +

If you’re using a custom directive rather than a standard GraphQL directive like @deprecated, you’ll also need to use +API#raw_sdl to define the custom directive.

+
+
+ +

This method returns an undefined value.

Adds a GraphQL directive to the current schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Add a standard GraphQL directive to a field

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID" do |f|
+      f.directive "deprecated"
+    end
+  end
+end
+ + +

Define a custom GraphQL directive and add it to an object type

+
+ +
ElasticGraph.define_schema do |schema|
+  # Define a directive we can use to annotate what system a data type comes from.
+  schema.raw_sdl "directive @sourcedFrom(system: String!) on OBJECT"
+
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID"
+    t.directive "sourcedFrom", system: "campaigns"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    name of the directive

    +
    + +
  • + +
  • + + arguments + + + (Hash<String, Object>) + + + (defaults to: {}) + + + — +

    arguments for the directive

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+42
+43
+44
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_directives.rb', line 42
+
+def directive(name, arguments = {})
+  directives << schema_def_state.factory.new_directive(name, arguments)
+end
+
+
+ +
+

+ + #directivesArray<SchemaElements::Directive> + + + + + +

+
+

Returns directives attached to this schema element.

+ + +
+
+
+ +

Returns:

+ + +
+ + + + +
+
+
+
+59
+60
+61
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_directives.rb', line 59
+
+def directives
+  @directives ||= []
+end
+
+
+ +
+

+ + #directives_sdl(suffix_with: "", prefix_with: "") ⇒ String + + + + + +

+
+

+ This method is part of a private API. + You should avoid using this method if possible, as it may be removed or be changed in the future. +

+

Helper method designed for use by including classes to get the formatted directive SDL.

+ + +
+
+
+

Parameters:

+
    + +
  • + + suffix_with + + + (String) + + + (defaults to: "") + + + — +

    suffix to add on the end of the SDL

    +
    + +
  • + +
  • + + prefix_with + + + (String) + + + (defaults to: "") + + + — +

    prefix to add to the beginning of the SDL

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    SDL string for the directives

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+52
+53
+54
+55
+56
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_directives.rb', line 52
+
+def directives_sdl(suffix_with: "", prefix_with: "")
+  sdl = directives.map(&:to_sdl).join(" ")
+  return sdl if sdl.empty?
+  prefix_with + sdl + suffix_with
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasDocumentation.html b/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasDocumentation.html new file mode 100644 index 00000000..7cdf2511 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasDocumentation.html @@ -0,0 +1,623 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Mixins::HasDocumentation + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Mixins::HasDocumentation + + + +

+
+ + + + + + + + + +
+
Included in:
+
SchemaElements::Argument, SchemaElements::EnumType, SchemaElements::EnumValue, SchemaElements::Field, SchemaElements::ScalarType, SchemaElements::TypeWithSubfields, SchemaElements::UnionType
+
+ + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_documentation.rb
+
+ +
+ +

Overview

+
+

Supports GraphQL documentation.

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + + +
+

Instance Attribute Details

+ + + +
+

+ + #doc_commentString? + + + + + +

+
+

Returns current documentation string for the schema element.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String, nil) + + + + — +

    current documentation string for the schema element

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+17
+18
+19
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_documentation.rb', line 17
+
+def doc_comment
+  @doc_comment
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #append_to_documentation(comment) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Appends some additional documentation to the existing documentation string.

+ + +
+
+
+

Parameters:

+
    + +
  • + + comment + + + (String) + + + + — +

    additional documentation

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+46
+47
+48
+49
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_documentation.rb', line 46
+
+def append_to_documentation(comment)
+  new_documentation = doc_comment ? "#{doc_comment}\n\n#{comment}" : comment
+  documentation(new_documentation)
+end
+
+
+ +
+

+ + #derived_documentation(intro, outro = nil) ⇒ String + + + + + +

+
+

Generates a documentation string that is derived from the schema elements existing documentation.

+ + +
+
+
+

Parameters:

+
    + +
  • + + intro + + + (String) + + + + — +

    string that goes before the schema element’s existing documentation

    +
    + +
  • + +
  • + + outro + + + (String, nil) + + + (defaults to: nil) + + + — +

    string that goes after the schema element’s existing documentation

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (String) + + + +
  • + +
+ +
+ + + + +
+
+
+
+64
+65
+66
+67
+68
+69
+70
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_documentation.rb', line 64
+
+def derived_documentation(intro, outro = nil)
+  outro &&= "\n\n#{outro}."
+  return "#{intro}.#{outro}" unless doc_comment
+
+  quoted_doc = doc_comment.split("\n").map { |line| "> #{line}" }.join("\n")
+  "#{intro}:\n\n#{quoted_doc}#{outro}"
+end
+
+
+ +
+

+ + #documentation(comment) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Sets the documentation of the schema element.

+ + +
+
+
+ +
+

Examples:

+ + +

Define documentation on an object type and on a field

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.documentation "A marketing campaign."
+
+    t.field "id", "ID" do |f|
+      f.documentation <<~EOS
+        The identifier of the campaign.
+
+        Note: this is randomly generated.
+      EOS
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + comment + + + (String) + + + + — +

    the documentation string

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+38
+39
+40
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_documentation.rb', line 38
+
+def documentation(comment)
+  self.doc_comment = comment
+end
+
+
+ +
+

+ + #formatted_documentationString + + + + + +

+
+

Formats the documentation using GraphQL SDL syntax.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    formatted documentation string

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+54
+55
+56
+57
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_documentation.rb', line 54
+
+def formatted_documentation
+  return nil unless (comment = doc_comment)
+  %("""\n#{comment.chomp}\n"""\n)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasIndices.html b/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasIndices.html new file mode 100644 index 00000000..14c35a00 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasIndices.html @@ -0,0 +1,1002 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Mixins::HasIndices + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Mixins::HasIndices + + + +

+
+ + + + + + + + + +
+
Included in:
+
SchemaElements::InterfaceType, SchemaElements::ObjectType, SchemaElements::UnionType
+
+ + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_indices.rb
+
+ +
+ +

Overview

+
+

Provides APIs for defining datastore indices.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #derive_indexed_type_fields(name, from_id:, route_with: nil, rollover_with: nil) {|Indexing::DerivedIndexedType| ... } ⇒ void + + + + + +

+
+

This method returns an undefined value.

Configures the ElasticGraph indexer to derive another type from this indexed type, using the from_id field as +the source of the id of the derived type, and the provided block for the definitions of the derived fields.

+ + +
+
+
+ +
+

Examples:

+ + +

Derive a Course type from StudentCourseEnrollment events

+
+ +
ElasticGraph.define_schema do |schema|
+  # `StudentCourseEnrollment` is a directly indexed type.
+  schema.object_type "StudentCourseEnrollment" do |t|
+    t.field "id", "ID"
+    t.field "courseId", "ID"
+    t.field "courseName", "String"
+    t.field "studentName", "String"
+    t.field "courseStartDate", "Date"
+
+    t.index "student_course_enrollments"
+
+    # Here we define how the `Course` indexed type  is derived when we index `StudentCourseEnrollment` events.
+    t.derive_indexed_type_fields "Course", from_id: "courseId" do |derive|
+      # `derive` is an instance of `DerivedIndexedType`.
+      derive.immutable_value "name", from: "courseName"
+      derive.append_only_set "students", from: "studentName"
+      derive.min_value "firstOfferedDate", from: "courseStartDate"
+      derive.max_value "mostRecentlyOfferedDate", from: "courseStartDate"
+    end
+  end
+
+  # `Course` is an indexed type that is derived entirely from `StudentCourseEnrollment` events.
+  schema.object_type "Course" do |t|
+    t.field "id", "ID"
+    t.field "name", "String"
+    t.field "students", "[String!]!"
+    t.field "firstOfferedDate", "Date"
+    t.field "mostRecentlyOfferedDate", "Date"
+
+    t.index "courses"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    name of the derived type

    +
    + +
  • + +
  • + + from_id + + + (String) + + + + — +

    path to the source type field with id values for the derived type

    +
    + +
  • + +
  • + + route_with + + + (String, nil) + + + (defaults to: nil) + + + — +

    path to the source type field with values for shard routing on the derived type

    +
    + +
  • + +
  • + + rollover_with + + + (String, nil) + + + (defaults to: nil) + + + — +

    path to the source type field with values for index rollover on the derived type

    +
    + +
  • + +
+ +

Yields:

+ + +
+ + + + +
+
+
+
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_indices.rb', line 131
+
+def derive_indexed_type_fields(
+  name,
+  from_id:,
+  route_with: nil,
+  rollover_with: nil,
+  &block
+)
+  Indexing::DerivedIndexedType.new(
+    source_type: self,
+    destination_type_ref: schema_def_state.type_ref(name).to_final_form,
+    id_source: from_id,
+    routing_value_source: route_with,
+    rollover_timestamp_value_source: rollover_with,
+    &block
+  ).tap { |dit| derived_indexed_types << dit }
+end
+
+
+ +
+

+ + #derived_indexed_typesArray<Indexing::DerivedIndexedType> + + + + + +

+
+

Returns list of derived types for this source type.

+ + +
+
+
+ +

Returns:

+ + +
+ + + + +
+
+
+
+149
+150
+151
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_indices.rb', line 149
+
+def derived_indexed_types
+  @derived_indexed_types ||= []
+end
+
+
+ +
+

+ + #index(name, **settings) {|Indexing::Index| ... } ⇒ void + + + + + +

+
+ +
+ Note: +

Use #root_query_fields on indexed types to name the field that will be exposed on Query.

+
+
+ +
+ Note: +

Indexed types must also define an id field, which ElasticGraph will use as the primary key.

+
+
+ +
+ Note: +

Datastore index settings can also be defined (or overridden) in an environment-specific settings YAML file. Index settings +that you want to configure differently for different environments (such as index.number_of_shards—-production and staging +will probably need different numbers!) should be configured in the per-environment YAML configuration files rather than here.

+
+
+ +

This method returns an undefined value.

Converts the current type from being an embedded type (that is, a type that is embedded within another indexed type) to an +indexed type that resides in the named index definition. Indexed types are directly indexed into the datastore, and will be +queryable from the root Query type.

+ + +
+
+
+ +
+

Examples:

+ + +

Define a campaigns index

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID"
+
+    t.index(
+      "campaigns",
+      # Configure `index.refresh_interval`.
+      refresh_interval: "1s",
+      # Use `index.search` to log warnings for any search query that take more than five seconds.
+      search: {slowlog: {level: "WARN", threshold: {query: {warn: "5s"}}}}
+    ) do |i|
+      # The index can be customized further here.
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    name of the index. See the Elasticsearch docs +for restrictions.

    +
    + +
  • + +
  • + + settings + + + (Hash<Symbol, Object>) + + + + — +

    datastore index settings you want applied to every environment. See the Elasticsearch docs +for a list of valid settings, but be sure to omit the index. prefix here.

    +
    + +
  • + +
+ +

Yields:

+
    + +
  • + + + (Indexing::Index) + + + + — +

    the index, so it can be customized further

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+65
+66
+67
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_indices.rb', line 65
+
+def index(name, **settings, &block)
+  indices.replace([Indexing::Index.new(name, settings, schema_def_state, self, &block)])
+end
+
+
+ +
+

+ + #indexed?Boolean + + + + + +

+
+

Returns true if this type has an index.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + + — +

    true if this type has an index

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+77
+78
+79
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_indices.rb', line 77
+
+def indexed?
+  indices.any?
+end
+
+
+ +
+

+ + #plural_root_query_field_nameString + + + + + +

+
+

Returns the plural name of the entity; used for the root Query field that queries documents of this indexed type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    the plural name of the entity; used for the root Query field that queries documents of this indexed type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+207
+208
+209
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_indices.rb', line 207
+
+def plural_root_query_field_name
+  @plural_root_query_field_name || naively_pluralize_type_name(name)
+end
+
+
+ +
+

+ + #root_query_fields(plural:, singular: nil) {|SchemaElements::Field| ... } ⇒ void + + + + + +

+
+

This method returns an undefined value.

Determines what the root Query fields will be to query this indexed type. In addition, this method accepts a block, which you +can use to customize the root query field (such as adding a GraphQL directive to it).

+ + +
+
+
+ +
+

Examples:

+ + +

Set plural and singular names

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Person" do |t|
+    t.field "id", "ID"
+
+    # Results in `Query.people` and `Query.personAggregations`.
+    t.root_query_fields plural: "people", singular: "person"
+
+    t.index "people"
+  end
+end
+ + +

Customize Query fields

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Person" do |t|
+    t.field "id", "ID"
+
+    t.root_query_fields plural: "people", singular: "person" do |f|
+      # Marks `Query.people` and `Query.personAggregations` as deprecated.
+      f.directive "deprecated"
+    end
+
+    t.index "people"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + plural + + + (String) + + + + — +

    the plural name of the entity; used for the root Query field that queries documents of this indexed type

    +
    + +
  • + +
  • + + singular + + + (String, nil) + + + (defaults to: nil) + + + — +

    the singular name of the entity; used for the root Query field (with an Aggregations suffix) that +queries aggregations of this indexed type. If not provided, will derive it from the type name (e.g. converting it to camelCase +or snake_case, depending on configuration).

    +
    + +
  • + +
+ +

Yields:

+
    + +
  • + + + (SchemaElements::Field) + + + + — +

    field on the root Query type used to query this indexed type, to support customization

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+200
+201
+202
+203
+204
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_indices.rb', line 200
+
+def root_query_fields(plural:, singular: nil, &customization_block)
+  @plural_root_query_field_name = plural
+  @singular_root_query_field_name = singular
+  @root_query_fields_customizations = customization_block
+end
+
+
+ +
+

+ + #singular_root_query_field_nameString + + + + + +

+
+

Returns the singular name of the entity; used for the root Query field (with an Aggregations suffix) that queries +aggregations of this indexed type. If not provided, will derive it from the type name (e.g. converting it to camelCase or +snake_case, depending on configuration).

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    the singular name of the entity; used for the root Query field (with an Aggregations suffix) that queries +aggregations of this indexed type. If not provided, will derive it from the type name (e.g. converting it to camelCase or +snake_case, depending on configuration).

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+214
+215
+216
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_indices.rb', line 214
+
+def singular_root_query_field_name
+  @singular_root_query_field_name || to_field_name(name)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasTypeInfo.html b/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasTypeInfo.html new file mode 100644 index 00000000..7a5fc293 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Mixins/HasTypeInfo.html @@ -0,0 +1,662 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Mixins::HasTypeInfo + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Mixins::HasTypeInfo + + + +

+
+ + + + + + + + + +
+
Included in:
+
SchemaElements::Field, SchemaElements::ScalarType, SchemaElements::TypeWithSubfields
+
+ + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_type_info.rb
+
+ +
+ +

Overview

+
+

Mixin used to specify non-GraphQL type info (datastore index and JSON schema type info). +Exists as a mixin so we can apply the same consistent API to every place we need to use this. +Currently it’s used in 3 places:

+ + + + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
CUSTOMIZABLE_DATASTORE_PARAMS = +
+
+

Set of mapping parameters that it makes sense to allow customization of, based on +the Elasticsearch docs.

+ + +
+
+
+ + +
+
+
Set[
+  :analyzer,
+  :eager_global_ordinals,
+  :enabled,
+  :fields,
+  :format,
+  :index,
+  :meta, # not actually in the doc above. Added to support some `index_configurator` tests on 7.9+.
+  :norms,
+  :null_value,
+  :search_analyzer,
+  :type,
+]
+ +
+ + + + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #json_schema(**options) ⇒ void + + + + + +

+
+ +
+ Note: +

We recommend using JSON schema validations in a limited fashion. Validations that are appropriate to apply when data is +entering the system-of-record are often not appropriate on a secondary index like ElasticGraph. Events that violate a JSON +schema validation will fail to index (typically they will be sent to the dead letter queue and page an oncall engineer). If an +ElasticGraph instance is meant to contain all the data of some source system, you probably don’t want it applying stricter +validations than the source system itself has. We recommend limiting your JSON schema validations to situations where +violations would prevent ElasticGraph from operating correctly.

+
+
+ +

This method returns an undefined value.

Defines the JSON schema validations for this field or type. Validations +defined here will be included in the generated json_schemas.yaml artifact, which is used by the ElasticGraph indexer to +validate events before indexing their data in the datastore. In addition, the publisher may use json_schemas.yaml for code +generation and to apply validation before publishing an event to ElasticGraph.

+ +

Can be called multiple times; each time, the options will be merged into the existing options.

+ +

This is required on a SchemaElements::ScalarType (since we don’t know how a custom scalar type should be represented in +JSON!). On a SchemaElements::Field, this is optional, but can be used to make the JSON schema validation stricter then it +would otherwise be. For example, you could use json_schema maxLength: 30 on a String field to limit the length.

+ +

You can use any of the JSON schema validation keywords here. In addition, nullable: false is supported to configure the +generated JSON schema to disallow null values for the field. Note that if you define a field with a non-nullable GraphQL type +(e.g. Int!), the JSON schema will automatically disallow nulls. However, as explained in the +SchemaElements::TypeWithSubfields#field documentation, we generally recommend against defining non-nullable GraphQL fields. +json_schema nullable: false will disallow null values from being indexed, while still keeping the field nullable in the +GraphQL schema. If you think you might want to make a field non-nullable in the GraphQL schema some day, it’s a good idea to use +json_schema nullable: false now to ensure every indexed record has a non-null value for the field.

+ + +
+
+
+ +
+

Examples:

+ + +

Define the JSON schema validations of a custom scalar type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.scalar_type "URL" do |t|
+    t.mapping type: "keyword"
+
+    # JSON schema has a built-in URI format validator:
+    # https://json-schema.org/understanding-json-schema/reference/string.html#resource-identifiers
+    t.json_schema type: "string", format: "uri"
+  end
+end
+ + +

Define additional validations on a field

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Card" do |t|
+    t.field "id", "ID!"
+
+    t.field "expYear", "Int" do |f|
+      # Use JSON schema to ensure the publisher is sending us 4 digit years, not 2 digit years.
+      f.json_schema minimum: 2000, maximum: 2099
+    end
+
+    t.field "expMonth", "Int" do |f|
+      f.json_schema minimum: 1, maximum: 12
+    end
+
+    t.index "cards"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + options + + + (Hash<Symbol, Object>) + + + + — +

    JSON schema options

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+169
+170
+171
+172
+173
+174
+175
+176
+177
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_type_info.rb', line 169
+
+def json_schema(**options)
+  validatable_json_schema = Support::HashUtil.stringify_keys(options)
+
+  if (error_msg = JSONSchema.strict_meta_schema_validator.validate_with_error_message(validatable_json_schema))
+    raise Errors::SchemaError, "Invalid JSON schema options set on #{self}:\n\n#{error_msg}"
+  end
+
+  json_schema_options.update(options)
+end
+
+
+ +
+

+ + #json_schema_optionsHash<Symbol, Object> + + + + + +

+
+

Returns JSON schema options.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<Symbol, Object>) + + + + — +

    JSON schema options

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+28
+29
+30
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_type_info.rb', line 28
+
+def json_schema_options
+  @json_schema_options ||= {}
+end
+
+
+ +
+

+ + #mapping(**options) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Defines the Elasticsearch/OpenSearch field mapping type +and mapping parameters for a field or type. +The options passed here will be included in the generated datastore_config.yaml artifact that ElasticGraph uses to configure +Elasticsearch/OpenSearch.

+ +

Can be called multiple times; each time, the options will be merged into the existing options.

+ +

This is required on a SchemaElements::ScalarType; without it, ElasticGraph would have no way to know how the datatype should be +indexed in the datastore.

+ +

On a SchemaElements::Field, this can be used to customize how a field is indexed. For example, String fields are normally +indexed as keywords; to instead index a String +field for full text search, you’d need to configure mapping type: "text".

+ +

On a SchemaElements::ObjectType, this can be used to use a specific Elasticsearch/OpenSearch data type for something that is +modeled as an object in GraphQL. For example, we use it for the GeoLocation type so they get indexed in Elasticsearch using the +geo_point type.

+ + +
+
+
+ +
+

Examples:

+ + +

Define the mapping of a custom scalar type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.scalar_type "URL" do |t|
+    t.mapping type: "keyword"
+    t.json_schema type: "string", format: "uri"
+  end
+end
+ + +

Customize the mapping of a field

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Card" do |t|
+    t.field "id", "ID!"
+
+    t.field "cardholderName", "String" do |f|
+      # index this field for full text search
+      f.mapping type: "text"
+    end
+
+    t.field "expYear", "Int" do |f|
+      # Use a smaller numeric type to save space in the datastore
+      f.mapping type: "short"
+      f.json_schema minimum: 2000, maximum: 2099
+    end
+
+    t.field "expMonth", "Int" do |f|
+      # Use a smaller numeric type to save space in the datastore
+      f.mapping type: "byte"
+      f.json_schema minimum: 1, maximum: 12
+    end
+
+    t.index "cards"
+  end
+end
+ +
+

Parameters:

+ + + +
+ + + + +
+
+
+
+102
+103
+104
+105
+106
+107
+108
+109
+110
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_type_info.rb', line 102
+
+def mapping(**options)
+  param_diff = (options.keys.to_set - CUSTOMIZABLE_DATASTORE_PARAMS).to_a
+
+  unless param_diff.empty?
+    raise Errors::SchemaError, "Some configured mapping overrides are unsupported: #{param_diff.inspect}"
+  end
+
+  mapping_options.update(options)
+end
+
+
+ +
+

+ + #mapping_optionsHash<Symbol, Object> + + + + + +

+
+

Returns datastore mapping options.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<Symbol, Object>) + + + + — +

    datastore mapping options

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+23
+24
+25
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/has_type_info.rb', line 23
+
+def mapping_options
+  @mapping_options ||= {}
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Mixins/ImplementsInterfaces.html b/docs/main/ElasticGraph/SchemaDefinition/Mixins/ImplementsInterfaces.html new file mode 100644 index 00000000..04546f7d --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Mixins/ImplementsInterfaces.html @@ -0,0 +1,470 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Mixins::ImplementsInterfaces + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Mixins::ImplementsInterfaces + + + +

+
+ + + + + + + + + +
+
Included in:
+
SchemaElements::InterfaceType, SchemaElements::ObjectType
+
+ + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb
+
+ +
+ +

Overview

+
+

Mixin for types that can implement interfaces (SchemaElements::ObjectType and SchemaElements::InterfaceType).

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #implemented_interfacesArray<SchemaElements::TypeReference> + + + + + +

+
+

Returns list of type references for the interface types implemented by this type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Array<SchemaElements::TypeReference>) + + + + — +

    list of type references for the interface types implemented by this type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+54
+55
+56
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb', line 54
+
+def implemented_interfaces
+  @implemented_interfaces ||= []
+end
+
+
+ +
+

+ + #implements(*interface_names) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Declares that the current type implements the specified interface, making the current type a subtype of the interface. The +current type must define all of the fields of the named interface, with the exact same field types.

+ + +
+
+
+ +
+

Examples:

+ + +

Implement an interface

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.interface_type "Athlete" do |t|
+    t.field "name", "String"
+    t.field "team", "String"
+  end
+
+  schema.object_type "BaseballPlayer" do |t|
+    t.implements "Athlete"
+    t.field "name", "String"
+    t.field "team", "String"
+    t.field "battingAvg", "Float"
+  end
+
+  schema.object_type "BasketballPlayer" do |t|
+    t.implements "Athlete"
+    t.field "name", "String"
+    t.field "team", "String"
+    t.field "pointsPerGame", "Float"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + interface_names + + + (Array<String>) + + + + — +

    names of interface types implemented by this type

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+43
+44
+45
+46
+47
+48
+49
+50
+51
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb', line 43
+
+def implements(*interface_names)
+  interface_refs = interface_names.map do |interface_name|
+    schema_def_state.type_ref(interface_name).to_final_form.tap do |interface_ref|
+      schema_def_state.implementations_by_interface_ref[interface_ref] << self
+    end
+  end
+
+  implemented_interfaces.concat(interface_refs)
+end
+
+
+ +
+

+ + #to_sdl {|SchemaElements::Argument| ... } ⇒ String + + + + + +

+
+

Returns SDL string of the type.

+ + +
+
+
+ +

Yields:

+ +

Yield Returns:

+
    + +
  • + + + (Boolean) + + + + — +

    whether or not to include the argument in the generated GraphQL SDL

    +
    + +
  • + +
+

Returns:

+
    + +
  • + + + (String) + + + + — +

    SDL string of the type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb', line 109
+
+def to_sdl(&field_arg_selector)
+  name_section =
+    if implemented_interfaces.empty?
+      name
+    else
+      "#{name} implements #{implemented_interfaces.join(" & ")}"
+    end
+
+  generate_sdl(name_section: name_section, &field_arg_selector)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Mixins/SupportsDefaultValue.html b/docs/main/ElasticGraph/SchemaDefinition/Mixins/SupportsDefaultValue.html new file mode 100644 index 00000000..944347f7 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Mixins/SupportsDefaultValue.html @@ -0,0 +1,298 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Mixins::SupportsDefaultValue + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Mixins::SupportsDefaultValue + + + +

+
+ + + + + + + + + +
+
Included in:
+
SchemaElements::Argument
+
+ + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/supports_default_value.rb
+
+ +
+ +

Overview

+
+

A mixin designed to be included in a schema element class that supports default values. +Designed to be prepended so that it can hook into initialize.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #default(default_value) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Used to specify the default value for this field or argument.

+ + +
+
+
+

Parameters:

+
    + +
  • + + default_value + + + (Object) + + + + — +

    default value for this field or argument

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+27
+28
+29
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/supports_default_value.rb', line 27
+
+def default(default_value)
+  @default_value = default_value
+end
+
+
+ +
+

+ + #default_value_sdlString + + + + + +

+
+

Generates SDL for the default value. Suitable for inclusion in the schema elememnts #to_sdl.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + +
  • + +
+ +
+ + + + +
+
+
+
+34
+35
+36
+37
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/supports_default_value.rb', line 34
+
+def default_value_sdl
+  return nil if @default_value == NO_DEFAULT_PROVIDED
+  " = #{Support::GraphQLFormatter.serialize(@default_value)}"
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Mixins/VerifiesGraphQLName.html b/docs/main/ElasticGraph/SchemaDefinition/Mixins/VerifiesGraphQLName.html new file mode 100644 index 00000000..165a3d44 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Mixins/VerifiesGraphQLName.html @@ -0,0 +1,247 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::Mixins::VerifiesGraphQLName + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::Mixins::VerifiesGraphQLName + + + +

+
+ + + + + + + + + +
+
Included in:
+
SchemaElements::Argument, SchemaElements::Directive, SchemaElements::EnumType, SchemaElements::EnumValue, SchemaElements::Field, SchemaElements::ScalarType, SchemaElements::TypeWithSubfields, SchemaElements::UnionType
+
+ + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/verifies_graphql_name.rb
+
+ +
+ +

Overview

+
+ +
+ Note: +

This mixin is designed to be used via prepend, so it can add a constructor override that enforces

+
+
+ +

Used to verify the validity of the name of GraphQL schema elements.

+ +

the GraphQL name pattern as the object is built.

+ + +
+
+
+ + +
+ + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .verify_name!(name) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Raises if the provided name is invalid.

+ + +
+
+
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    name of GraphQL schema element

    +
    + +
  • + +
+ +

Raises:

+
    + +
  • + + + (Errors::InvalidGraphQLNameError) + + + + — +

    if the name is invalid

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+31
+32
+33
+34
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/mixins/verifies_graphql_name.rb', line 31
+
+def self.verify_name!(name)
+  return if GRAPHQL_NAME_PATTERN.match?(name)
+  raise Errors::InvalidGraphQLNameError, "Not a valid GraphQL name: `#{name}`. #{GRAPHQL_NAME_VALIDITY_DESCRIPTION}"
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/RakeTasks.html b/docs/main/ElasticGraph/SchemaDefinition/RakeTasks.html new file mode 100644 index 00000000..a2c14bf8 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/RakeTasks.html @@ -0,0 +1,556 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::RakeTasks + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::RakeTasks + + + +

+
+ +
+
Inherits:
+
+ Rake::TaskLib + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/rake_tasks.rb
+
+ +
+ +

Overview

+
+ +
+ Note: +

Local::RakeTasks wraps this and provides additional functionality. Most users will not need to interact with +this class directly.

+
+
+ +

Defines rake tasks for managing artifacts generated from a schema definition.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + +
+

Constructor Details

+ +
+

+ + #initialize(index_document_sizes:, path_to_schema:, schema_artifacts_directory:, schema_element_name_form:, schema_element_name_overrides: {}, derived_type_name_formats: {}, type_name_overrides: {}, enum_value_overrides_by_type: {}, extension_modules: [], enforce_json_schema_version: true, output: $stdout) ⇒ RakeTasks + + + + + +

+
+

Returns a new instance of RakeTasks.

+ + +
+
+
+ +
+

Examples:

+ + +

Minimal setup with defaults

+
+ +
ElasticGraph::SchemaDefinition::RakeTasks.new(
+  index_document_sizes: false,
+  path_to_schema: "config/schema.rb",
+  schema_artifacts_directory: "config/schema/artifacts",
+  schema_element_name_form: :camelCase
+)
+ + +

Spell out the full names of the gt/gte/lt/lte filter operators

+
+ +
ElasticGraph::SchemaDefinition::RakeTasks.new(
+  index_document_sizes: false,
+  path_to_schema: "config/schema.rb",
+  schema_artifacts_directory: "config/schema/artifacts",
+  schema_element_name_form: :camelCase,
+  schema_element_name_overrides: {
+    gt: "greaterThan",
+    gte: "greaterThanOrEqualTo",
+    lt: "lessThan",
+    lte: "lessThanOrEqualTo"
+  }
+)
+ + +

Change the AggregatedValues type suffix to Metrics

+
+ +
ElasticGraph::SchemaDefinition::RakeTasks.new(
+  index_document_sizes: false,
+  path_to_schema: "config/schema.rb",
+  schema_artifacts_directory: "config/schema/artifacts",
+  schema_element_name_form: :camelCase,
+  derived_type_name_formats: {AggregatedValues: "Metrics"}
+)
+ + +

Rename JsonSafeLong to BigInt

+
+ +
ElasticGraph::SchemaDefinition::RakeTasks.new(
+  index_document_sizes: false,
+  path_to_schema: "config/schema.rb",
+  schema_artifacts_directory: "config/schema/artifacts",
+  schema_element_name_form: :camelCase,
+  type_name_overrides: {JsonSafeLong: "BigInt"}
+)
+ + +

Shorten the names of the DayOfWeek enum values

+
+ +
ElasticGraph::SchemaDefinition::RakeTasks.new(
+  index_document_sizes: false,
+  path_to_schema: "config/schema.rb",
+  schema_artifacts_directory: "config/schema/artifacts",
+  schema_element_name_form: :camelCase,
+  enum_value_overrides_by_type: {
+    DayOfWeek: {
+      MONDAY: "MON",
+      TUESDAY: "TUE",
+      WEDNESDAY: "WED",
+      THURSDAY: "THU",
+      FRIDAY: "FRI",
+      SATURDAY: "SAT",
+      SUNDAY: "SUN"
+    }
+  }
+)
+ +
+

Parameters:

+
    + +
  • + + index_document_sizes + + + (Boolean) + + + + — +

    When enabled, ElasticGraph will configure the index mappings so that the datastore indexes a +_size field in each document. ElasticGraph itself does not do anything with this field, but it will be available for your use +in any direct queries (e.g. via Kibana). Important note: this requires the mapper-size +plugin to be installed on your datastore cluster. +You are responsible for ensuring that is installed if you enable this feature. If you enable this and the plugin is not +installed, you will get errors!

    +
    + +
  • + +
  • + + path_to_schema + + + (String, Pathname) + + + + — +

    path to the main (or only) schema definition file

    +
    + +
  • + +
  • + + schema_artifacts_directory + + + (String, Pathname) + + + + — +

    Directory to dump the schema artifacts in

    +
    + +
  • + +
  • + + schema_element_name_form + + + (:camelCase, :snake_case) + + + + — +

    the form of names for schema elements (fields, arguments, directives) +generated by ElasticGraph.

    +
    + +
  • + +
  • + + schema_element_name_overrides + + + (Hash<Symbol, String>) + + + (defaults to: {}) + + + — +

    overrides for specific names of schema elements (fields, arguments, +directives) generated by ElasticGraph. For example, to rename the gt filter field to greaterThan, pass {gt: "greaterThan"}.

    +
    + +
  • + +
  • + + derived_type_name_formats + + + (Hash<Symbol, String>) + + + (defaults to: {}) + + + — +

    overrides for the naming formats used by ElasticGraph for derived GraphQL +type names. For example, to use Metrics instead of AggregatedValues as the suffix for the generated types supporting +getting aggregated metrid values, pass {AggregatedValues: "%{base}Metrics"}. See SchemaElements::TypeNamer::DEFAULT_FORMATS +for the available formats.

    +
    + +
  • + +
  • + + type_name_overrides + + + (Hash<Symbol, String>) + + + (defaults to: {}) + + + — +

    overrides for the names of specific GraphQL types. For example, to rename the +DateTime scalar to Timestamp, pass {DateTime: "Timestamp}.

    +
    + +
  • + +
  • + + enum_value_overrides_by_type + + + (Hash<Symbol, Hash<Symbol, String>>) + + + (defaults to: {}) + + + — +

    overrides for the names of specific enum values for +specific enum types. For example, to rename the DayOfWeek.MONDAY enum to DayOfWeek.MON, pass {DayOfWeek: {MONDAY: "MON"}}.

    +
    + +
  • + +
  • + + extension_modules + + + (Array<Module>) + + + (defaults to: []) + + + — +

    List of Ruby modules to extend onto the SchemaDefinition::API instance. Designed to +support ElasticGraph extension gems (such as elasticgraph-apollo).

    +
    + +
  • + +
  • + + enforce_json_schema_version + + + (Boolean) + + + (defaults to: true) + + + — +

    Whether or not to enforce the requirement that the JSON schema version is incremented +every time dumping the JSON schemas results in a changed artifact. Generally speaking, you will want this to be true for any +ElasticGraph application that is in production as the versioning of JSON schemas is what supports safe schema evolution as it +allows ElasticGraph to identify which version of the JSON schema the publishing system was operating on when it published an +event. It can be useful to set it to false before your application is in production, as you do not want to be forced to bump +the version after every single schema change while you are building an initial prototype.

    +
    + +
  • + +
  • + + output + + + (IO) + + + (defaults to: $stdout) + + + — +

    used for printing task output

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/rake_tasks.rb', line 110
+
+def initialize(
+  index_document_sizes:,
+  path_to_schema:,
+  schema_artifacts_directory:,
+  schema_element_name_form:,
+  schema_element_name_overrides: {},
+  derived_type_name_formats: {},
+  type_name_overrides: {},
+  enum_value_overrides_by_type: {},
+  extension_modules: [],
+  enforce_json_schema_version: true,
+  output: $stdout
+)
+  @schema_element_names = SchemaArtifacts::RuntimeMetadata::SchemaElementNames.new(
+    form: schema_element_name_form,
+    overrides: schema_element_name_overrides
+  )
+
+  @derived_type_name_formats = derived_type_name_formats
+  @type_name_overrides = type_name_overrides
+  @enum_value_overrides_by_type = enum_value_overrides_by_type
+  @index_document_sizes = index_document_sizes
+  @path_to_schema = path_to_schema
+  @schema_artifacts_directory = schema_artifacts_directory
+  @enforce_json_schema_version = enforce_json_schema_version
+  @extension_modules = extension_modules
+  @output = output
+
+  define_tasks
+end
+
+
+ +
+ + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/Results.html b/docs/main/ElasticGraph/SchemaDefinition/Results.html new file mode 100644 index 00000000..9bcf88b6 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/Results.html @@ -0,0 +1,688 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::Results + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::Results + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + +
+
Includes:
+
SchemaArtifacts::ArtifactsHelperMethods
+
+ + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/results.rb
+
+ +
+ +

Overview

+
+ +
+ Note: +

This class is designed to implement the same interface as ElasticGraph::SchemaArtifacts::FromDisk, so that it can be used

+
+
+ +

Provides the results of defining a schema.

+ +

interchangeably with schema artifacts loaded from disk. This allows the artifacts to be used in tests without having to dump them or +reload them.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + + +
+

Instance Method Details

+ + +
+

+ + #available_json_schema_versionsSet<Integer> + + + + + +

+
+

Returns set of available JSON schema versions.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Set<Integer>) + + + + — +

    set of available JSON schema versions

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+60
+61
+62
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/results.rb', line 60
+
+def available_json_schema_versions
+  @available_json_schema_versions ||= Set[latest_json_schema_version]
+end
+
+
+ +
+

+ + #datastore_configHash<String, Object> + + + + + +

+
+

Returns the Elasticsearch/OpenSearch configuration dumped as datastore_config.yaml.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, Object>) + + + + — +

    the Elasticsearch/OpenSearch configuration dumped as datastore_config.yaml

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+39
+40
+41
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/results.rb', line 39
+
+def datastore_config
+  @datastore_config ||= generate_datastore_config
+end
+
+
+ +
+

+ + #graphql_schema_stringString + + + + + +

+
+

Returns the generated GraphQL SDL schema string dumped as schema.graphql.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    the generated GraphQL SDL schema string dumped as schema.graphql

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+34
+35
+36
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/results.rb', line 34
+
+def graphql_schema_string
+  @graphql_schema_string ||= generate_sdl
+end
+
+
+ +
+

+ + #json_schemas_for(version) ⇒ Hash<String, Object> + + + + + +

+
+

Returns the JSON schema for the requested version, if available.

+ + +
+
+
+

Parameters:

+
    + +
  • + + version + + + (Integer) + + + + — +

    desired JSON schema version

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash<String, Object>) + + + + — +

    the JSON schema for the requested version, if available

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (Errors::NotFoundError) + + + + — +

    if the requested JSON schema version is not available

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+51
+52
+53
+54
+55
+56
+57
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/results.rb', line 51
+
+def json_schemas_for(version)
+  unless available_json_schema_versions.include?(version)
+    raise Errors::NotFoundError, "The requested json schema version (#{version}) is not available. Available versions: #{available_json_schema_versions.to_a.join(", ")}."
+  end
+
+  @latest_versioned_json_schema ||= (current_public_json_schema).json_schema
+end
+
+
+ +
+

+ + #latest_json_schema_versionHash<String, Object> + + + + + +

+
+

Returns the newly generated JSON schema.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, Object>) + + + + — +

    the newly generated JSON schema

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+65
+66
+67
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/results.rb', line 65
+
+def latest_json_schema_version
+  current_public_json_schema[JSON_SCHEMA_VERSION_KEY]
+end
+
+
+ +
+

+ + #runtime_metadataHash<String, Object> + + + + + +

+
+

Returns runtime metadata used by other parts of ElasticGraph and dumped as runtime_metadata.yaml.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, Object>) + + + + — +

    runtime metadata used by other parts of ElasticGraph and dumped as runtime_metadata.yaml

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+44
+45
+46
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/results.rb', line 44
+
+def 
+  @runtime_metadata ||= 
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements.html new file mode 100644 index 00000000..047c1799 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements.html @@ -0,0 +1,127 @@ + + + + + + + Module: ElasticGraph::SchemaDefinition::SchemaElements + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::SchemaDefinition::SchemaElements + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/argument.rb,
+ elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/directive.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field_path.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/input_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_namer.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/union_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/input_field.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/object_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field_source.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/relationship.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/built_in_types.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/interface_type.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_reference.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_value_namer.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/list_counts_state.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/deprecated_element.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/sub_aggregation_path.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/sort_order_enum_value.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/graphql_sdl_enumerator.rb,
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enums_for_indexed_types.rb
+
+
+ +
+ +

Overview

+
+

Namespace for classes which represent GraphQL schema elements.

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + + + Classes: Argument, BuiltInTypes, Directive, EnumType, EnumValue, Field, InterfaceType, ObjectType, Relationship, ScalarType, SortOrderEnumValue, TypeNamer, TypeWithSubfields, UnionType + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/Argument.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/Argument.html new file mode 100644 index 00000000..8ccc08e4 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/Argument.html @@ -0,0 +1,909 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::SchemaElements::Argument + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::SchemaElements::Argument + + + +

+
+ +
+
Inherits:
+
+ Struct + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + +
+
Includes:
+
Mixins::HasDirectives, Mixins::HasDocumentation, Mixins::SupportsDefaultValue, Mixins::VerifiesGraphQLName
+
+ + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/argument.rb
+
+ +
+ +

Overview

+
+

Represents a GraphQL argument.

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

Attributes included from Mixins::HasDocumentation

+

#doc_comment

+ + + +

+ Instance Method Summary + collapse +

+ + + + + + + + + + + + + +

Methods included from Mixins::HasDirectives

+

#directive, #directives, #directives_sdl

+ + + + + + + + + +

Methods included from Mixins::HasDocumentation

+

#append_to_documentation, #derived_documentation, #documentation, #formatted_documentation

+ + + + + + + + + +

Methods included from Mixins::VerifiesGraphQLName

+

verify_name!

+ + + + + + + + + +

Methods included from Mixins::SupportsDefaultValue

+

#default, #default_value_sdl

+ + +
+

Instance Attribute Details

+ + + +
+

+ + #nameString (readonly) + + + + + +

+
+

Returns name of the argument.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    name of the argument

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/argument.rb', line 30
+
+class Argument < Struct.new(:schema_def_state, :parent_field, :name, :original_value_type)
+  prepend Mixins::VerifiesGraphQLName
+  prepend Mixins::SupportsDefaultValue
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasReadableToSAndInspect.new { |a| "#{a.parent_field.parent_type.name}.#{a.parent_field.name}(#{a.name}: #{a.value_type})" }
+
+  # @return [String] GraphQL SDL form of the argument
+  def to_sdl
+    "#{formatted_documentation}#{name}: #{value_type}#{default_value_sdl}#{directives_sdl(prefix_with: " ")}"
+  end
+
+  # When the argument type is an enum, and we're configured with different naming for input vs output enums,
+  # we need to convert the value type to its input form. Note that this intentionally happens lazily (rather than
+  # doing this when `Argument` is instantiated), because the referenced type need not exist when the argument
+  # is defined, and we may not be able to figure out if it's an enum until the type has been defined. So, we
+  # apply this lazily.
+  #
+  # @return [TypeReference] the type of the argument
+  # @see #original_value_type
+  def value_type
+    original_value_type.to_final_form(as_input: true)
+  end
+end
+
+
+ + + +
+

+ + #original_value_typeTypeReference (readonly) + + + + + +

+
+

Returns type of the argument, as originally provided.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (TypeReference) + + + + — +

    type of the argument, as originally provided

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/argument.rb', line 30
+
+class Argument < Struct.new(:schema_def_state, :parent_field, :name, :original_value_type)
+  prepend Mixins::VerifiesGraphQLName
+  prepend Mixins::SupportsDefaultValue
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasReadableToSAndInspect.new { |a| "#{a.parent_field.parent_type.name}.#{a.parent_field.name}(#{a.name}: #{a.value_type})" }
+
+  # @return [String] GraphQL SDL form of the argument
+  def to_sdl
+    "#{formatted_documentation}#{name}: #{value_type}#{default_value_sdl}#{directives_sdl(prefix_with: " ")}"
+  end
+
+  # When the argument type is an enum, and we're configured with different naming for input vs output enums,
+  # we need to convert the value type to its input form. Note that this intentionally happens lazily (rather than
+  # doing this when `Argument` is instantiated), because the referenced type need not exist when the argument
+  # is defined, and we may not be able to figure out if it's an enum until the type has been defined. So, we
+  # apply this lazily.
+  #
+  # @return [TypeReference] the type of the argument
+  # @see #original_value_type
+  def value_type
+    original_value_type.to_final_form(as_input: true)
+  end
+end
+
+
+ + + +
+

+ + #parent_fieldField (readonly) + + + + + +

+
+

Returns field which has this argument.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Field) + + + + — +

    field which has this argument

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/argument.rb', line 30
+
+class Argument < Struct.new(:schema_def_state, :parent_field, :name, :original_value_type)
+  prepend Mixins::VerifiesGraphQLName
+  prepend Mixins::SupportsDefaultValue
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasReadableToSAndInspect.new { |a| "#{a.parent_field.parent_type.name}.#{a.parent_field.name}(#{a.name}: #{a.value_type})" }
+
+  # @return [String] GraphQL SDL form of the argument
+  def to_sdl
+    "#{formatted_documentation}#{name}: #{value_type}#{default_value_sdl}#{directives_sdl(prefix_with: " ")}"
+  end
+
+  # When the argument type is an enum, and we're configured with different naming for input vs output enums,
+  # we need to convert the value type to its input form. Note that this intentionally happens lazily (rather than
+  # doing this when `Argument` is instantiated), because the referenced type need not exist when the argument
+  # is defined, and we may not be able to figure out if it's an enum until the type has been defined. So, we
+  # apply this lazily.
+  #
+  # @return [TypeReference] the type of the argument
+  # @see #original_value_type
+  def value_type
+    original_value_type.to_final_form(as_input: true)
+  end
+end
+
+
+ + + +
+

+ + #schema_def_stateState (readonly) + + + + + +

+
+

Returns state of the schema.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (State) + + + + — +

    state of the schema

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/argument.rb', line 30
+
+class Argument < Struct.new(:schema_def_state, :parent_field, :name, :original_value_type)
+  prepend Mixins::VerifiesGraphQLName
+  prepend Mixins::SupportsDefaultValue
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasReadableToSAndInspect.new { |a| "#{a.parent_field.parent_type.name}.#{a.parent_field.name}(#{a.name}: #{a.value_type})" }
+
+  # @return [String] GraphQL SDL form of the argument
+  def to_sdl
+    "#{formatted_documentation}#{name}: #{value_type}#{default_value_sdl}#{directives_sdl(prefix_with: " ")}"
+  end
+
+  # When the argument type is an enum, and we're configured with different naming for input vs output enums,
+  # we need to convert the value type to its input form. Note that this intentionally happens lazily (rather than
+  # doing this when `Argument` is instantiated), because the referenced type need not exist when the argument
+  # is defined, and we may not be able to figure out if it's an enum until the type has been defined. So, we
+  # apply this lazily.
+  #
+  # @return [TypeReference] the type of the argument
+  # @see #original_value_type
+  def value_type
+    original_value_type.to_final_form(as_input: true)
+  end
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #to_sdlString + + + + + +

+
+

Returns GraphQL SDL form of the argument.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    GraphQL SDL form of the argument

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+38
+39
+40
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/argument.rb', line 38
+
+def to_sdl
+  "#{formatted_documentation}#{name}: #{value_type}#{default_value_sdl}#{directives_sdl(prefix_with: " ")}"
+end
+
+
+ +
+

+ + #value_typeTypeReference + + + + + +

+
+

When the argument type is an enum, and we’re configured with different naming for input vs output enums, +we need to convert the value type to its input form. Note that this intentionally happens lazily (rather than +doing this when Argument is instantiated), because the referenced type need not exist when the argument +is defined, and we may not be able to figure out if it’s an enum until the type has been defined. So, we +apply this lazily.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (TypeReference) + + + + — +

    the type of the argument

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+50
+51
+52
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/argument.rb', line 50
+
+def value_type
+  original_value_type.to_final_form(as_input: true)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/BuiltInTypes.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/BuiltInTypes.html new file mode 100644 index 00000000..03a65da6 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/BuiltInTypes.html @@ -0,0 +1,264 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::SchemaElements::BuiltInTypes + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::SchemaElements::BuiltInTypes + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/built_in_types.rb
+
+ +
+ +

Overview

+
+

Defines all built-in GraphQL types provided by ElasticGraph.

+ +

Scalar Types

+ +

Standard GraphQL Scalars

+ +

These are defined by the GraphQL spec.

+ +
+
Boolean
+
Represents true or false values.
+
Float
+
Represents signed double-precision fractional values as specified by +IEEE 754.
+
ID
+
Represents a unique identifier that is Base64 obfuscated. It is often used to +refetch an object or as key for a cache. The ID type appears in a JSON response as a +String; however, it is not intended to be human-readable. When expected as an input +type, any string (such as "VXNlci0xMA==") or integer (such as 4) input value will +be accepted as an ID.
+
Int
+
Represents non-fractional signed whole numeric values. Int can represent values between +-(2^31) and 2^31 - 1.
+
String
+
Represents textual data as UTF-8 character sequences. This type is most often used by +GraphQL to represent free-form human-readable text.
+
+ +

Additional ElasticGraph Scalars

+ +

ElasticGraph defines these additional scalar types.

+ +
+
Cursor
+
An opaque string value representing a specific location in a paginated connection type. +Returned cursors can be passed back in the next query via the before or after +arguments to continue paginating from that point.
+
Date
+
A date, represented as an ISO 8601 date string.
+
DateTime
+
A timestamp, represented as an ISO 8601 time string.
+
JsonSafeLong
+
A numeric type for large integer values that can serialize safely as JSON. While JSON +itself has no hard limit on the size of integers, the RFC-7159 spec mentions that +values outside of the range -9,007,199,254,740,991 (-(2^53) + 1) to 9,007,199,254,740,991 +(2^53 - 1) may not be interopable with all JSON implementations. As it turns out, the +number implementation used by JavaScript has this issue. When you parse a JSON string that +contains a numeric value like 4693522397653681111, the parsed result will contain a +rounded value like 4693522397653681000. While this is entirely a client-side problem, +we want to preserve maximum compatibility with common client languages. Given the ubiquity +of GraphiQL as a GraphQL client, we want to avoid this problem. Our solution is to support +two separate types: + +
    +
  • This type (JsonSafeLong) is serialized as a number, but limits values to the safely +serializable range.
  • +
  • The LongString type supports long values that use all 64 bits, but serializes as a +string rather than a number, avoiding the JavaScript compatibility problems. For more +background, see the JavaScript Number.MAX_SAFE_INTEGER +docs.
  • +
+
+
LocalTime
+
A local time such as "23:59:33" or "07:20:47.454" without a time zone or offset, +formatted based on the partial-time portion of +RFC3339.
+
LongString
+
A numeric type for large integer values in the inclusive range -2^63 (-9,223,372,036,854,775,808) +to (2^63 - 1) (9,223,372,036,854,775,807). Note that LongString values are serialized as strings +within JSON, to avoid interopability problems with JavaScript. If you want a large integer type +that serializes within JSON as a number, use JsonSafeLong.
+
TimeZone
+
An IANA time zone identifier, such as America/Los_Angeles +or UTC. For a full list of valid identifiers, see the +wikipedia article.
+
Untyped
+
A custom scalar type that allows any type of data, including: + +
    +
  • strings
  • +
  • numbers
  • +
  • objects and arrays (nested as deeply as you like)
  • +
  • booleans
  • +
+ +

Note: fields of this type are effectively untyped. We recommend it only be used for parts +of your schema that can’t be statically typed.

+
+
+ +

Enum Types

+ +

ElasticGraph defines these enum types. Most of these are intended for usage as an input +argument, but they could be used as a return type in your schema if they meet your needs.

+ +
+
DateGroupingGranularity
+
Enumerates the supported granularities of a Date.
+
DateGroupingTruncationUnit
+
Enumerates the supported truncation units of a Date.
+
DateTimeGroupingGranularity
+
Enumerates the supported granularities of a DateTime.
+
DateTimeGroupingTruncationUnit
+
Enumerates the supported truncation units of a DateTime.
+
DateTimeUnit
+
Enumeration of DateTime units.
+
DateUnit
+
Enumeration of Date units.
+
DayOfWeek
+
Indicates the specific day of the week.
+
DistanceUnit
+
Enumerates the supported distance units.
+
LocalTimeGroupingTruncationUnit
+
Enumerates the supported truncation units of a LocalTime.
+
LocalTimeUnit
+
Enumeration of LocalTime units.
+
MatchesQueryAllowedEditsPerTerm
+
Enumeration of allowed values for the matchesQuery: {allowedEditsPerTerm: ...} filter option.
+
+ +

Object Types

+ +

ElasticGraph defines these object types.

+ +
+
AggregationCountDetail
+
Provides detail about an aggregation count.
+
GeoLocation
+
Geographic coordinates representing a location on the Earth’s surface.
+
PageInfo
+
Provides information about the specific fetched page. This implements the +PageInfo specification from the Relay GraphQL Cursor Connections +Specification.
+
+ + +
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/Directive.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/Directive.html new file mode 100644 index 00000000..9b8611b1 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/Directive.html @@ -0,0 +1,567 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::SchemaElements::Directive + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::SchemaElements::Directive + + + +

+
+ +
+
Inherits:
+
+ Data + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + +
+
Includes:
+
Mixins::VerifiesGraphQLName
+
+ + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/directive.rb,
+ elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/directive.rb
+
+
+ +
+ +

Overview

+
+

Represents a GraphQL directive.

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + + + + + + + + +

Methods included from Mixins::VerifiesGraphQLName

+

verify_name!

+ + +
+

Instance Attribute Details

+ + + +
+

+ + #argumentsHash<Symbol, Object> (readonly) + + + + + +

+
+

Returns directive arguments.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<Symbol, Object>) + + + + — +

    directive arguments

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/directive.rb', line 22
+
+class Directive < ::Data.define(:name, :arguments)
+  prepend Mixins::VerifiesGraphQLName
+
+  # @return [String] GraphQL SDL form of the directive
+  def to_sdl
+    %(@#{name}#{Support::GraphQLFormatter.format_args(**arguments)})
+  end
+
+  # Duplicates this directive on another GraphQL schema element.
+  #
+  # @param element [Argument, EnumType, EnumValue, Field, ScalarType, TypeWithSubfields, UnionType] schema element
+  # @return [void]
+  def duplicate_on(element)
+    element.directive name, arguments
+  end
+end
+
+
+ + + +
+

+ + #nameString (readonly) + + + + + +

+
+

Returns name of the directive.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    name of the directive

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/directive.rb', line 22
+
+class Directive < ::Data.define(:name, :arguments)
+  prepend Mixins::VerifiesGraphQLName
+
+  # @return [String] GraphQL SDL form of the directive
+  def to_sdl
+    %(@#{name}#{Support::GraphQLFormatter.format_args(**arguments)})
+  end
+
+  # Duplicates this directive on another GraphQL schema element.
+  #
+  # @param element [Argument, EnumType, EnumValue, Field, ScalarType, TypeWithSubfields, UnionType] schema element
+  # @return [void]
+  def duplicate_on(element)
+    element.directive name, arguments
+  end
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #duplicate_on(element) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Duplicates this directive on another GraphQL schema element.

+ + +
+
+
+

Parameters:

+ + + +
+ + + + +
+
+
+
+34
+35
+36
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/directive.rb', line 34
+
+def duplicate_on(element)
+  element.directive name, arguments
+end
+
+
+ +
+

+ + #to_sdlString + + + + + +

+
+

Returns GraphQL SDL form of the directive.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    GraphQL SDL form of the directive

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+26
+27
+28
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/directive.rb', line 26
+
+def to_sdl
+  %(@#{name}#{Support::GraphQLFormatter.format_args(**arguments)})
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/EnumType.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/EnumType.html new file mode 100644 index 00000000..436edf67 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/EnumType.html @@ -0,0 +1,2226 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::SchemaElements::EnumType + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::SchemaElements::EnumType + + + +

+
+ +
+
Inherits:
+
+ Struct + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + +
+
Includes:
+
Mixins::CanBeGraphQLOnly, Mixins::HasDerivedGraphQLTypeCustomizations, Mixins::HasDirectives, Mixins::HasDocumentation, Mixins::VerifiesGraphQLName
+
+ + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb
+
+ +
+ +

Overview

+
+

Defines a GraphQL enum type. +The type is restricted to an enumerated set of values, each with a unique name. +Use value or values to define the enum values in the passed block.

+ +

Note: if required by your configuration, this may generate a pair of Enum types (an input +enum and an output enum).

+ + +
+
+
+ +
+

Examples:

+ + +

Define an enum type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.enum_type "Currency" do |t|
+    # in the block, `t` is an EnumType
+    t.value "USD"
+  end
+end
+ +
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

Attributes included from Mixins::HasDocumentation

+

#doc_comment

+ + + +

+ Instance Method Summary + collapse +

+ + + + + + + + + + + + + +

Methods included from Mixins::HasDerivedGraphQLTypeCustomizations

+

#customize_derived_type_fields, #customize_derived_types

+ + + + + + + + + +

Methods included from Mixins::HasDirectives

+

#directive, #directives, #directives_sdl

+ + + + + + + + + +

Methods included from Mixins::HasDocumentation

+

#append_to_documentation, #derived_documentation, #documentation, #formatted_documentation

+ + + + + + + + + +

Methods included from Mixins::CanBeGraphQLOnly

+

#graphql_only, #graphql_only?

+ + + + + + + + + +

Methods included from Mixins::VerifiesGraphQLName

+

verify_name!

+ + +
+

Instance Attribute Details

+ + + +
+

+ + #for_outputBoolean + + + + + +

+
+

Returns true if this enum is used for both input and output; false if it is for input only.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + + — +

    true if this enum is used for both input and output; false if it is for input only

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 39
+
+class EnumType < Struct.new(:schema_def_state, :type_ref, :for_output, :values_by_name)
+  # @dynamic type_ref, graphql_only?
+  prepend Mixins::VerifiesGraphQLName
+  include Mixins::CanBeGraphQLOnly
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasDerivedGraphQLTypeCustomizations
+  include Mixins::HasReadableToSAndInspect.new { |e| e.name }
+
+  # @private
+  def initialize(schema_def_state, name)
+    # @type var values_by_name: ::Hash[::String, EnumValue]
+    values_by_name = {}
+    super(schema_def_state, schema_def_state.type_ref(name).to_final_form, true, values_by_name)
+
+    # :nocov: -- currently all invocations have a block
+    yield self if block_given?
+    # :nocov:
+  end
+
+  # @return [String] name of the enum type
+  def name
+    type_ref.name
+  end
+
+  # @return [TypeReference] reference to `AggregatedValues` type to use for this enum.
+  def aggregated_values_type
+    schema_def_state.type_ref("NonNumeric").as_aggregated_values
+  end
+
+  # Defines an enum value for the current enum type.
+  #
+  # @param value_name [String] name of the enum value
+  # @yield [EnumValue] enum value so it can be further customized
+  # @return [void]
+  #
+  # @example Define an enum type with multiple enum values
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.enum_type "Currency" do |t|
+  #       t.value "USD" do |v|
+  #         v.documentation "US Dollars."
+  #       end
+  #
+  #       t.value "JPY" do |v|
+  #         v.documentation "Japanese Yen."
+  #       end
+  #     end
+  #   end
+  def value(value_name, &block)
+    alternate_original_name = value_name
+    value_name = schema_def_state.enum_value_namer.name_for(name, value_name.to_s)
+
+    if values_by_name.key?(value_name)
+      raise Errors::SchemaError, "Duplicate value on Enum::Type #{name}: #{value_name}"
+    end
+
+    if value_name.length > DEFAULT_MAX_KEYWORD_LENGTH
+      raise Errors::SchemaError, "Enum value `#{name}.#{value_name}` is too long: it is #{value_name.length} characters but cannot exceed #{DEFAULT_MAX_KEYWORD_LENGTH} characters."
+    end
+
+    values_by_name[value_name] = schema_def_state.factory.new_enum_value(value_name, alternate_original_name, &block)
+  end
+
+  # Defines multiple enum values. In contrast to {#value}, the enum values cannot be customized
+  # further via a block.
+  #
+  # @param value_names [Array<String>] names of the enum values
+  # @return [void]
+  #
+  # @example Define an enum type with multiple enum values
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.enum_type "Currency" do |t|
+  #       t.values "USD", "JPY", "CAD", "GBP"
+  #     end
+  #   end
+  def values(*value_names)
+    value_names.flatten.each { |name| value(name) }
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::Enum::Type] runtime metadata for this enum type
+  def 
+     = values_by_name
+      .transform_values(&:runtime_metadata)
+      .compact
+
+    SchemaArtifacts::RuntimeMetadata::Enum::Type.new(values_by_name: )
+  end
+
+  # @return [String] GraphQL SDL form of the enum type
+  def to_sdl
+    if values_by_name.empty?
+      raise Errors::SchemaError, "Enum type #{name} has no values, but enums must have at least one value."
+    end
+
+    <<~EOS
+      #{formatted_documentation}enum #{name} #{directives_sdl(suffix_with: " ")}{
+        #{values_by_name.values.map(&:to_sdl).flat_map { |s| s.split("\n") }.join("\n  ")}
+      }
+    EOS
+  end
+
+  # @private
+  def derived_graphql_types
+    # Derived GraphQL types must be generated for an output enum. For an enum type that is only
+    # used as an input, we do not need derived types.
+    return [] unless for_output
+
+    derived_scalar_types = schema_def_state.factory.new_scalar_type(name) do |t|
+      t.mapping type: "keyword"
+      t.json_schema type: "string"
+      t.graphql_only graphql_only?
+    end.derived_graphql_types
+
+    if (input_enum = as_input).equal?(self)
+      derived_scalar_types
+    else
+      [input_enum] + derived_scalar_types
+    end
+  end
+
+  # @return [Indexing::FieldType::Enum] indexing representation of this enum type
+  def to_indexing_field_type
+    Indexing::FieldType::Enum.new(values_by_name.keys)
+  end
+
+  # @return [false] enum types are never directly indexed
+  def indexed?
+    false
+  end
+
+  # @return [EnumType] converts the enum type to its input form for when different naming is used for input vs output enums.
+  def as_input
+    input_name = type_ref
+      .as_input_enum # To apply the configured format for input enums.
+      .to_final_form # To handle a type name override of the input enum.
+      .name
+
+    return self if input_name == name
+
+    schema_def_state.factory.new_enum_type(input_name) do |t|
+      t.for_output = false # flag that it's not used as an output enum, and therefore `derived_graphql_types` will be empty on it.
+      t.graphql_only true # input enums are always GraphQL-only.
+      t.documentation doc_comment
+      directives.each { |dir| dir.duplicate_on(t) }
+      values_by_name.each { |_, val| val.duplicate_on(t) }
+    end
+  end
+end
+
+
+ + + +
+

+ + #schema_def_stateState (readonly) + + + + + +

+
+

Returns state of the schema.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (State) + + + + — +

    state of the schema

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 39
+
+class EnumType < Struct.new(:schema_def_state, :type_ref, :for_output, :values_by_name)
+  # @dynamic type_ref, graphql_only?
+  prepend Mixins::VerifiesGraphQLName
+  include Mixins::CanBeGraphQLOnly
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasDerivedGraphQLTypeCustomizations
+  include Mixins::HasReadableToSAndInspect.new { |e| e.name }
+
+  # @private
+  def initialize(schema_def_state, name)
+    # @type var values_by_name: ::Hash[::String, EnumValue]
+    values_by_name = {}
+    super(schema_def_state, schema_def_state.type_ref(name).to_final_form, true, values_by_name)
+
+    # :nocov: -- currently all invocations have a block
+    yield self if block_given?
+    # :nocov:
+  end
+
+  # @return [String] name of the enum type
+  def name
+    type_ref.name
+  end
+
+  # @return [TypeReference] reference to `AggregatedValues` type to use for this enum.
+  def aggregated_values_type
+    schema_def_state.type_ref("NonNumeric").as_aggregated_values
+  end
+
+  # Defines an enum value for the current enum type.
+  #
+  # @param value_name [String] name of the enum value
+  # @yield [EnumValue] enum value so it can be further customized
+  # @return [void]
+  #
+  # @example Define an enum type with multiple enum values
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.enum_type "Currency" do |t|
+  #       t.value "USD" do |v|
+  #         v.documentation "US Dollars."
+  #       end
+  #
+  #       t.value "JPY" do |v|
+  #         v.documentation "Japanese Yen."
+  #       end
+  #     end
+  #   end
+  def value(value_name, &block)
+    alternate_original_name = value_name
+    value_name = schema_def_state.enum_value_namer.name_for(name, value_name.to_s)
+
+    if values_by_name.key?(value_name)
+      raise Errors::SchemaError, "Duplicate value on Enum::Type #{name}: #{value_name}"
+    end
+
+    if value_name.length > DEFAULT_MAX_KEYWORD_LENGTH
+      raise Errors::SchemaError, "Enum value `#{name}.#{value_name}` is too long: it is #{value_name.length} characters but cannot exceed #{DEFAULT_MAX_KEYWORD_LENGTH} characters."
+    end
+
+    values_by_name[value_name] = schema_def_state.factory.new_enum_value(value_name, alternate_original_name, &block)
+  end
+
+  # Defines multiple enum values. In contrast to {#value}, the enum values cannot be customized
+  # further via a block.
+  #
+  # @param value_names [Array<String>] names of the enum values
+  # @return [void]
+  #
+  # @example Define an enum type with multiple enum values
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.enum_type "Currency" do |t|
+  #       t.values "USD", "JPY", "CAD", "GBP"
+  #     end
+  #   end
+  def values(*value_names)
+    value_names.flatten.each { |name| value(name) }
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::Enum::Type] runtime metadata for this enum type
+  def 
+     = values_by_name
+      .transform_values(&:runtime_metadata)
+      .compact
+
+    SchemaArtifacts::RuntimeMetadata::Enum::Type.new(values_by_name: )
+  end
+
+  # @return [String] GraphQL SDL form of the enum type
+  def to_sdl
+    if values_by_name.empty?
+      raise Errors::SchemaError, "Enum type #{name} has no values, but enums must have at least one value."
+    end
+
+    <<~EOS
+      #{formatted_documentation}enum #{name} #{directives_sdl(suffix_with: " ")}{
+        #{values_by_name.values.map(&:to_sdl).flat_map { |s| s.split("\n") }.join("\n  ")}
+      }
+    EOS
+  end
+
+  # @private
+  def derived_graphql_types
+    # Derived GraphQL types must be generated for an output enum. For an enum type that is only
+    # used as an input, we do not need derived types.
+    return [] unless for_output
+
+    derived_scalar_types = schema_def_state.factory.new_scalar_type(name) do |t|
+      t.mapping type: "keyword"
+      t.json_schema type: "string"
+      t.graphql_only graphql_only?
+    end.derived_graphql_types
+
+    if (input_enum = as_input).equal?(self)
+      derived_scalar_types
+    else
+      [input_enum] + derived_scalar_types
+    end
+  end
+
+  # @return [Indexing::FieldType::Enum] indexing representation of this enum type
+  def to_indexing_field_type
+    Indexing::FieldType::Enum.new(values_by_name.keys)
+  end
+
+  # @return [false] enum types are never directly indexed
+  def indexed?
+    false
+  end
+
+  # @return [EnumType] converts the enum type to its input form for when different naming is used for input vs output enums.
+  def as_input
+    input_name = type_ref
+      .as_input_enum # To apply the configured format for input enums.
+      .to_final_form # To handle a type name override of the input enum.
+      .name
+
+    return self if input_name == name
+
+    schema_def_state.factory.new_enum_type(input_name) do |t|
+      t.for_output = false # flag that it's not used as an output enum, and therefore `derived_graphql_types` will be empty on it.
+      t.graphql_only true # input enums are always GraphQL-only.
+      t.documentation doc_comment
+      directives.each { |dir| dir.duplicate_on(t) }
+      values_by_name.each { |_, val| val.duplicate_on(t) }
+    end
+  end
+end
+
+
+ + + +
+

+ + #values_by_nameHash<String, EnumValue> (readonly) + + + + + +

+
+

Returns map of enum values, keyed by name.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<String, EnumValue>) + + + + — +

    map of enum values, keyed by name

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 39
+
+class EnumType < Struct.new(:schema_def_state, :type_ref, :for_output, :values_by_name)
+  # @dynamic type_ref, graphql_only?
+  prepend Mixins::VerifiesGraphQLName
+  include Mixins::CanBeGraphQLOnly
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasDerivedGraphQLTypeCustomizations
+  include Mixins::HasReadableToSAndInspect.new { |e| e.name }
+
+  # @private
+  def initialize(schema_def_state, name)
+    # @type var values_by_name: ::Hash[::String, EnumValue]
+    values_by_name = {}
+    super(schema_def_state, schema_def_state.type_ref(name).to_final_form, true, values_by_name)
+
+    # :nocov: -- currently all invocations have a block
+    yield self if block_given?
+    # :nocov:
+  end
+
+  # @return [String] name of the enum type
+  def name
+    type_ref.name
+  end
+
+  # @return [TypeReference] reference to `AggregatedValues` type to use for this enum.
+  def aggregated_values_type
+    schema_def_state.type_ref("NonNumeric").as_aggregated_values
+  end
+
+  # Defines an enum value for the current enum type.
+  #
+  # @param value_name [String] name of the enum value
+  # @yield [EnumValue] enum value so it can be further customized
+  # @return [void]
+  #
+  # @example Define an enum type with multiple enum values
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.enum_type "Currency" do |t|
+  #       t.value "USD" do |v|
+  #         v.documentation "US Dollars."
+  #       end
+  #
+  #       t.value "JPY" do |v|
+  #         v.documentation "Japanese Yen."
+  #       end
+  #     end
+  #   end
+  def value(value_name, &block)
+    alternate_original_name = value_name
+    value_name = schema_def_state.enum_value_namer.name_for(name, value_name.to_s)
+
+    if values_by_name.key?(value_name)
+      raise Errors::SchemaError, "Duplicate value on Enum::Type #{name}: #{value_name}"
+    end
+
+    if value_name.length > DEFAULT_MAX_KEYWORD_LENGTH
+      raise Errors::SchemaError, "Enum value `#{name}.#{value_name}` is too long: it is #{value_name.length} characters but cannot exceed #{DEFAULT_MAX_KEYWORD_LENGTH} characters."
+    end
+
+    values_by_name[value_name] = schema_def_state.factory.new_enum_value(value_name, alternate_original_name, &block)
+  end
+
+  # Defines multiple enum values. In contrast to {#value}, the enum values cannot be customized
+  # further via a block.
+  #
+  # @param value_names [Array<String>] names of the enum values
+  # @return [void]
+  #
+  # @example Define an enum type with multiple enum values
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.enum_type "Currency" do |t|
+  #       t.values "USD", "JPY", "CAD", "GBP"
+  #     end
+  #   end
+  def values(*value_names)
+    value_names.flatten.each { |name| value(name) }
+  end
+
+  # @return [SchemaArtifacts::RuntimeMetadata::Enum::Type] runtime metadata for this enum type
+  def 
+     = values_by_name
+      .transform_values(&:runtime_metadata)
+      .compact
+
+    SchemaArtifacts::RuntimeMetadata::Enum::Type.new(values_by_name: )
+  end
+
+  # @return [String] GraphQL SDL form of the enum type
+  def to_sdl
+    if values_by_name.empty?
+      raise Errors::SchemaError, "Enum type #{name} has no values, but enums must have at least one value."
+    end
+
+    <<~EOS
+      #{formatted_documentation}enum #{name} #{directives_sdl(suffix_with: " ")}{
+        #{values_by_name.values.map(&:to_sdl).flat_map { |s| s.split("\n") }.join("\n  ")}
+      }
+    EOS
+  end
+
+  # @private
+  def derived_graphql_types
+    # Derived GraphQL types must be generated for an output enum. For an enum type that is only
+    # used as an input, we do not need derived types.
+    return [] unless for_output
+
+    derived_scalar_types = schema_def_state.factory.new_scalar_type(name) do |t|
+      t.mapping type: "keyword"
+      t.json_schema type: "string"
+      t.graphql_only graphql_only?
+    end.derived_graphql_types
+
+    if (input_enum = as_input).equal?(self)
+      derived_scalar_types
+    else
+      [input_enum] + derived_scalar_types
+    end
+  end
+
+  # @return [Indexing::FieldType::Enum] indexing representation of this enum type
+  def to_indexing_field_type
+    Indexing::FieldType::Enum.new(values_by_name.keys)
+  end
+
+  # @return [false] enum types are never directly indexed
+  def indexed?
+    false
+  end
+
+  # @return [EnumType] converts the enum type to its input form for when different naming is used for input vs output enums.
+  def as_input
+    input_name = type_ref
+      .as_input_enum # To apply the configured format for input enums.
+      .to_final_form # To handle a type name override of the input enum.
+      .name
+
+    return self if input_name == name
+
+    schema_def_state.factory.new_enum_type(input_name) do |t|
+      t.for_output = false # flag that it's not used as an output enum, and therefore `derived_graphql_types` will be empty on it.
+      t.graphql_only true # input enums are always GraphQL-only.
+      t.documentation doc_comment
+      directives.each { |dir| dir.duplicate_on(t) }
+      values_by_name.each { |_, val| val.duplicate_on(t) }
+    end
+  end
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #aggregated_values_typeTypeReference + + + + + +

+
+

Returns reference to AggregatedValues type to use for this enum.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (TypeReference) + + + + — +

    reference to AggregatedValues type to use for this enum.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+65
+66
+67
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 65
+
+def aggregated_values_type
+  schema_def_state.type_ref("NonNumeric").as_aggregated_values
+end
+
+
+ +
+

+ + #as_inputEnumType + + + + + +

+
+

Returns converts the enum type to its input form for when different naming is used for input vs output enums.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (EnumType) + + + + — +

    converts the enum type to its input form for when different naming is used for input vs output enums.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 170
+
+def as_input
+  input_name = type_ref
+    .as_input_enum # To apply the configured format for input enums.
+    .to_final_form # To handle a type name override of the input enum.
+    .name
+
+  return self if input_name == name
+
+  schema_def_state.factory.new_enum_type(input_name) do |t|
+    t.for_output = false # flag that it's not used as an output enum, and therefore `derived_graphql_types` will be empty on it.
+    t.graphql_only true # input enums are always GraphQL-only.
+    t.documentation doc_comment
+    directives.each { |dir| dir.duplicate_on(t) }
+    values_by_name.each { |_, val| val.duplicate_on(t) }
+  end
+end
+
+
+ +
+

+ + #indexed?false + + + + + +

+
+

Returns enum types are never directly indexed.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (false) + + + + — +

    enum types are never directly indexed

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+165
+166
+167
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 165
+
+def indexed?
+  false
+end
+
+
+ +
+

+ + #nameString + + + + + +

+
+

Returns name of the enum type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    name of the enum type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+60
+61
+62
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 60
+
+def name
+  type_ref.name
+end
+
+
+ +
+

+ + #runtime_metadataSchemaArtifacts::RuntimeMetadata::Enum::Type + + + + + +

+
+

Returns runtime metadata for this enum type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (SchemaArtifacts::RuntimeMetadata::Enum::Type) + + + + — +

    runtime metadata for this enum type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+119
+120
+121
+122
+123
+124
+125
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 119
+
+def 
+   = values_by_name
+    .transform_values(&:runtime_metadata)
+    .compact
+
+  SchemaArtifacts::RuntimeMetadata::Enum::Type.new(values_by_name: )
+end
+
+
+ +
+

+ + #to_indexing_field_typeIndexing::FieldType::Enum + + + + + +

+
+

Returns indexing representation of this enum type.

+ + +
+
+
+ +

Returns:

+ + +
+ + + + +
+
+
+
+160
+161
+162
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 160
+
+def to_indexing_field_type
+  Indexing::FieldType::Enum.new(values_by_name.keys)
+end
+
+
+ +
+

+ + #to_sdlString + + + + + +

+
+

Returns GraphQL SDL form of the enum type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    GraphQL SDL form of the enum type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 128
+
+def to_sdl
+  if values_by_name.empty?
+    raise Errors::SchemaError, "Enum type #{name} has no values, but enums must have at least one value."
+  end
+
+  <<~EOS
+    #{formatted_documentation}enum #{name} #{directives_sdl(suffix_with: " ")}{
+      #{values_by_name.values.map(&:to_sdl).flat_map { |s| s.split("\n") }.join("\n  ")}
+    }
+  EOS
+end
+
+
+ +
+

+ + #value(value_name) {|EnumValue| ... } ⇒ void + + + + + +

+
+

This method returns an undefined value.

Defines an enum value for the current enum type.

+ + +
+
+
+ +
+

Examples:

+ + +

Define an enum type with multiple enum values

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.enum_type "Currency" do |t|
+    t.value "USD" do |v|
+      v.documentation "US Dollars."
+    end
+
+    t.value "JPY" do |v|
+      v.documentation "Japanese Yen."
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + value_name + + + (String) + + + + — +

    name of the enum value

    +
    + +
  • + +
+ +

Yields:

+
    + +
  • + + + (EnumValue) + + + + — +

    enum value so it can be further customized

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 87
+
+def value(value_name, &block)
+  alternate_original_name = value_name
+  value_name = schema_def_state.enum_value_namer.name_for(name, value_name.to_s)
+
+  if values_by_name.key?(value_name)
+    raise Errors::SchemaError, "Duplicate value on Enum::Type #{name}: #{value_name}"
+  end
+
+  if value_name.length > DEFAULT_MAX_KEYWORD_LENGTH
+    raise Errors::SchemaError, "Enum value `#{name}.#{value_name}` is too long: it is #{value_name.length} characters but cannot exceed #{DEFAULT_MAX_KEYWORD_LENGTH} characters."
+  end
+
+  values_by_name[value_name] = schema_def_state.factory.new_enum_value(value_name, alternate_original_name, &block)
+end
+
+
+ +
+

+ + #values(*value_names) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Defines multiple enum values. In contrast to #value, the enum values cannot be customized +further via a block.

+ + +
+
+
+ +
+

Examples:

+ + +

Define an enum type with multiple enum values

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.enum_type "Currency" do |t|
+    t.values "USD", "JPY", "CAD", "GBP"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + value_names + + + (Array<String>) + + + + — +

    names of the enum values

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+114
+115
+116
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 114
+
+def values(*value_names)
+  value_names.flatten.each { |name| value(name) }
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/EnumValue.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/EnumValue.html new file mode 100644 index 00000000..34115c50 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/EnumValue.html @@ -0,0 +1,979 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::SchemaElements::EnumValue + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::SchemaElements::EnumValue + + + +

+
+ +
+
Inherits:
+
+ Struct + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + +
+
Includes:
+
Mixins::HasDirectives, Mixins::HasDocumentation, Mixins::VerifiesGraphQLName
+
+ + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb
+
+ +
+ +

Overview

+
+

Represents a value of a GraphQL enum type.

+ + +
+
+
+ + +
+

Direct Known Subclasses

+

SortOrderEnumValue

+
+ + + + +

Instance Attribute Summary collapse

+ + + + + + +

Attributes included from Mixins::HasDocumentation

+

#doc_comment

+ + + +

+ Instance Method Summary + collapse +

+ + + + + + + + + + + + + +

Methods included from Mixins::HasDirectives

+

#directive, #directives, #directives_sdl

+ + + + + + + + + +

Methods included from Mixins::HasDocumentation

+

#append_to_documentation, #derived_documentation, #documentation, #formatted_documentation

+ + + + + + + + + +

Methods included from Mixins::VerifiesGraphQLName

+

verify_name!

+ + +
+

Instance Attribute Details

+ + + +
+

+ + #nameString (readonly) + + + + + +

+
+

Returns name of the value.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    name of the value

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb', line 25
+
+class EnumValue < Struct.new(:schema_def_state, :name, :runtime_metadata)
+  prepend Mixins::VerifiesGraphQLName
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasReadableToSAndInspect.new { |v| v.name }
+
+  # @private
+  def initialize(schema_def_state, name, original_name)
+     = SchemaArtifacts::RuntimeMetadata::Enum::Value.new(
+      sort_field: nil,
+      datastore_value: nil,
+      datastore_abbreviation: nil,
+      alternate_original_name: (original_name if original_name != name)
+    )
+
+    super(schema_def_state, name, )
+    yield self
+  end
+
+  # @return [String] GraphQL SDL form of the enum value
+  def to_sdl
+    "#{formatted_documentation}#{name}#{directives_sdl(prefix_with: " ")}"
+  end
+
+  # Duplicates this enum value on another {EnumType}.
+  #
+  # @param other_enum_type [EnumType] enum type to duplicate this value onto
+  # @return [void]
+  def duplicate_on(other_enum_type)
+    other_enum_type.value name do |v|
+      v.documentation doc_comment
+      directives.each { |dir| dir.duplicate_on(v) }
+      v.(**.to_h)
+    end
+  end
+
+  # Updates the runtime metadata.
+  #
+  # @param [Hash<Symbol, Object>] updates to apply to the runtime metadata
+  # @return [void]
+  def (**updates)
+    self. = .with(**updates)
+  end
+
+  private :runtime_metadata=
+end
+
+
+ + + +
+

+ + #runtime_metadataSchemaElements::RuntimeMetadata::Enum::Value (readonly) + + + + + +

+
+

Returns runtime metadata.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (SchemaElements::RuntimeMetadata::Enum::Value) + + + + — +

    runtime metadata

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb', line 25
+
+class EnumValue < Struct.new(:schema_def_state, :name, :runtime_metadata)
+  prepend Mixins::VerifiesGraphQLName
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasReadableToSAndInspect.new { |v| v.name }
+
+  # @private
+  def initialize(schema_def_state, name, original_name)
+     = SchemaArtifacts::RuntimeMetadata::Enum::Value.new(
+      sort_field: nil,
+      datastore_value: nil,
+      datastore_abbreviation: nil,
+      alternate_original_name: (original_name if original_name != name)
+    )
+
+    super(schema_def_state, name, )
+    yield self
+  end
+
+  # @return [String] GraphQL SDL form of the enum value
+  def to_sdl
+    "#{formatted_documentation}#{name}#{directives_sdl(prefix_with: " ")}"
+  end
+
+  # Duplicates this enum value on another {EnumType}.
+  #
+  # @param other_enum_type [EnumType] enum type to duplicate this value onto
+  # @return [void]
+  def duplicate_on(other_enum_type)
+    other_enum_type.value name do |v|
+      v.documentation doc_comment
+      directives.each { |dir| dir.duplicate_on(v) }
+      v.(**.to_h)
+    end
+  end
+
+  # Updates the runtime metadata.
+  #
+  # @param [Hash<Symbol, Object>] updates to apply to the runtime metadata
+  # @return [void]
+  def (**updates)
+    self. = .with(**updates)
+  end
+
+  private :runtime_metadata=
+end
+
+
+ + + +
+

+ + #schema_def_stateState (readonly) + + + + + +

+
+

Returns state of the schema.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (State) + + + + — +

    state of the schema

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb', line 25
+
+class EnumValue < Struct.new(:schema_def_state, :name, :runtime_metadata)
+  prepend Mixins::VerifiesGraphQLName
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasReadableToSAndInspect.new { |v| v.name }
+
+  # @private
+  def initialize(schema_def_state, name, original_name)
+     = SchemaArtifacts::RuntimeMetadata::Enum::Value.new(
+      sort_field: nil,
+      datastore_value: nil,
+      datastore_abbreviation: nil,
+      alternate_original_name: (original_name if original_name != name)
+    )
+
+    super(schema_def_state, name, )
+    yield self
+  end
+
+  # @return [String] GraphQL SDL form of the enum value
+  def to_sdl
+    "#{formatted_documentation}#{name}#{directives_sdl(prefix_with: " ")}"
+  end
+
+  # Duplicates this enum value on another {EnumType}.
+  #
+  # @param other_enum_type [EnumType] enum type to duplicate this value onto
+  # @return [void]
+  def duplicate_on(other_enum_type)
+    other_enum_type.value name do |v|
+      v.documentation doc_comment
+      directives.each { |dir| dir.duplicate_on(v) }
+      v.(**.to_h)
+    end
+  end
+
+  # Updates the runtime metadata.
+  #
+  # @param [Hash<Symbol, Object>] updates to apply to the runtime metadata
+  # @return [void]
+  def (**updates)
+    self. = .with(**updates)
+  end
+
+  private :runtime_metadata=
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #duplicate_on(other_enum_type) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Duplicates this enum value on another ElasticGraph::SchemaDefinition::SchemaElements::EnumType.

+ + +
+
+
+

Parameters:

+
    + +
  • + + other_enum_type + + + (EnumType) + + + + — +

    enum type to duplicate this value onto

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+53
+54
+55
+56
+57
+58
+59
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb', line 53
+
+def duplicate_on(other_enum_type)
+  other_enum_type.value name do |v|
+    v.documentation doc_comment
+    directives.each { |dir| dir.duplicate_on(v) }
+    v.(**.to_h)
+  end
+end
+
+
+ +
+

+ + #to_sdlString + + + + + +

+
+

Returns GraphQL SDL form of the enum value.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    GraphQL SDL form of the enum value

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+45
+46
+47
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb', line 45
+
+def to_sdl
+  "#{formatted_documentation}#{name}#{directives_sdl(prefix_with: " ")}"
+end
+
+
+ +
+

+ + #update_runtime_metadata(**updates) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Updates the runtime metadata.

+ + +
+
+
+

Parameters:

+
    + +
  • + + updates + + + (Hash<Symbol, Object>) + + + + — +

    to apply to the runtime metadata

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+65
+66
+67
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb', line 65
+
+def (**updates)
+  self. = .with(**updates)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/Field.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/Field.html new file mode 100644 index 00000000..86e23f4d --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/Field.html @@ -0,0 +1,10739 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::SchemaElements::Field + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::SchemaElements::Field + + + +

+
+ +
+
Inherits:
+
+ Struct + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + +
+
Includes:
+
Mixins::HasDirectives, Mixins::HasDocumentation, Mixins::HasTypeInfo, Mixins::VerifiesGraphQLName
+
+ + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb
+
+ +
+ +

Overview

+
+

Represents a GraphQL field.

+ + +
+
+
+ +
+

Examples:

+ + +

Define a GraphQL field

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Widget" do |t|
+    t.field "id", "ID" do |f|
+      # `f` in this block is a Field object
+    end
+  end
+end
+ +
+ + +
+

Direct Known Subclasses

+

Relationship

+
+ + + +

Constant Summary

+ +

Constants included + from Mixins::HasTypeInfo

+

Mixins::HasTypeInfo::CUSTOMIZABLE_DATASTORE_PARAMS

+ + +

Instance Attribute Summary collapse

+ + + + + + +

Attributes included from Mixins::HasDocumentation

+

#doc_comment

+ + + +

+ Instance Method Summary + collapse +

+ + + + + + + + + + + + + +

Methods included from Mixins::HasTypeInfo

+

#json_schema_options, #mapping, #mapping_options

+ + + + + + + + + +

Methods included from Mixins::HasDirectives

+

#directive, #directives, #directives_sdl

+ + + + + + + + + +

Methods included from Mixins::HasDocumentation

+

#append_to_documentation, #derived_documentation, #documentation, #formatted_documentation

+ + + + + + + + + +

Methods included from Mixins::VerifiesGraphQLName

+

verify_name!

+ + +
+

Instance Attribute Details

+ + + +
+

+ + #graphql_onlyBoolean (readonly) + + + + + +

+
+

Returns true if this field exists only in the GraphQL schema and is not indexed.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + + — +

    true if this field exists only in the GraphQL schema and is not indexed

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 89
+
+class Field < Struct.new(
+  :name, :original_type, :parent_type, :original_type_for_derived_types, :schema_def_state, :accuracy_confidence,
+  :filter_customizations, :grouped_by_customizations, :sub_aggregations_customizations,
+  :aggregated_values_customizations, :sort_order_enum_value_customizations,
+  :args, :sortable, :filterable, :aggregatable, :groupable, :graphql_only, :source, :runtime_field_script, :relationship, :singular_name,
+  :computation_detail, :non_nullable_in_json_schema, :backing_indexing_field, :as_input,
+  :legacy_grouping_schema, :name_in_index
+)
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasTypeInfo
+  include Mixins::HasReadableToSAndInspect.new { |f| "#{f.parent_type.name}.#{f.name}: #{f.type}" }
+
+  # @private
+  def initialize(
+    name:, type:, parent_type:, schema_def_state:,
+    accuracy_confidence: :high, name_in_index: name,
+    runtime_metadata_graphql_field: SchemaArtifacts::RuntimeMetadata::GraphQLField::EMPTY,
+    type_for_derived_types: nil, graphql_only: nil, singular: nil,
+    sortable: nil, filterable: nil, aggregatable: nil, groupable: nil,
+    backing_indexing_field: nil, as_input: false, legacy_grouping_schema: false
+  )
+    type_ref = schema_def_state.type_ref(type)
+    super(
+      name: name,
+      original_type: type_ref,
+      parent_type: parent_type,
+      original_type_for_derived_types: type_for_derived_types ? schema_def_state.type_ref(type_for_derived_types) : type_ref,
+      schema_def_state: schema_def_state,
+      accuracy_confidence: accuracy_confidence,
+      filter_customizations: [],
+      grouped_by_customizations: [],
+      sub_aggregations_customizations: [],
+      aggregated_values_customizations: [],
+      sort_order_enum_value_customizations: [],
+      args: {},
+      sortable: sortable,
+      filterable: filterable,
+      aggregatable: aggregatable,
+      groupable: groupable,
+      graphql_only: graphql_only,
+      source: nil,
+      runtime_field_script: nil,
+      # Note: we named the keyword argument `singular` (with no `_name` suffix) for consistency with
+      # other schema definition APIs, which also use `singular:` instead of `singular_name:`. We include
+      # the `_name` suffix on the attribute for clarity.
+      singular_name: singular,
+      name_in_index: name_in_index,
+      non_nullable_in_json_schema: false,
+      backing_indexing_field: backing_indexing_field,
+      as_input: as_input,
+      legacy_grouping_schema: legacy_grouping_schema
+    )
+
+    if name != name_in_index && name_in_index&.include?(".") && !graphql_only
+      raise Errors::SchemaError, "#{self} has an invalid `name_in_index`: #{name_in_index.inspect}. Only `graphql_only: true` fields can have a `name_in_index` that references a child field."
+    end
+
+    schema_def_state.register_user_defined_field(self)
+    yield self if block_given?
+  end
+
+  # @private
+  @@initialize_param_names = instance_method(:initialize).parameters.map(&:last).to_set
+
+  # must come after we capture the initialize params.
+  prepend Mixins::VerifiesGraphQLName
+
+  # @return [TypeReference] the type of this field
+  def type
+    # Here we lazily convert the `original_type` to an input type as needed. This must be lazy because
+    # the logic of `as_input` depends on detecting whether the type is an enum type, which it may not
+    # be able to do right away--we assume not if we can't tell, and retry every time this method is called.
+    original_type.to_final_form(as_input: as_input)
+  end
+
+  # @return [TypeReference] the type of the corresponding field on derived types (usually this is the same as {#type}).
+  #
+  # @private
+  def type_for_derived_types
+    original_type_for_derived_types.to_final_form(as_input: as_input)
+  end
+
+  # @note For each field defined in your schema that is filterable, a corresponding filtering field will be created on the
+  #   `*FilterInput` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding filtering field that will be generated for this
+  # field.
+  #
+  # @yield [Field] derived filtering field
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignFilterInput.organizationId` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "organizationId", "ID" do |f|
+  #         f.customize_filter_field do |ff|
+  #           ff.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_filter_field(&customization_block)
+    filter_customizations << customization_block
+  end
+
+  # @note For each field defined in your schema that is aggregatable, a corresponding `aggregatedValues` field will be created on the
+  #   `*AggregatedValues` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding `aggregatedValues` field that will be generated for
+  # this field.
+  #
+  # @yield [Field] derived aggregated values field
+  # @return [void]
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignAggregatedValues.adImpressions` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "adImpressions", "Int" do |f|
+  #         f.customize_aggregated_values_field do |avf|
+  #           avf.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_aggregated_values_field(&customization_block)
+    aggregated_values_customizations << customization_block
+  end
+
+  # @note For each field defined in your schema that is groupable, a corresponding `groupedBy` field will be created on the
+  #   `*AggregationGroupedBy` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding `groupedBy` field that will be generated for this
+  # field.
+  #
+  # @yield [Field] derived grouped by field
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignGroupedBy.organizationId` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "organizationId", "ID" do |f|
+  #         f.customize_grouped_by_field do |gbf|
+  #           gbf.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_grouped_by_field(&customization_block)
+    grouped_by_customizations << customization_block
+  end
+
+  # @note For each field defined in your schema that is sub-aggregatable (e.g. list fields indexed using the `nested` mapping type),
+  # a corresponding field will be created on the `*AggregationSubAggregations` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding `subAggregations` field that will be generated for
+  # this field.
+  #
+  # @yield [Field] derived sub-aggregations field
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `TransactionAggregationSubAggregations.fees` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Transaction" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "fees", "[Money!]!" do |f|
+  #         f.mapping type: "nested"
+  #
+  #         f.customize_sub_aggregations_field do |saf|
+  #           # Adds a `@deprecated` directive to the `PaymentAggregationSubAggregations.fees`
+  #           # field without also adding it to the `Payment.fees` field.
+  #           saf.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "transactions"
+  #     end
+  #
+  #     schema.object_type "Money" do |t|
+  #       t.field "amount", "Int"
+  #       t.field "currency", "String"
+  #     end
+  #   end
+  def customize_sub_aggregations_field(&customization_block)
+    sub_aggregations_customizations << customization_block
+  end
+
+  # @note for each sortable field, enum values will be generated on the derived sort order enum type allowing you to
+  #   sort by the field `ASC` or `DESC`.
+  #
+  # Registers a customization callback that will be applied to the corresponding enum values that will be generated for this field
+  # on the derived `SortOrder` enum type.
+  #
+  # @yield [SortOrderEnumValue] derived sort order enum value
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignSortOrder.organizationId_(ASC|DESC)` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "organizationId", "ID" do |f|
+  #         f.customize_sort_order_enum_values do |soev|
+  #           soev.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_sort_order_enum_values(&customization_block)
+    sort_order_enum_value_customizations << customization_block
+  end
+
+  # When you define a {Field} on an {ObjectType} or {InterfaceType}, ElasticGraph generates up to 6 different GraphQL schema elements
+  # for it:
+  #
+  # * A {Field} is generated on the parent {ObjectType} or {InterfaceType} (that is, this field itself). This is used by clients to
+  #   ask for values for the field in a response.
+  # * A {Field} may be generated on the `*FilterInput` {InputType} derived from the parent {ObjectType} or {InterfaceType}. This is
+  #   used by clients to specify how the query should filter.
+  # * A {Field} may be generated on the `*AggregationGroupedBy` {ObjectType} derived from the parent {ObjectType} or {InterfaceType}.
+  #   This is used by clients to specify how aggregations should be grouped.
+  # * A {Field} may be generated on the `*AggregatedValues` {ObjectType} derived from the parent {ObjectType} or {InterfaceType}.
+  #   This is used by clients to apply aggregation functions (e.g. `sum`, `max`, `min`, etc) to a set of field values for a group.
+  # * A {Field} may be generated on the `*AggregationSubAggregations` {ObjectType} derived from the parent {ObjectType} or
+  #   {InterfaceType}. This is used by clients to perform sub-aggregations on list fields indexed using the `nested` mapping type.
+  # * Multiple {EnumValue}s (both `*_ASC` and `*_DESC`) are generated on the `*SortOrder` {EnumType} derived from the parent indexed
+  #   {ObjectType}. This is used by clients to sort by a field.
+  #
+  # This method registers a customization callback which is applied to every element that is generated for this field.
+  #
+  # @yield [Field, EnumValue] the schema element
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Transaction" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "amount", "Int" do |f|
+  #         f.on_each_generated_schema_element do |element|
+  #           # Adds a `@deprecated` directive to every GraphQL schema element generated for `amount`:
+  #           #
+  #           # - The `Transaction.amount` field.
+  #           # - The `TransactionFilterInput.amount` field.
+  #           # - The `TransactionAggregationGroupedBy.amount` field.
+  #           # - The `TransactionAggregatedValues.amount` field.
+  #           # - The `TransactionSortOrder.amount_ASC` and`TransactionSortOrder.amount_DESC` enum values.
+  #           element.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "transactions"
+  #     end
+  #   end
+  def on_each_generated_schema_element(&customization_block)
+    customization_block.call(self)
+    customize_filter_field(&customization_block)
+    customize_aggregated_values_field(&customization_block)
+    customize_grouped_by_field(&customization_block)
+    customize_sub_aggregations_field(&customization_block)
+    customize_sort_order_enum_values(&customization_block)
+  end
+
+  # (see Mixins::HasTypeInfo#json_schema)
+  def json_schema(nullable: nil, **options)
+    if options.key?(:type)
+      raise Errors::SchemaError, "Cannot override JSON schema type of field `#{name}` with `#{options.fetch(:type)}`"
+    end
+
+    case nullable
+    when true
+      raise Errors::SchemaError, "`nullable: true` is not allowed on a field--just declare the GraphQL field as being nullable (no `!` suffix) instead."
+    when false
+      self.non_nullable_in_json_schema = true
+    end
+
+    super(**options)
+  end
+
+  # Configures ElasticGraph to source a field’s value from a related object. This can be used to denormalize data at ingestion time to
+  # support filtering, grouping, sorting, or aggregating data on a field from a related object.
+  #
+  # @param relationship [String] name of a relationship defined with {TypeWithSubfields#relates_to_one} using an inbound foreign key
+  #   which contains the the field you wish to source values from
+  # @param field_path [String] dot-separated path to the field on the related type containing values that should be copied to this
+  #   field
+  # @return [void]
+  #
+  # @example Source `City.currency` from `Country.currency`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Country" do |t|
+  #       t.field "id", "ID"
+  #       t.field "name", "String"
+  #       t.field "currency", "String"
+  #       t.relates_to_one "capitalCity", "City", via: "capitalCityId", dir: :out
+  #       t.index "countries"
+  #     end
+  #
+  #     schema.object_type "City" do |t|
+  #       t.field "id", "ID"
+  #       t.field "name", "String"
+  #       t.relates_to_one "capitalOf", "Country", via: "capitalCityId", dir: :in
+  #
+  #       t.field "currency", "String" do |f|
+  #         f.sourced_from "capitalOf", "currency"
+  #       end
+  #
+  #       t.index "cities"
+  #     end
+  #   end
+  def sourced_from(relationship, field_path)
+    self.source = schema_def_state.factory.new_field_source(
+      relationship_name: relationship,
+      field_path: field_path
+    )
+  end
+
+  # @private
+  def runtime_script(script)
+    self.runtime_field_script = script
+  end
+
+  # Registers an old name that this field used to have in a prior version of the schema.
+  #
+  # @note In situations where this API applies, ElasticGraph will give you an error message indicating that you need to use this API
+  #   or {TypeWithSubfields#deleted_field}. Likewise, when ElasticGraph no longer needs to know about this, it'll give you a warning
+  #   indicating the call to this method can be removed.
+  #
+  # @param old_name [String] old name this field used to have in a prior version of the schema
+  # @return [void]
+  #
+  # @example Indicate that `Widget.description` used to be called `Widget.notes`.
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Widget" do |t|
+  #       t.field "description", "String" do |f|
+  #         f.renamed_from "notes"
+  #       end
+  #     end
+  #   end
+  def renamed_from(old_name)
+    schema_def_state.register_renamed_field(
+      parent_type.name,
+      from: old_name,
+      to: name,
+      defined_at: caller_locations(1, 1).first, # : ::Thread::Backtrace::Location
+      defined_via: %(field.renamed_from "#{old_name}")
+    )
+  end
+
+  # @private
+  def to_sdl(type_structure_only: false, default_value_sdl: nil, &arg_selector)
+    if type_structure_only
+      "#{name}#{args_sdl(joiner: ", ", &arg_selector)}: #{type.name}"
+    else
+      args_sdl = args_sdl(joiner: "\n  ", after_opening_paren: "\n  ", &arg_selector)
+      "#{formatted_documentation}#{name}#{args_sdl}: #{type.name}#{default_value_sdl} #{directives_sdl}".strip
+    end
+  end
+
+  # Indicates if this field is sortable. Sortable fields will have corresponding `_ASC` and `_DESC` values generated in the
+  # sort order {EnumType} of the parent indexed type.
+  #
+  # By default, the sortability is inferred by the field type and mapping. For example, list fields are not sortable,
+  # and fields mapped as `text` are not sortable either. Fields are sortable in most other cases.
+  #
+  # The `sortable: true` option can be used to force a field to be sortable.
+  #
+  # @return [Boolean] true if this field is sortable
+  def sortable?
+    return sortable unless sortable.nil?
+
+    # List fields are not sortable by default. We'd need to provide the datastore a sort mode option:
+    # https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#_sort_mode_option
+    return false if type.list?
+
+    # Boolean fields are not sortable by default.
+    #   - Boolean: sorting all falses before all trues (or whatever) is not generally interesting.
+    return false if type.unwrap_non_null.boolean?
+
+    # Elasticsearch/OpenSearch do not support sorting text fields:
+    # > Text fields are not used for sorting...
+    # (from https://www.elastic.co/guide/en/elasticsearch/reference/current/the datastore.html#text)
+    return false if text?
+
+    # If the type uses custom mapping type we don't know how if the datastore can sort by it, so we assume it's not sortable.
+    return false if type.as_object_type&.has_custom_mapping_type?
+
+    # Default every other field to being sortable.
+    true
+  end
+
+  # Indicates if this field is filterable. Filterable fields will be available in the GraphQL schema under the `filter` argument.
+  #
+  # Most fields are filterable, except when:
+  #
+  # - It's a relation. Relation fields require us to load the related data from another index and can't be filtered on.
+  # - The field is an object type that isn't itself filterable (e.g. due to having no filterable fields or whatever).
+  # - Explicitly disabled with `filterable: false`.
+  #
+  # @return [Boolean]
+  def filterable?
+    # Object types that use custom index mappings (as `GeoLocation` does) aren't filterable
+    # by default since we can't guess what datastore filtering capabilities they have. We've implemented
+    # filtering support for `GeoLocation` fields, though, so we need to explicitly make it fliterable here.
+    # TODO: clean this up using an interface instead of checking for `GeoLocation`.
+    return true if type.fully_unwrapped.name == "GeoLocation"
+
+    return false if relationship || type.fully_unwrapped.as_object_type&.does_not_support?(&:filterable?)
+    return true if filterable.nil?
+    filterable
+  end
+
+  # Indicates if this field is groupable. Groupable fields will be available under `groupedBy` for an aggregations query.
+  #
+  # Groupability is inferred based on the field type and mapping type, or you can use the `groupable: true` option to force it.
+  #
+  # @return [Boolean]
+  def groupable?
+    # If the groupability of the field was specified explicitly when the field was defined, use the specified value.
+    return groupable unless groupable.nil?
+
+    # We don't want the `id` field of an indexed type to be available to group by, because it's the unique primary key
+    # and the groupings would each contain one document. It's simpler and more efficient to just query the raw documents
+    # instead.
+    return false if parent_type.indexed? && name == "id"
+
+    return false if relationship || type.fully_unwrapped.as_object_type&.does_not_support?(&:groupable?)
+
+    # We don't support grouping an entire list of values, but we do support grouping on individual values in a list.
+    # However, we only do so when a `singular_name` has been provided (so that we know what to call the grouped_by field).
+    # The semantics are a little odd (since one document can be duplicated in multiple grouping buckets) so we're ok
+    # with not offering it by default--the user has to opt-in by telling us what to call the field in its singular form.
+    return list_field_groupable_by_single_values? if type.list? && type.fully_unwrapped.leaf?
+
+    # Nested fields will be supported through specific nested aggregation support, and do not
+    # work as expected when grouping on the root document type.
+    return false if nested?
+
+    # Text fields cannot be efficiently grouped on, so make them non-groupable by default.
+    return false if text?
+
+    # In all other cases, default to being groupable.
+    true
+  end
+
+  # Indicates if this field is aggregatable. Aggregatable fields will be available under `aggregatedValues` for an aggregations query.
+  #
+  # Aggregatability is inferred based on the field type and mapping type, or you can use the `aggregatable: true` option to force it.
+  #
+  # @return [Boolean]
+  def aggregatable?
+    return aggregatable unless aggregatable.nil?
+    return false if relationship
+
+    # We don't yet support aggregating over subfields of a `nested` field.
+    # TODO: add support for aggregating over subfields of `nested` fields.
+    return false if nested?
+
+    # Text fields are not efficiently aggregatable (and you'll often get errors from the datastore if you attempt to aggregate them).
+    return false if text?
+
+    type_for_derived_types.fully_unwrapped.as_object_type&.supports?(&:aggregatable?) || index_leaf?
+  end
+
+  # Indicates if this field can be used as the basis for a sub-aggregation. Sub-aggregatable fields will be available under
+  # `subAggregations` for an aggregations query.
+  #
+  # Only nested fields, and object fields which have nested fields, can be sub-aggregated.
+  #
+  # @return [Boolean]
+  def sub_aggregatable?
+    return false if relationship
+
+    nested? || type_for_derived_types.fully_unwrapped.as_object_type&.supports?(&:sub_aggregatable?)
+  end
+
+  # Defines an argument on the field.
+  #
+  # @note ElasticGraph takes care of defining arguments for all the query features it supports, so there is generally no need to use
+  #   this API, and it has no way to interpret arbitrary arguments defined on a field. However, it can be useful for extensions that
+  #   extend the {ElasticGraph::GraphQL} query engine. For example, {ElasticGraph::Apollo} uses this API to satisfy the [Apollo
+  #   federation subgraph spec](https://www.apollographql.com/docs/federation/federation-spec/).
+  #
+  # @param name [String] name of the argument
+  # @param value_type [String] type of the argument in GraphQL SDL syntax
+  # @yield [Argument] for further customization
+  #
+  # @example Define an argument on a field
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Product" do |t|
+  #       t.field "name", "String" do |f|
+  #         f.argument "language", "String"
+  #       end
+  #     end
+  #   end
+  def argument(name, value_type, &block)
+    args[name] = schema_def_state.factory.new_argument(
+      self,
+      name,
+      schema_def_state.type_ref(value_type),
+      &block
+    )
+  end
+
+  # The index mapping type in effect for this field. This could come from either the field definition or from the type definition.
+  #
+  # @return [String]
+  def mapping_type
+    backing_indexing_field&.mapping_type || (resolve_mapping || {})["type"]
+  end
+
+  # @private
+  def list_field_groupable_by_single_values?
+    (type.list? || backing_indexing_field&.type&.list?) && !singular_name.nil?
+  end
+
+  # @private
+  def define_aggregated_values_field(parent_type)
+    return unless aggregatable?
+
+    unwrapped_type_for_derived_types = type_for_derived_types.fully_unwrapped
+    aggregated_values_type =
+      if index_leaf?
+        unwrapped_type_for_derived_types.resolved.aggregated_values_type
+      else
+        unwrapped_type_for_derived_types.as_aggregated_values
+      end
+
+    parent_type.field name, aggregated_values_type.name, name_in_index: name_in_index, graphql_only: true do |f|
+      f.documentation derived_documentation("Computed aggregate values for the `#{name}` field")
+      aggregated_values_customizations.each { |block| block.call(f) }
+    end
+  end
+
+  # @private
+  def define_grouped_by_field(parent_type)
+    return unless (field_name = grouped_by_field_name)
+
+    parent_type.field field_name, grouped_by_field_type_name, name_in_index: name_in_index, graphql_only: true do |f|
+      add_grouped_by_field_documentation(f)
+
+      define_legacy_timestamp_grouping_arguments_if_needed(f) if legacy_grouping_schema
+
+      grouped_by_customizations.each { |block| block.call(f) }
+    end
+  end
+
+  # @private
+  def grouped_by_field_type_name
+    unwrapped_type = type_for_derived_types.fully_unwrapped
+    if unwrapped_type.scalar_type_needing_grouped_by_object? && !legacy_grouping_schema
+      unwrapped_type.with_reverted_override.as_grouped_by.name
+    elsif unwrapped_type.leaf?
+      unwrapped_type.name
+    else
+      unwrapped_type.as_grouped_by.name
+    end
+  end
+
+  # @private
+  def add_grouped_by_field_documentation(field)
+    text = if list_field_groupable_by_single_values?
+      derived_documentation(
+        "The individual value from `#{name}` for this group",
+        list_field_grouped_by_doc_note("`#{name}`")
+      )
+    elsif type.list? && type.fully_unwrapped.object?
+      derived_documentation(
+        "The `#{name}` field value for this group",
+        list_field_grouped_by_doc_note("the selected subfields of `#{name}`")
+      )
+    elsif type_for_derived_types.fully_unwrapped.scalar_type_needing_grouped_by_object? && !legacy_grouping_schema
+      derived_documentation("Offers the different grouping options for the `#{name}` value within this group")
+    else
+      derived_documentation("The `#{name}` field value for this group")
+    end
+
+    field.documentation text
+  end
+
+  # @private
+  def grouped_by_field_name
+    return nil unless groupable?
+    list_field_groupable_by_single_values? ? singular_name : name
+  end
+
+  # @private
+  def define_sub_aggregations_field(parent_type:, type:)
+    parent_type.field name, type, name_in_index: name_in_index, graphql_only: true do |f|
+      f.documentation derived_documentation("Used to perform a sub-aggregation of `#{name}`")
+      sub_aggregations_customizations.each { |c| c.call(f) }
+
+      yield f if block_given?
+    end
+  end
+
+  # @private
+  def to_filter_field(parent_type:, for_single_value: !type_for_derived_types.list?)
+    type_prefix = text? ? "Text" : type_for_derived_types.fully_unwrapped.name
+    filter_type = schema_def_state
+      .type_ref(type_prefix)
+      .as_static_derived_type(filter_field_category(for_single_value))
+      .name
+
+    params = to_h
+      .slice(*@@initialize_param_names)
+      .merge(type: filter_type, parent_type: parent_type, name_in_index: name_in_index, type_for_derived_types: nil)
+
+    schema_def_state.factory.new_field(**params).tap do |f|
+      f.documentation derived_documentation(
+        "Used to filter on the `#{name}` field",
+        "Will be ignored if `null` or an empty object is passed"
+      )
+
+      filter_customizations.each { |c| c.call(f) }
+    end
+  end
+
+  # @private
+  def define_relay_pagination_arguments!
+    argument schema_def_state.schema_elements.first.to_sym, "Int" do |a|
+      a.documentation <<~EOS
+        Used in conjunction with the `after` argument to forward-paginate through the `#{name}`.
+        When provided, limits the number of returned results to the first `n` after the provided
+        `after` cursor (or from the start of the `#{name}`, if no `after` cursor is provided).
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+
+    argument schema_def_state.schema_elements.after.to_sym, "Cursor" do |a|
+      a.documentation <<~EOS
+        Used to forward-paginate through the `#{name}`. When provided, the next page after the
+        provided cursor will be returned.
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+
+    argument schema_def_state.schema_elements.last.to_sym, "Int" do |a|
+      a.documentation <<~EOS
+        Used in conjunction with the `before` argument to backward-paginate through the `#{name}`.
+        When provided, limits the number of returned results to the last `n` before the provided
+        `before` cursor (or from the end of the `#{name}`, if no `before` cursor is provided).
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+
+    argument schema_def_state.schema_elements.before.to_sym, "Cursor" do |a|
+      a.documentation <<~EOS
+        Used to backward-paginate through the `#{name}`. When provided, the previous page before the
+        provided cursor will be returned.
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+  end
+
+  # Converts this field to an `Indexing::FieldReference`, which contains all the attributes involved
+  # in building an `Indexing::Field`. Notably, we cannot actually convert to an `Indexing::Field` at
+  # the point this method is called, because the referenced field type may not have been defined
+  # yet. We don't need an actual `Indexing::Field` until the very end of the schema definition process,
+  # when we are dumping the artifacts. However, we need this at field definition time so that we
+  # can correctly detect duplicate indexing field issues when a field is defined. (This is used
+  # in `TypeWithSubfields#field`).
+  #
+  # @private
+  def to_indexing_field_reference
+    return nil if graphql_only
+
+    Indexing::FieldReference.new(
+      name: name,
+      name_in_index: name_in_index,
+      type: non_nullable_in_json_schema ? type.wrap_non_null : type,
+      mapping_options: mapping_options,
+      json_schema_options: json_schema_options,
+      accuracy_confidence: accuracy_confidence,
+      source: source,
+      runtime_field_script: runtime_field_script
+    )
+  end
+
+  # Converts this field to its `IndexingField` form.
+  #
+  # @private
+  def to_indexing_field
+    to_indexing_field_reference&.resolve
+  end
+
+  # @private
+  def resolve_mapping
+    to_indexing_field&.mapping
+  end
+
+  # Returns the string paths to the list fields that we need to index counts for.
+  # We do this to support the ability to filter on the size of a list.
+  #
+  # @private
+  def paths_to_lists_for_count_indexing(has_list_ancestor: false)
+    self_path = (has_list_ancestor || type.list?) ? [name_in_index] : []
+
+    nested_paths =
+      # Nested fields get indexed as separate hidden documents:
+      # https://www.elastic.co/guide/en/elasticsearch/reference/8.8/nested.html
+      #
+      # Given that, the counts of any `nested` list subfields will go in a `__counts` field on the
+      # separate hidden document.
+      if !nested? && (object_type = type.fully_unwrapped.as_object_type)
+        object_type.indexing_fields_by_name_in_index.values.flat_map do |sub_field|
+          sub_field.paths_to_lists_for_count_indexing(has_list_ancestor: has_list_ancestor || type.list?).map do |sub_path|
+            "#{name_in_index}#{LIST_COUNTS_FIELD_PATH_KEY_SEPARATOR}#{sub_path}"
+          end
+        end
+      else
+        []
+      end
+
+    self_path + nested_paths
+  end
+
+  # Indicates if this field is a leaf value in the index.  Note that GraphQL leaf values
+  # are always leaf values in the index but the inverse is not always true. For example,
+  # a `GeoLocation` field is not a leaf in GraphQL (because `GeoLocation` is an object
+  # type with subfields) but in the index we use a single `geo_point` mapping type, which
+  # is a single unit, so we consider it an index leaf.
+  #
+  # @private
+  def index_leaf?
+    type_for_derived_types.fully_unwrapped.leaf? || DATASTORE_PROPERTYLESS_OBJECT_TYPES.include?(mapping_type)
+  end
+
+  # @private
+  ACCURACY_SCORES = {
+    # :high is assigned to `Field`s that are generated directly from GraphQL fields or :extra_fields.
+    # For these, we know everything available to us in the schema about them.
+    high: 3,
+
+    # :medium is assigned to `Field`s that are inferred from the id fields required by a relation.
+    # We make logical guesses about the `indexing_field_type` but if the field is also manually defined,
+    # it could be slightly different (e.g. additional json schema validations), so we have medium
+    # confidence of these.
+    medium: 2,
+
+    # :low is assigned to the ElastcField inferred for the foreign key of an inbound relation. The
+    # nullability/cardinality of the foreign key field cannot be known from the relation metadata,
+    # so we just guess what seems safest (`[:nullable]`). If the field is defined another way
+    # we should prefer it, so we give these fields :low confidence.
+    low: 1
+  }
+
+  # Given two fields, picks the one that is most accurate. If they have the same accuracy
+  # confidence, yields to a block to force it to deal with the discrepancy, unless the fields
+  # are exactly equal (in which case we can return either).
+  #
+  # @private
+  def self.pick_most_accurate_from(field1, field2, to_comparable: ->(it) { it })
+    return field1 if to_comparable.call(field1) == to_comparable.call(field2)
+    yield if field1.accuracy_confidence == field2.accuracy_confidence
+    # Array#max_by can return nil (when called on an empty array), but our steep type is non-nil.
+    # Since it's not smart enough to realize the non-empty-array-usage of `max_by` won't return nil,
+    # we have to cast it to untyped here.
+    _ = [field1, field2].max_by { |f| ACCURACY_SCORES.fetch(f.accuracy_confidence) }
+  end
+
+  # Indicates if the field uses the `nested` mapping type.
+  #
+  # @private
+  def nested?
+    mapping_type == "nested"
+  end
+
+  # Records the `ComputationDetail` that should be on the `runtime_metadata_graphql_field`.
+  #
+  # @private
+  def (empty_bucket_value:, function:)
+    self.computation_detail = SchemaArtifacts::RuntimeMetadata::ComputationDetail.new(
+      empty_bucket_value: empty_bucket_value,
+      function: function
+    )
+  end
+
+  # Lazily creates and returns a GraphQLField using the field's {#name_in_index}, {#computation_detail},
+  # and {#relationship}.
+  #
+  # @private
+  def 
+    SchemaArtifacts::RuntimeMetadata::GraphQLField.new(
+      name_in_index: name_in_index,
+      computation_detail: computation_detail,
+      relation: relationship&.
+    )
+  end
+
+  private
+
+  def args_sdl(joiner:, after_opening_paren: "", &arg_selector)
+    selected_args = args.values.select(&arg_selector)
+    args_sdl = selected_args.map(&:to_sdl).flat_map { |s| s.split("\n") }.join(joiner)
+    return nil if args_sdl.empty?
+    "(#{after_opening_paren}#{args_sdl})"
+  end
+
+  # Indicates if the field uses the `text` mapping type.
+  def text?
+    mapping_type == "text"
+  end
+
+  def define_legacy_timestamp_grouping_arguments_if_needed(grouping_field)
+    case type.fully_unwrapped.name
+    when "Date"
+      grouping_field.argument schema_def_state.schema_elements.granularity, "DateGroupingGranularity!" do |a|
+        a.documentation "Determines the grouping granularity for this field."
+      end
+
+      grouping_field.argument schema_def_state.schema_elements.offset_days, "Int" do |a|
+        a.documentation <<~EOS
+          Number of days (positive or negative) to shift the `Date` boundaries of each date grouping bucket.
+
+          For example, when grouping by `YEAR`, this can be used to align the buckets with fiscal or school years instead of calendar years.
+        EOS
+      end
+    when "DateTime"
+      grouping_field.argument schema_def_state.schema_elements.granularity, "DateTimeGroupingGranularity!" do |a|
+        a.documentation "Determines the grouping granularity for this field."
+      end
+
+      grouping_field.argument schema_def_state.schema_elements.time_zone, "TimeZone" do |a|
+        a.documentation "The time zone to use when determining which grouping a `DateTime` value falls in."
+        a.default "UTC"
+      end
+
+      grouping_field.argument schema_def_state.schema_elements.offset, "DateTimeGroupingOffsetInput" do |a|
+        a.documentation <<~EOS
+          Amount of offset (positive or negative) to shift the `DateTime` boundaries of each grouping bucket.
+
+          For example, when grouping by `WEEK`, you can shift by 24 hours to change what day-of-week weeks are considered to start on.
+        EOS
+      end
+    end
+  end
+
+  def list_field_grouped_by_doc_note(individual_value_selection_description)
+    <<~EOS.strip
+      Note: `#{name}` is a collection field, but selecting this field will group on individual values of #{individual_value_selection_description}.
+      That means that a document may be grouped into multiple aggregation groupings (i.e. when its `#{name}`
+      field has multiple values) leading to some data duplication in the response. However, if a value shows
+      up in `#{name}` multiple times for a single document, that document will only be included in the group
+      once
+    EOS
+  end
+
+  # Determines the suffix of the filter field derived for this field. The suffix used determines
+  # the filtering capabilities (e.g. filtering on a single value vs a list of values with `any_satisfy`).
+  def filter_field_category(for_single_value)
+    return :filter_input if for_single_value
+
+    # For an index leaf field, there are no further nesting paths to traverse. We want to directly
+    # use a `ListFilterInput` type (e.g. `IntListFilterInput`) to offer `any_satisfy` filtering at this level.
+    return :list_filter_input if index_leaf?
+
+    # If it's a list-of-objects field we require the user to tell us what mapping type they want to
+    # use, which determines the suffix (and is handled below). Otherwise, we want to use `FieldsListFilterInput`.
+    # We are within a list filtering context (as indicated by `for_single_value` being false) without
+    # being at an index leaf field, so we must use `FieldsListFilterInput` as there are further nesting paths
+    # on the document and we want to provide `any_satisfy` at the leaf fields.
+    return :fields_list_filter_input unless type_for_derived_types.list?
+
+    case mapping_type
+    when "nested" then :list_filter_input
+    when "object" then :fields_list_filter_input
+    else
+      raise Errors::SchemaError, <<~EOS
+        `#{parent_type.name}.#{name}` is a list-of-objects field, but the mapping type has not been explicitly specified. Elasticsearch and OpenSearch
+        offer two ways to index list-of-objects fields. It cannot be changed on an existing field without dropping the index and recreating it (losing
+        any existing indexed data!), and there are nuanced tradeoffs involved here, so ElasticGraph provides no default mapping in this situation.
+
+        If you're currently prototyping and don't want to spend time weighing this tradeoff, we recommend you do this:
+
+        ```
+        t.field "#{name}", "#{type.name}" do |f|
+          # Here we are opting for flexibility (nested) over pure performance (object).
+          # TODO: evaluate if we want to stick with `nested` before going to production.
+          f.mapping type: "nested"
+        end
+        ```
+
+        Read on for details of the tradeoff involved here.
+
+        -----------------------------------------------------------------------------------------------------------------------------
+
+        Here are the options:
+
+        1) `f.mapping type: "object"` will cause each field path to be indexed as a separate "flattened" list.
+
+        For example, given a `Film` document like this:
+
+        ```
+        {
+          "name": "The Empire Strikes Back",
+          "characters": [
+            {"first": "Luke", "last": "Skywalker"},
+            {"first": "Han", "last": "Solo"}
+          ]
+        }
+        ```
+
+        ...the data will look like this in the inverted Lucene index:
+
+        ```
+        {
+          "name": "The Empire Strikes Back",
+          "characters.first": ["Luke", "Han"],
+          "characters.last": ["Skywalker", "Solo"]
+        }
+        ```
+
+        This is highly efficient, but there is no way to search on multiple fields of a character and be sure that the matching values came from the same character.
+        ElasticGraph models this in the filtering API it offers for this case:
+
+        ```
+        query {
+          films(filter: {
+            characters: {
+              first: {#{schema_def_state.schema_elements.any_satisfy}: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Luke"]}}
+              last: {#{schema_def_state.schema_elements.any_satisfy}: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Skywalker"]}}
+            }
+          }) {
+            # ...
+          }
+        }
+        ```
+
+        As suggested by this filtering API, this will match any film that has a character with a first name of "Luke" and a character
+        with the last name of "Skywalker", but this could be satisfied by two separate characters.
+
+        2) `f.mapping type: "nested"` will cause each _object_ in the list to be indexed as a separate hidden document, preserving the independence of each.
+
+        Given a `Film` document like "The Empire Strikes Back" from above, the `nested` type will index separate hidden documents for each character. This
+        allows ElasticGraph to offer this filtering API instead:
+
+        ```
+        query {
+          films(filter: {
+            characters: {#{schema_def_state.schema_elements.any_satisfy}: {
+              first: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Luke"]}
+              last: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Skywalker"]}
+            }}
+          }) {
+            # ...
+          }
+        }
+        ```
+
+        As suggested by this filtering API, this will only match films that have a character named "Luke Skywalker". However, the Elasticsearch docs[^1][^2] warn
+        that the `nested` mapping type can lead to performance problems, and index sorting cannot be configured[^3] when the `nested` type is used.
+
+        [^1]: https://www.elastic.co/guide/en/elasticsearch/reference/8.10/nested.html
+        [^2]: https://www.elastic.co/guide/en/elasticsearch/reference/8.10/joining-queries.html
+        [^3]: https://www.elastic.co/guide/en/elasticsearch/reference/8.10/index-modules-index-sorting.html
+      EOS
+    end
+  end
+end
+
+
+ + + +
+

+ + #nameString (readonly) + + + + + +

+
+

Returns name of the field.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    name of the field

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 89
+
+class Field < Struct.new(
+  :name, :original_type, :parent_type, :original_type_for_derived_types, :schema_def_state, :accuracy_confidence,
+  :filter_customizations, :grouped_by_customizations, :sub_aggregations_customizations,
+  :aggregated_values_customizations, :sort_order_enum_value_customizations,
+  :args, :sortable, :filterable, :aggregatable, :groupable, :graphql_only, :source, :runtime_field_script, :relationship, :singular_name,
+  :computation_detail, :non_nullable_in_json_schema, :backing_indexing_field, :as_input,
+  :legacy_grouping_schema, :name_in_index
+)
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasTypeInfo
+  include Mixins::HasReadableToSAndInspect.new { |f| "#{f.parent_type.name}.#{f.name}: #{f.type}" }
+
+  # @private
+  def initialize(
+    name:, type:, parent_type:, schema_def_state:,
+    accuracy_confidence: :high, name_in_index: name,
+    runtime_metadata_graphql_field: SchemaArtifacts::RuntimeMetadata::GraphQLField::EMPTY,
+    type_for_derived_types: nil, graphql_only: nil, singular: nil,
+    sortable: nil, filterable: nil, aggregatable: nil, groupable: nil,
+    backing_indexing_field: nil, as_input: false, legacy_grouping_schema: false
+  )
+    type_ref = schema_def_state.type_ref(type)
+    super(
+      name: name,
+      original_type: type_ref,
+      parent_type: parent_type,
+      original_type_for_derived_types: type_for_derived_types ? schema_def_state.type_ref(type_for_derived_types) : type_ref,
+      schema_def_state: schema_def_state,
+      accuracy_confidence: accuracy_confidence,
+      filter_customizations: [],
+      grouped_by_customizations: [],
+      sub_aggregations_customizations: [],
+      aggregated_values_customizations: [],
+      sort_order_enum_value_customizations: [],
+      args: {},
+      sortable: sortable,
+      filterable: filterable,
+      aggregatable: aggregatable,
+      groupable: groupable,
+      graphql_only: graphql_only,
+      source: nil,
+      runtime_field_script: nil,
+      # Note: we named the keyword argument `singular` (with no `_name` suffix) for consistency with
+      # other schema definition APIs, which also use `singular:` instead of `singular_name:`. We include
+      # the `_name` suffix on the attribute for clarity.
+      singular_name: singular,
+      name_in_index: name_in_index,
+      non_nullable_in_json_schema: false,
+      backing_indexing_field: backing_indexing_field,
+      as_input: as_input,
+      legacy_grouping_schema: legacy_grouping_schema
+    )
+
+    if name != name_in_index && name_in_index&.include?(".") && !graphql_only
+      raise Errors::SchemaError, "#{self} has an invalid `name_in_index`: #{name_in_index.inspect}. Only `graphql_only: true` fields can have a `name_in_index` that references a child field."
+    end
+
+    schema_def_state.register_user_defined_field(self)
+    yield self if block_given?
+  end
+
+  # @private
+  @@initialize_param_names = instance_method(:initialize).parameters.map(&:last).to_set
+
+  # must come after we capture the initialize params.
+  prepend Mixins::VerifiesGraphQLName
+
+  # @return [TypeReference] the type of this field
+  def type
+    # Here we lazily convert the `original_type` to an input type as needed. This must be lazy because
+    # the logic of `as_input` depends on detecting whether the type is an enum type, which it may not
+    # be able to do right away--we assume not if we can't tell, and retry every time this method is called.
+    original_type.to_final_form(as_input: as_input)
+  end
+
+  # @return [TypeReference] the type of the corresponding field on derived types (usually this is the same as {#type}).
+  #
+  # @private
+  def type_for_derived_types
+    original_type_for_derived_types.to_final_form(as_input: as_input)
+  end
+
+  # @note For each field defined in your schema that is filterable, a corresponding filtering field will be created on the
+  #   `*FilterInput` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding filtering field that will be generated for this
+  # field.
+  #
+  # @yield [Field] derived filtering field
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignFilterInput.organizationId` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "organizationId", "ID" do |f|
+  #         f.customize_filter_field do |ff|
+  #           ff.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_filter_field(&customization_block)
+    filter_customizations << customization_block
+  end
+
+  # @note For each field defined in your schema that is aggregatable, a corresponding `aggregatedValues` field will be created on the
+  #   `*AggregatedValues` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding `aggregatedValues` field that will be generated for
+  # this field.
+  #
+  # @yield [Field] derived aggregated values field
+  # @return [void]
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignAggregatedValues.adImpressions` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "adImpressions", "Int" do |f|
+  #         f.customize_aggregated_values_field do |avf|
+  #           avf.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_aggregated_values_field(&customization_block)
+    aggregated_values_customizations << customization_block
+  end
+
+  # @note For each field defined in your schema that is groupable, a corresponding `groupedBy` field will be created on the
+  #   `*AggregationGroupedBy` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding `groupedBy` field that will be generated for this
+  # field.
+  #
+  # @yield [Field] derived grouped by field
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignGroupedBy.organizationId` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "organizationId", "ID" do |f|
+  #         f.customize_grouped_by_field do |gbf|
+  #           gbf.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_grouped_by_field(&customization_block)
+    grouped_by_customizations << customization_block
+  end
+
+  # @note For each field defined in your schema that is sub-aggregatable (e.g. list fields indexed using the `nested` mapping type),
+  # a corresponding field will be created on the `*AggregationSubAggregations` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding `subAggregations` field that will be generated for
+  # this field.
+  #
+  # @yield [Field] derived sub-aggregations field
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `TransactionAggregationSubAggregations.fees` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Transaction" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "fees", "[Money!]!" do |f|
+  #         f.mapping type: "nested"
+  #
+  #         f.customize_sub_aggregations_field do |saf|
+  #           # Adds a `@deprecated` directive to the `PaymentAggregationSubAggregations.fees`
+  #           # field without also adding it to the `Payment.fees` field.
+  #           saf.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "transactions"
+  #     end
+  #
+  #     schema.object_type "Money" do |t|
+  #       t.field "amount", "Int"
+  #       t.field "currency", "String"
+  #     end
+  #   end
+  def customize_sub_aggregations_field(&customization_block)
+    sub_aggregations_customizations << customization_block
+  end
+
+  # @note for each sortable field, enum values will be generated on the derived sort order enum type allowing you to
+  #   sort by the field `ASC` or `DESC`.
+  #
+  # Registers a customization callback that will be applied to the corresponding enum values that will be generated for this field
+  # on the derived `SortOrder` enum type.
+  #
+  # @yield [SortOrderEnumValue] derived sort order enum value
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignSortOrder.organizationId_(ASC|DESC)` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "organizationId", "ID" do |f|
+  #         f.customize_sort_order_enum_values do |soev|
+  #           soev.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_sort_order_enum_values(&customization_block)
+    sort_order_enum_value_customizations << customization_block
+  end
+
+  # When you define a {Field} on an {ObjectType} or {InterfaceType}, ElasticGraph generates up to 6 different GraphQL schema elements
+  # for it:
+  #
+  # * A {Field} is generated on the parent {ObjectType} or {InterfaceType} (that is, this field itself). This is used by clients to
+  #   ask for values for the field in a response.
+  # * A {Field} may be generated on the `*FilterInput` {InputType} derived from the parent {ObjectType} or {InterfaceType}. This is
+  #   used by clients to specify how the query should filter.
+  # * A {Field} may be generated on the `*AggregationGroupedBy` {ObjectType} derived from the parent {ObjectType} or {InterfaceType}.
+  #   This is used by clients to specify how aggregations should be grouped.
+  # * A {Field} may be generated on the `*AggregatedValues` {ObjectType} derived from the parent {ObjectType} or {InterfaceType}.
+  #   This is used by clients to apply aggregation functions (e.g. `sum`, `max`, `min`, etc) to a set of field values for a group.
+  # * A {Field} may be generated on the `*AggregationSubAggregations` {ObjectType} derived from the parent {ObjectType} or
+  #   {InterfaceType}. This is used by clients to perform sub-aggregations on list fields indexed using the `nested` mapping type.
+  # * Multiple {EnumValue}s (both `*_ASC` and `*_DESC`) are generated on the `*SortOrder` {EnumType} derived from the parent indexed
+  #   {ObjectType}. This is used by clients to sort by a field.
+  #
+  # This method registers a customization callback which is applied to every element that is generated for this field.
+  #
+  # @yield [Field, EnumValue] the schema element
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Transaction" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "amount", "Int" do |f|
+  #         f.on_each_generated_schema_element do |element|
+  #           # Adds a `@deprecated` directive to every GraphQL schema element generated for `amount`:
+  #           #
+  #           # - The `Transaction.amount` field.
+  #           # - The `TransactionFilterInput.amount` field.
+  #           # - The `TransactionAggregationGroupedBy.amount` field.
+  #           # - The `TransactionAggregatedValues.amount` field.
+  #           # - The `TransactionSortOrder.amount_ASC` and`TransactionSortOrder.amount_DESC` enum values.
+  #           element.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "transactions"
+  #     end
+  #   end
+  def on_each_generated_schema_element(&customization_block)
+    customization_block.call(self)
+    customize_filter_field(&customization_block)
+    customize_aggregated_values_field(&customization_block)
+    customize_grouped_by_field(&customization_block)
+    customize_sub_aggregations_field(&customization_block)
+    customize_sort_order_enum_values(&customization_block)
+  end
+
+  # (see Mixins::HasTypeInfo#json_schema)
+  def json_schema(nullable: nil, **options)
+    if options.key?(:type)
+      raise Errors::SchemaError, "Cannot override JSON schema type of field `#{name}` with `#{options.fetch(:type)}`"
+    end
+
+    case nullable
+    when true
+      raise Errors::SchemaError, "`nullable: true` is not allowed on a field--just declare the GraphQL field as being nullable (no `!` suffix) instead."
+    when false
+      self.non_nullable_in_json_schema = true
+    end
+
+    super(**options)
+  end
+
+  # Configures ElasticGraph to source a field’s value from a related object. This can be used to denormalize data at ingestion time to
+  # support filtering, grouping, sorting, or aggregating data on a field from a related object.
+  #
+  # @param relationship [String] name of a relationship defined with {TypeWithSubfields#relates_to_one} using an inbound foreign key
+  #   which contains the the field you wish to source values from
+  # @param field_path [String] dot-separated path to the field on the related type containing values that should be copied to this
+  #   field
+  # @return [void]
+  #
+  # @example Source `City.currency` from `Country.currency`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Country" do |t|
+  #       t.field "id", "ID"
+  #       t.field "name", "String"
+  #       t.field "currency", "String"
+  #       t.relates_to_one "capitalCity", "City", via: "capitalCityId", dir: :out
+  #       t.index "countries"
+  #     end
+  #
+  #     schema.object_type "City" do |t|
+  #       t.field "id", "ID"
+  #       t.field "name", "String"
+  #       t.relates_to_one "capitalOf", "Country", via: "capitalCityId", dir: :in
+  #
+  #       t.field "currency", "String" do |f|
+  #         f.sourced_from "capitalOf", "currency"
+  #       end
+  #
+  #       t.index "cities"
+  #     end
+  #   end
+  def sourced_from(relationship, field_path)
+    self.source = schema_def_state.factory.new_field_source(
+      relationship_name: relationship,
+      field_path: field_path
+    )
+  end
+
+  # @private
+  def runtime_script(script)
+    self.runtime_field_script = script
+  end
+
+  # Registers an old name that this field used to have in a prior version of the schema.
+  #
+  # @note In situations where this API applies, ElasticGraph will give you an error message indicating that you need to use this API
+  #   or {TypeWithSubfields#deleted_field}. Likewise, when ElasticGraph no longer needs to know about this, it'll give you a warning
+  #   indicating the call to this method can be removed.
+  #
+  # @param old_name [String] old name this field used to have in a prior version of the schema
+  # @return [void]
+  #
+  # @example Indicate that `Widget.description` used to be called `Widget.notes`.
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Widget" do |t|
+  #       t.field "description", "String" do |f|
+  #         f.renamed_from "notes"
+  #       end
+  #     end
+  #   end
+  def renamed_from(old_name)
+    schema_def_state.register_renamed_field(
+      parent_type.name,
+      from: old_name,
+      to: name,
+      defined_at: caller_locations(1, 1).first, # : ::Thread::Backtrace::Location
+      defined_via: %(field.renamed_from "#{old_name}")
+    )
+  end
+
+  # @private
+  def to_sdl(type_structure_only: false, default_value_sdl: nil, &arg_selector)
+    if type_structure_only
+      "#{name}#{args_sdl(joiner: ", ", &arg_selector)}: #{type.name}"
+    else
+      args_sdl = args_sdl(joiner: "\n  ", after_opening_paren: "\n  ", &arg_selector)
+      "#{formatted_documentation}#{name}#{args_sdl}: #{type.name}#{default_value_sdl} #{directives_sdl}".strip
+    end
+  end
+
+  # Indicates if this field is sortable. Sortable fields will have corresponding `_ASC` and `_DESC` values generated in the
+  # sort order {EnumType} of the parent indexed type.
+  #
+  # By default, the sortability is inferred by the field type and mapping. For example, list fields are not sortable,
+  # and fields mapped as `text` are not sortable either. Fields are sortable in most other cases.
+  #
+  # The `sortable: true` option can be used to force a field to be sortable.
+  #
+  # @return [Boolean] true if this field is sortable
+  def sortable?
+    return sortable unless sortable.nil?
+
+    # List fields are not sortable by default. We'd need to provide the datastore a sort mode option:
+    # https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#_sort_mode_option
+    return false if type.list?
+
+    # Boolean fields are not sortable by default.
+    #   - Boolean: sorting all falses before all trues (or whatever) is not generally interesting.
+    return false if type.unwrap_non_null.boolean?
+
+    # Elasticsearch/OpenSearch do not support sorting text fields:
+    # > Text fields are not used for sorting...
+    # (from https://www.elastic.co/guide/en/elasticsearch/reference/current/the datastore.html#text)
+    return false if text?
+
+    # If the type uses custom mapping type we don't know how if the datastore can sort by it, so we assume it's not sortable.
+    return false if type.as_object_type&.has_custom_mapping_type?
+
+    # Default every other field to being sortable.
+    true
+  end
+
+  # Indicates if this field is filterable. Filterable fields will be available in the GraphQL schema under the `filter` argument.
+  #
+  # Most fields are filterable, except when:
+  #
+  # - It's a relation. Relation fields require us to load the related data from another index and can't be filtered on.
+  # - The field is an object type that isn't itself filterable (e.g. due to having no filterable fields or whatever).
+  # - Explicitly disabled with `filterable: false`.
+  #
+  # @return [Boolean]
+  def filterable?
+    # Object types that use custom index mappings (as `GeoLocation` does) aren't filterable
+    # by default since we can't guess what datastore filtering capabilities they have. We've implemented
+    # filtering support for `GeoLocation` fields, though, so we need to explicitly make it fliterable here.
+    # TODO: clean this up using an interface instead of checking for `GeoLocation`.
+    return true if type.fully_unwrapped.name == "GeoLocation"
+
+    return false if relationship || type.fully_unwrapped.as_object_type&.does_not_support?(&:filterable?)
+    return true if filterable.nil?
+    filterable
+  end
+
+  # Indicates if this field is groupable. Groupable fields will be available under `groupedBy` for an aggregations query.
+  #
+  # Groupability is inferred based on the field type and mapping type, or you can use the `groupable: true` option to force it.
+  #
+  # @return [Boolean]
+  def groupable?
+    # If the groupability of the field was specified explicitly when the field was defined, use the specified value.
+    return groupable unless groupable.nil?
+
+    # We don't want the `id` field of an indexed type to be available to group by, because it's the unique primary key
+    # and the groupings would each contain one document. It's simpler and more efficient to just query the raw documents
+    # instead.
+    return false if parent_type.indexed? && name == "id"
+
+    return false if relationship || type.fully_unwrapped.as_object_type&.does_not_support?(&:groupable?)
+
+    # We don't support grouping an entire list of values, but we do support grouping on individual values in a list.
+    # However, we only do so when a `singular_name` has been provided (so that we know what to call the grouped_by field).
+    # The semantics are a little odd (since one document can be duplicated in multiple grouping buckets) so we're ok
+    # with not offering it by default--the user has to opt-in by telling us what to call the field in its singular form.
+    return list_field_groupable_by_single_values? if type.list? && type.fully_unwrapped.leaf?
+
+    # Nested fields will be supported through specific nested aggregation support, and do not
+    # work as expected when grouping on the root document type.
+    return false if nested?
+
+    # Text fields cannot be efficiently grouped on, so make them non-groupable by default.
+    return false if text?
+
+    # In all other cases, default to being groupable.
+    true
+  end
+
+  # Indicates if this field is aggregatable. Aggregatable fields will be available under `aggregatedValues` for an aggregations query.
+  #
+  # Aggregatability is inferred based on the field type and mapping type, or you can use the `aggregatable: true` option to force it.
+  #
+  # @return [Boolean]
+  def aggregatable?
+    return aggregatable unless aggregatable.nil?
+    return false if relationship
+
+    # We don't yet support aggregating over subfields of a `nested` field.
+    # TODO: add support for aggregating over subfields of `nested` fields.
+    return false if nested?
+
+    # Text fields are not efficiently aggregatable (and you'll often get errors from the datastore if you attempt to aggregate them).
+    return false if text?
+
+    type_for_derived_types.fully_unwrapped.as_object_type&.supports?(&:aggregatable?) || index_leaf?
+  end
+
+  # Indicates if this field can be used as the basis for a sub-aggregation. Sub-aggregatable fields will be available under
+  # `subAggregations` for an aggregations query.
+  #
+  # Only nested fields, and object fields which have nested fields, can be sub-aggregated.
+  #
+  # @return [Boolean]
+  def sub_aggregatable?
+    return false if relationship
+
+    nested? || type_for_derived_types.fully_unwrapped.as_object_type&.supports?(&:sub_aggregatable?)
+  end
+
+  # Defines an argument on the field.
+  #
+  # @note ElasticGraph takes care of defining arguments for all the query features it supports, so there is generally no need to use
+  #   this API, and it has no way to interpret arbitrary arguments defined on a field. However, it can be useful for extensions that
+  #   extend the {ElasticGraph::GraphQL} query engine. For example, {ElasticGraph::Apollo} uses this API to satisfy the [Apollo
+  #   federation subgraph spec](https://www.apollographql.com/docs/federation/federation-spec/).
+  #
+  # @param name [String] name of the argument
+  # @param value_type [String] type of the argument in GraphQL SDL syntax
+  # @yield [Argument] for further customization
+  #
+  # @example Define an argument on a field
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Product" do |t|
+  #       t.field "name", "String" do |f|
+  #         f.argument "language", "String"
+  #       end
+  #     end
+  #   end
+  def argument(name, value_type, &block)
+    args[name] = schema_def_state.factory.new_argument(
+      self,
+      name,
+      schema_def_state.type_ref(value_type),
+      &block
+    )
+  end
+
+  # The index mapping type in effect for this field. This could come from either the field definition or from the type definition.
+  #
+  # @return [String]
+  def mapping_type
+    backing_indexing_field&.mapping_type || (resolve_mapping || {})["type"]
+  end
+
+  # @private
+  def list_field_groupable_by_single_values?
+    (type.list? || backing_indexing_field&.type&.list?) && !singular_name.nil?
+  end
+
+  # @private
+  def define_aggregated_values_field(parent_type)
+    return unless aggregatable?
+
+    unwrapped_type_for_derived_types = type_for_derived_types.fully_unwrapped
+    aggregated_values_type =
+      if index_leaf?
+        unwrapped_type_for_derived_types.resolved.aggregated_values_type
+      else
+        unwrapped_type_for_derived_types.as_aggregated_values
+      end
+
+    parent_type.field name, aggregated_values_type.name, name_in_index: name_in_index, graphql_only: true do |f|
+      f.documentation derived_documentation("Computed aggregate values for the `#{name}` field")
+      aggregated_values_customizations.each { |block| block.call(f) }
+    end
+  end
+
+  # @private
+  def define_grouped_by_field(parent_type)
+    return unless (field_name = grouped_by_field_name)
+
+    parent_type.field field_name, grouped_by_field_type_name, name_in_index: name_in_index, graphql_only: true do |f|
+      add_grouped_by_field_documentation(f)
+
+      define_legacy_timestamp_grouping_arguments_if_needed(f) if legacy_grouping_schema
+
+      grouped_by_customizations.each { |block| block.call(f) }
+    end
+  end
+
+  # @private
+  def grouped_by_field_type_name
+    unwrapped_type = type_for_derived_types.fully_unwrapped
+    if unwrapped_type.scalar_type_needing_grouped_by_object? && !legacy_grouping_schema
+      unwrapped_type.with_reverted_override.as_grouped_by.name
+    elsif unwrapped_type.leaf?
+      unwrapped_type.name
+    else
+      unwrapped_type.as_grouped_by.name
+    end
+  end
+
+  # @private
+  def add_grouped_by_field_documentation(field)
+    text = if list_field_groupable_by_single_values?
+      derived_documentation(
+        "The individual value from `#{name}` for this group",
+        list_field_grouped_by_doc_note("`#{name}`")
+      )
+    elsif type.list? && type.fully_unwrapped.object?
+      derived_documentation(
+        "The `#{name}` field value for this group",
+        list_field_grouped_by_doc_note("the selected subfields of `#{name}`")
+      )
+    elsif type_for_derived_types.fully_unwrapped.scalar_type_needing_grouped_by_object? && !legacy_grouping_schema
+      derived_documentation("Offers the different grouping options for the `#{name}` value within this group")
+    else
+      derived_documentation("The `#{name}` field value for this group")
+    end
+
+    field.documentation text
+  end
+
+  # @private
+  def grouped_by_field_name
+    return nil unless groupable?
+    list_field_groupable_by_single_values? ? singular_name : name
+  end
+
+  # @private
+  def define_sub_aggregations_field(parent_type:, type:)
+    parent_type.field name, type, name_in_index: name_in_index, graphql_only: true do |f|
+      f.documentation derived_documentation("Used to perform a sub-aggregation of `#{name}`")
+      sub_aggregations_customizations.each { |c| c.call(f) }
+
+      yield f if block_given?
+    end
+  end
+
+  # @private
+  def to_filter_field(parent_type:, for_single_value: !type_for_derived_types.list?)
+    type_prefix = text? ? "Text" : type_for_derived_types.fully_unwrapped.name
+    filter_type = schema_def_state
+      .type_ref(type_prefix)
+      .as_static_derived_type(filter_field_category(for_single_value))
+      .name
+
+    params = to_h
+      .slice(*@@initialize_param_names)
+      .merge(type: filter_type, parent_type: parent_type, name_in_index: name_in_index, type_for_derived_types: nil)
+
+    schema_def_state.factory.new_field(**params).tap do |f|
+      f.documentation derived_documentation(
+        "Used to filter on the `#{name}` field",
+        "Will be ignored if `null` or an empty object is passed"
+      )
+
+      filter_customizations.each { |c| c.call(f) }
+    end
+  end
+
+  # @private
+  def define_relay_pagination_arguments!
+    argument schema_def_state.schema_elements.first.to_sym, "Int" do |a|
+      a.documentation <<~EOS
+        Used in conjunction with the `after` argument to forward-paginate through the `#{name}`.
+        When provided, limits the number of returned results to the first `n` after the provided
+        `after` cursor (or from the start of the `#{name}`, if no `after` cursor is provided).
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+
+    argument schema_def_state.schema_elements.after.to_sym, "Cursor" do |a|
+      a.documentation <<~EOS
+        Used to forward-paginate through the `#{name}`. When provided, the next page after the
+        provided cursor will be returned.
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+
+    argument schema_def_state.schema_elements.last.to_sym, "Int" do |a|
+      a.documentation <<~EOS
+        Used in conjunction with the `before` argument to backward-paginate through the `#{name}`.
+        When provided, limits the number of returned results to the last `n` before the provided
+        `before` cursor (or from the end of the `#{name}`, if no `before` cursor is provided).
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+
+    argument schema_def_state.schema_elements.before.to_sym, "Cursor" do |a|
+      a.documentation <<~EOS
+        Used to backward-paginate through the `#{name}`. When provided, the previous page before the
+        provided cursor will be returned.
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+  end
+
+  # Converts this field to an `Indexing::FieldReference`, which contains all the attributes involved
+  # in building an `Indexing::Field`. Notably, we cannot actually convert to an `Indexing::Field` at
+  # the point this method is called, because the referenced field type may not have been defined
+  # yet. We don't need an actual `Indexing::Field` until the very end of the schema definition process,
+  # when we are dumping the artifacts. However, we need this at field definition time so that we
+  # can correctly detect duplicate indexing field issues when a field is defined. (This is used
+  # in `TypeWithSubfields#field`).
+  #
+  # @private
+  def to_indexing_field_reference
+    return nil if graphql_only
+
+    Indexing::FieldReference.new(
+      name: name,
+      name_in_index: name_in_index,
+      type: non_nullable_in_json_schema ? type.wrap_non_null : type,
+      mapping_options: mapping_options,
+      json_schema_options: json_schema_options,
+      accuracy_confidence: accuracy_confidence,
+      source: source,
+      runtime_field_script: runtime_field_script
+    )
+  end
+
+  # Converts this field to its `IndexingField` form.
+  #
+  # @private
+  def to_indexing_field
+    to_indexing_field_reference&.resolve
+  end
+
+  # @private
+  def resolve_mapping
+    to_indexing_field&.mapping
+  end
+
+  # Returns the string paths to the list fields that we need to index counts for.
+  # We do this to support the ability to filter on the size of a list.
+  #
+  # @private
+  def paths_to_lists_for_count_indexing(has_list_ancestor: false)
+    self_path = (has_list_ancestor || type.list?) ? [name_in_index] : []
+
+    nested_paths =
+      # Nested fields get indexed as separate hidden documents:
+      # https://www.elastic.co/guide/en/elasticsearch/reference/8.8/nested.html
+      #
+      # Given that, the counts of any `nested` list subfields will go in a `__counts` field on the
+      # separate hidden document.
+      if !nested? && (object_type = type.fully_unwrapped.as_object_type)
+        object_type.indexing_fields_by_name_in_index.values.flat_map do |sub_field|
+          sub_field.paths_to_lists_for_count_indexing(has_list_ancestor: has_list_ancestor || type.list?).map do |sub_path|
+            "#{name_in_index}#{LIST_COUNTS_FIELD_PATH_KEY_SEPARATOR}#{sub_path}"
+          end
+        end
+      else
+        []
+      end
+
+    self_path + nested_paths
+  end
+
+  # Indicates if this field is a leaf value in the index.  Note that GraphQL leaf values
+  # are always leaf values in the index but the inverse is not always true. For example,
+  # a `GeoLocation` field is not a leaf in GraphQL (because `GeoLocation` is an object
+  # type with subfields) but in the index we use a single `geo_point` mapping type, which
+  # is a single unit, so we consider it an index leaf.
+  #
+  # @private
+  def index_leaf?
+    type_for_derived_types.fully_unwrapped.leaf? || DATASTORE_PROPERTYLESS_OBJECT_TYPES.include?(mapping_type)
+  end
+
+  # @private
+  ACCURACY_SCORES = {
+    # :high is assigned to `Field`s that are generated directly from GraphQL fields or :extra_fields.
+    # For these, we know everything available to us in the schema about them.
+    high: 3,
+
+    # :medium is assigned to `Field`s that are inferred from the id fields required by a relation.
+    # We make logical guesses about the `indexing_field_type` but if the field is also manually defined,
+    # it could be slightly different (e.g. additional json schema validations), so we have medium
+    # confidence of these.
+    medium: 2,
+
+    # :low is assigned to the ElastcField inferred for the foreign key of an inbound relation. The
+    # nullability/cardinality of the foreign key field cannot be known from the relation metadata,
+    # so we just guess what seems safest (`[:nullable]`). If the field is defined another way
+    # we should prefer it, so we give these fields :low confidence.
+    low: 1
+  }
+
+  # Given two fields, picks the one that is most accurate. If they have the same accuracy
+  # confidence, yields to a block to force it to deal with the discrepancy, unless the fields
+  # are exactly equal (in which case we can return either).
+  #
+  # @private
+  def self.pick_most_accurate_from(field1, field2, to_comparable: ->(it) { it })
+    return field1 if to_comparable.call(field1) == to_comparable.call(field2)
+    yield if field1.accuracy_confidence == field2.accuracy_confidence
+    # Array#max_by can return nil (when called on an empty array), but our steep type is non-nil.
+    # Since it's not smart enough to realize the non-empty-array-usage of `max_by` won't return nil,
+    # we have to cast it to untyped here.
+    _ = [field1, field2].max_by { |f| ACCURACY_SCORES.fetch(f.accuracy_confidence) }
+  end
+
+  # Indicates if the field uses the `nested` mapping type.
+  #
+  # @private
+  def nested?
+    mapping_type == "nested"
+  end
+
+  # Records the `ComputationDetail` that should be on the `runtime_metadata_graphql_field`.
+  #
+  # @private
+  def (empty_bucket_value:, function:)
+    self.computation_detail = SchemaArtifacts::RuntimeMetadata::ComputationDetail.new(
+      empty_bucket_value: empty_bucket_value,
+      function: function
+    )
+  end
+
+  # Lazily creates and returns a GraphQLField using the field's {#name_in_index}, {#computation_detail},
+  # and {#relationship}.
+  #
+  # @private
+  def 
+    SchemaArtifacts::RuntimeMetadata::GraphQLField.new(
+      name_in_index: name_in_index,
+      computation_detail: computation_detail,
+      relation: relationship&.
+    )
+  end
+
+  private
+
+  def args_sdl(joiner:, after_opening_paren: "", &arg_selector)
+    selected_args = args.values.select(&arg_selector)
+    args_sdl = selected_args.map(&:to_sdl).flat_map { |s| s.split("\n") }.join(joiner)
+    return nil if args_sdl.empty?
+    "(#{after_opening_paren}#{args_sdl})"
+  end
+
+  # Indicates if the field uses the `text` mapping type.
+  def text?
+    mapping_type == "text"
+  end
+
+  def define_legacy_timestamp_grouping_arguments_if_needed(grouping_field)
+    case type.fully_unwrapped.name
+    when "Date"
+      grouping_field.argument schema_def_state.schema_elements.granularity, "DateGroupingGranularity!" do |a|
+        a.documentation "Determines the grouping granularity for this field."
+      end
+
+      grouping_field.argument schema_def_state.schema_elements.offset_days, "Int" do |a|
+        a.documentation <<~EOS
+          Number of days (positive or negative) to shift the `Date` boundaries of each date grouping bucket.
+
+          For example, when grouping by `YEAR`, this can be used to align the buckets with fiscal or school years instead of calendar years.
+        EOS
+      end
+    when "DateTime"
+      grouping_field.argument schema_def_state.schema_elements.granularity, "DateTimeGroupingGranularity!" do |a|
+        a.documentation "Determines the grouping granularity for this field."
+      end
+
+      grouping_field.argument schema_def_state.schema_elements.time_zone, "TimeZone" do |a|
+        a.documentation "The time zone to use when determining which grouping a `DateTime` value falls in."
+        a.default "UTC"
+      end
+
+      grouping_field.argument schema_def_state.schema_elements.offset, "DateTimeGroupingOffsetInput" do |a|
+        a.documentation <<~EOS
+          Amount of offset (positive or negative) to shift the `DateTime` boundaries of each grouping bucket.
+
+          For example, when grouping by `WEEK`, you can shift by 24 hours to change what day-of-week weeks are considered to start on.
+        EOS
+      end
+    end
+  end
+
+  def list_field_grouped_by_doc_note(individual_value_selection_description)
+    <<~EOS.strip
+      Note: `#{name}` is a collection field, but selecting this field will group on individual values of #{individual_value_selection_description}.
+      That means that a document may be grouped into multiple aggregation groupings (i.e. when its `#{name}`
+      field has multiple values) leading to some data duplication in the response. However, if a value shows
+      up in `#{name}` multiple times for a single document, that document will only be included in the group
+      once
+    EOS
+  end
+
+  # Determines the suffix of the filter field derived for this field. The suffix used determines
+  # the filtering capabilities (e.g. filtering on a single value vs a list of values with `any_satisfy`).
+  def filter_field_category(for_single_value)
+    return :filter_input if for_single_value
+
+    # For an index leaf field, there are no further nesting paths to traverse. We want to directly
+    # use a `ListFilterInput` type (e.g. `IntListFilterInput`) to offer `any_satisfy` filtering at this level.
+    return :list_filter_input if index_leaf?
+
+    # If it's a list-of-objects field we require the user to tell us what mapping type they want to
+    # use, which determines the suffix (and is handled below). Otherwise, we want to use `FieldsListFilterInput`.
+    # We are within a list filtering context (as indicated by `for_single_value` being false) without
+    # being at an index leaf field, so we must use `FieldsListFilterInput` as there are further nesting paths
+    # on the document and we want to provide `any_satisfy` at the leaf fields.
+    return :fields_list_filter_input unless type_for_derived_types.list?
+
+    case mapping_type
+    when "nested" then :list_filter_input
+    when "object" then :fields_list_filter_input
+    else
+      raise Errors::SchemaError, <<~EOS
+        `#{parent_type.name}.#{name}` is a list-of-objects field, but the mapping type has not been explicitly specified. Elasticsearch and OpenSearch
+        offer two ways to index list-of-objects fields. It cannot be changed on an existing field without dropping the index and recreating it (losing
+        any existing indexed data!), and there are nuanced tradeoffs involved here, so ElasticGraph provides no default mapping in this situation.
+
+        If you're currently prototyping and don't want to spend time weighing this tradeoff, we recommend you do this:
+
+        ```
+        t.field "#{name}", "#{type.name}" do |f|
+          # Here we are opting for flexibility (nested) over pure performance (object).
+          # TODO: evaluate if we want to stick with `nested` before going to production.
+          f.mapping type: "nested"
+        end
+        ```
+
+        Read on for details of the tradeoff involved here.
+
+        -----------------------------------------------------------------------------------------------------------------------------
+
+        Here are the options:
+
+        1) `f.mapping type: "object"` will cause each field path to be indexed as a separate "flattened" list.
+
+        For example, given a `Film` document like this:
+
+        ```
+        {
+          "name": "The Empire Strikes Back",
+          "characters": [
+            {"first": "Luke", "last": "Skywalker"},
+            {"first": "Han", "last": "Solo"}
+          ]
+        }
+        ```
+
+        ...the data will look like this in the inverted Lucene index:
+
+        ```
+        {
+          "name": "The Empire Strikes Back",
+          "characters.first": ["Luke", "Han"],
+          "characters.last": ["Skywalker", "Solo"]
+        }
+        ```
+
+        This is highly efficient, but there is no way to search on multiple fields of a character and be sure that the matching values came from the same character.
+        ElasticGraph models this in the filtering API it offers for this case:
+
+        ```
+        query {
+          films(filter: {
+            characters: {
+              first: {#{schema_def_state.schema_elements.any_satisfy}: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Luke"]}}
+              last: {#{schema_def_state.schema_elements.any_satisfy}: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Skywalker"]}}
+            }
+          }) {
+            # ...
+          }
+        }
+        ```
+
+        As suggested by this filtering API, this will match any film that has a character with a first name of "Luke" and a character
+        with the last name of "Skywalker", but this could be satisfied by two separate characters.
+
+        2) `f.mapping type: "nested"` will cause each _object_ in the list to be indexed as a separate hidden document, preserving the independence of each.
+
+        Given a `Film` document like "The Empire Strikes Back" from above, the `nested` type will index separate hidden documents for each character. This
+        allows ElasticGraph to offer this filtering API instead:
+
+        ```
+        query {
+          films(filter: {
+            characters: {#{schema_def_state.schema_elements.any_satisfy}: {
+              first: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Luke"]}
+              last: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Skywalker"]}
+            }}
+          }) {
+            # ...
+          }
+        }
+        ```
+
+        As suggested by this filtering API, this will only match films that have a character named "Luke Skywalker". However, the Elasticsearch docs[^1][^2] warn
+        that the `nested` mapping type can lead to performance problems, and index sorting cannot be configured[^3] when the `nested` type is used.
+
+        [^1]: https://www.elastic.co/guide/en/elasticsearch/reference/8.10/nested.html
+        [^2]: https://www.elastic.co/guide/en/elasticsearch/reference/8.10/joining-queries.html
+        [^3]: https://www.elastic.co/guide/en/elasticsearch/reference/8.10/index-modules-index-sorting.html
+      EOS
+    end
+  end
+end
+
+
+ + + +
+

+ + #name_in_indexString (readonly) + + + + + +

+
+

Returns the name of this field in the datastore index.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    the name of this field in the datastore index

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 89
+
+class Field < Struct.new(
+  :name, :original_type, :parent_type, :original_type_for_derived_types, :schema_def_state, :accuracy_confidence,
+  :filter_customizations, :grouped_by_customizations, :sub_aggregations_customizations,
+  :aggregated_values_customizations, :sort_order_enum_value_customizations,
+  :args, :sortable, :filterable, :aggregatable, :groupable, :graphql_only, :source, :runtime_field_script, :relationship, :singular_name,
+  :computation_detail, :non_nullable_in_json_schema, :backing_indexing_field, :as_input,
+  :legacy_grouping_schema, :name_in_index
+)
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasTypeInfo
+  include Mixins::HasReadableToSAndInspect.new { |f| "#{f.parent_type.name}.#{f.name}: #{f.type}" }
+
+  # @private
+  def initialize(
+    name:, type:, parent_type:, schema_def_state:,
+    accuracy_confidence: :high, name_in_index: name,
+    runtime_metadata_graphql_field: SchemaArtifacts::RuntimeMetadata::GraphQLField::EMPTY,
+    type_for_derived_types: nil, graphql_only: nil, singular: nil,
+    sortable: nil, filterable: nil, aggregatable: nil, groupable: nil,
+    backing_indexing_field: nil, as_input: false, legacy_grouping_schema: false
+  )
+    type_ref = schema_def_state.type_ref(type)
+    super(
+      name: name,
+      original_type: type_ref,
+      parent_type: parent_type,
+      original_type_for_derived_types: type_for_derived_types ? schema_def_state.type_ref(type_for_derived_types) : type_ref,
+      schema_def_state: schema_def_state,
+      accuracy_confidence: accuracy_confidence,
+      filter_customizations: [],
+      grouped_by_customizations: [],
+      sub_aggregations_customizations: [],
+      aggregated_values_customizations: [],
+      sort_order_enum_value_customizations: [],
+      args: {},
+      sortable: sortable,
+      filterable: filterable,
+      aggregatable: aggregatable,
+      groupable: groupable,
+      graphql_only: graphql_only,
+      source: nil,
+      runtime_field_script: nil,
+      # Note: we named the keyword argument `singular` (with no `_name` suffix) for consistency with
+      # other schema definition APIs, which also use `singular:` instead of `singular_name:`. We include
+      # the `_name` suffix on the attribute for clarity.
+      singular_name: singular,
+      name_in_index: name_in_index,
+      non_nullable_in_json_schema: false,
+      backing_indexing_field: backing_indexing_field,
+      as_input: as_input,
+      legacy_grouping_schema: legacy_grouping_schema
+    )
+
+    if name != name_in_index && name_in_index&.include?(".") && !graphql_only
+      raise Errors::SchemaError, "#{self} has an invalid `name_in_index`: #{name_in_index.inspect}. Only `graphql_only: true` fields can have a `name_in_index` that references a child field."
+    end
+
+    schema_def_state.register_user_defined_field(self)
+    yield self if block_given?
+  end
+
+  # @private
+  @@initialize_param_names = instance_method(:initialize).parameters.map(&:last).to_set
+
+  # must come after we capture the initialize params.
+  prepend Mixins::VerifiesGraphQLName
+
+  # @return [TypeReference] the type of this field
+  def type
+    # Here we lazily convert the `original_type` to an input type as needed. This must be lazy because
+    # the logic of `as_input` depends on detecting whether the type is an enum type, which it may not
+    # be able to do right away--we assume not if we can't tell, and retry every time this method is called.
+    original_type.to_final_form(as_input: as_input)
+  end
+
+  # @return [TypeReference] the type of the corresponding field on derived types (usually this is the same as {#type}).
+  #
+  # @private
+  def type_for_derived_types
+    original_type_for_derived_types.to_final_form(as_input: as_input)
+  end
+
+  # @note For each field defined in your schema that is filterable, a corresponding filtering field will be created on the
+  #   `*FilterInput` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding filtering field that will be generated for this
+  # field.
+  #
+  # @yield [Field] derived filtering field
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignFilterInput.organizationId` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "organizationId", "ID" do |f|
+  #         f.customize_filter_field do |ff|
+  #           ff.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_filter_field(&customization_block)
+    filter_customizations << customization_block
+  end
+
+  # @note For each field defined in your schema that is aggregatable, a corresponding `aggregatedValues` field will be created on the
+  #   `*AggregatedValues` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding `aggregatedValues` field that will be generated for
+  # this field.
+  #
+  # @yield [Field] derived aggregated values field
+  # @return [void]
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignAggregatedValues.adImpressions` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "adImpressions", "Int" do |f|
+  #         f.customize_aggregated_values_field do |avf|
+  #           avf.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_aggregated_values_field(&customization_block)
+    aggregated_values_customizations << customization_block
+  end
+
+  # @note For each field defined in your schema that is groupable, a corresponding `groupedBy` field will be created on the
+  #   `*AggregationGroupedBy` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding `groupedBy` field that will be generated for this
+  # field.
+  #
+  # @yield [Field] derived grouped by field
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignGroupedBy.organizationId` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "organizationId", "ID" do |f|
+  #         f.customize_grouped_by_field do |gbf|
+  #           gbf.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_grouped_by_field(&customization_block)
+    grouped_by_customizations << customization_block
+  end
+
+  # @note For each field defined in your schema that is sub-aggregatable (e.g. list fields indexed using the `nested` mapping type),
+  # a corresponding field will be created on the `*AggregationSubAggregations` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding `subAggregations` field that will be generated for
+  # this field.
+  #
+  # @yield [Field] derived sub-aggregations field
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `TransactionAggregationSubAggregations.fees` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Transaction" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "fees", "[Money!]!" do |f|
+  #         f.mapping type: "nested"
+  #
+  #         f.customize_sub_aggregations_field do |saf|
+  #           # Adds a `@deprecated` directive to the `PaymentAggregationSubAggregations.fees`
+  #           # field without also adding it to the `Payment.fees` field.
+  #           saf.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "transactions"
+  #     end
+  #
+  #     schema.object_type "Money" do |t|
+  #       t.field "amount", "Int"
+  #       t.field "currency", "String"
+  #     end
+  #   end
+  def customize_sub_aggregations_field(&customization_block)
+    sub_aggregations_customizations << customization_block
+  end
+
+  # @note for each sortable field, enum values will be generated on the derived sort order enum type allowing you to
+  #   sort by the field `ASC` or `DESC`.
+  #
+  # Registers a customization callback that will be applied to the corresponding enum values that will be generated for this field
+  # on the derived `SortOrder` enum type.
+  #
+  # @yield [SortOrderEnumValue] derived sort order enum value
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignSortOrder.organizationId_(ASC|DESC)` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "organizationId", "ID" do |f|
+  #         f.customize_sort_order_enum_values do |soev|
+  #           soev.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_sort_order_enum_values(&customization_block)
+    sort_order_enum_value_customizations << customization_block
+  end
+
+  # When you define a {Field} on an {ObjectType} or {InterfaceType}, ElasticGraph generates up to 6 different GraphQL schema elements
+  # for it:
+  #
+  # * A {Field} is generated on the parent {ObjectType} or {InterfaceType} (that is, this field itself). This is used by clients to
+  #   ask for values for the field in a response.
+  # * A {Field} may be generated on the `*FilterInput` {InputType} derived from the parent {ObjectType} or {InterfaceType}. This is
+  #   used by clients to specify how the query should filter.
+  # * A {Field} may be generated on the `*AggregationGroupedBy` {ObjectType} derived from the parent {ObjectType} or {InterfaceType}.
+  #   This is used by clients to specify how aggregations should be grouped.
+  # * A {Field} may be generated on the `*AggregatedValues` {ObjectType} derived from the parent {ObjectType} or {InterfaceType}.
+  #   This is used by clients to apply aggregation functions (e.g. `sum`, `max`, `min`, etc) to a set of field values for a group.
+  # * A {Field} may be generated on the `*AggregationSubAggregations` {ObjectType} derived from the parent {ObjectType} or
+  #   {InterfaceType}. This is used by clients to perform sub-aggregations on list fields indexed using the `nested` mapping type.
+  # * Multiple {EnumValue}s (both `*_ASC` and `*_DESC`) are generated on the `*SortOrder` {EnumType} derived from the parent indexed
+  #   {ObjectType}. This is used by clients to sort by a field.
+  #
+  # This method registers a customization callback which is applied to every element that is generated for this field.
+  #
+  # @yield [Field, EnumValue] the schema element
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Transaction" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "amount", "Int" do |f|
+  #         f.on_each_generated_schema_element do |element|
+  #           # Adds a `@deprecated` directive to every GraphQL schema element generated for `amount`:
+  #           #
+  #           # - The `Transaction.amount` field.
+  #           # - The `TransactionFilterInput.amount` field.
+  #           # - The `TransactionAggregationGroupedBy.amount` field.
+  #           # - The `TransactionAggregatedValues.amount` field.
+  #           # - The `TransactionSortOrder.amount_ASC` and`TransactionSortOrder.amount_DESC` enum values.
+  #           element.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "transactions"
+  #     end
+  #   end
+  def on_each_generated_schema_element(&customization_block)
+    customization_block.call(self)
+    customize_filter_field(&customization_block)
+    customize_aggregated_values_field(&customization_block)
+    customize_grouped_by_field(&customization_block)
+    customize_sub_aggregations_field(&customization_block)
+    customize_sort_order_enum_values(&customization_block)
+  end
+
+  # (see Mixins::HasTypeInfo#json_schema)
+  def json_schema(nullable: nil, **options)
+    if options.key?(:type)
+      raise Errors::SchemaError, "Cannot override JSON schema type of field `#{name}` with `#{options.fetch(:type)}`"
+    end
+
+    case nullable
+    when true
+      raise Errors::SchemaError, "`nullable: true` is not allowed on a field--just declare the GraphQL field as being nullable (no `!` suffix) instead."
+    when false
+      self.non_nullable_in_json_schema = true
+    end
+
+    super(**options)
+  end
+
+  # Configures ElasticGraph to source a field’s value from a related object. This can be used to denormalize data at ingestion time to
+  # support filtering, grouping, sorting, or aggregating data on a field from a related object.
+  #
+  # @param relationship [String] name of a relationship defined with {TypeWithSubfields#relates_to_one} using an inbound foreign key
+  #   which contains the the field you wish to source values from
+  # @param field_path [String] dot-separated path to the field on the related type containing values that should be copied to this
+  #   field
+  # @return [void]
+  #
+  # @example Source `City.currency` from `Country.currency`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Country" do |t|
+  #       t.field "id", "ID"
+  #       t.field "name", "String"
+  #       t.field "currency", "String"
+  #       t.relates_to_one "capitalCity", "City", via: "capitalCityId", dir: :out
+  #       t.index "countries"
+  #     end
+  #
+  #     schema.object_type "City" do |t|
+  #       t.field "id", "ID"
+  #       t.field "name", "String"
+  #       t.relates_to_one "capitalOf", "Country", via: "capitalCityId", dir: :in
+  #
+  #       t.field "currency", "String" do |f|
+  #         f.sourced_from "capitalOf", "currency"
+  #       end
+  #
+  #       t.index "cities"
+  #     end
+  #   end
+  def sourced_from(relationship, field_path)
+    self.source = schema_def_state.factory.new_field_source(
+      relationship_name: relationship,
+      field_path: field_path
+    )
+  end
+
+  # @private
+  def runtime_script(script)
+    self.runtime_field_script = script
+  end
+
+  # Registers an old name that this field used to have in a prior version of the schema.
+  #
+  # @note In situations where this API applies, ElasticGraph will give you an error message indicating that you need to use this API
+  #   or {TypeWithSubfields#deleted_field}. Likewise, when ElasticGraph no longer needs to know about this, it'll give you a warning
+  #   indicating the call to this method can be removed.
+  #
+  # @param old_name [String] old name this field used to have in a prior version of the schema
+  # @return [void]
+  #
+  # @example Indicate that `Widget.description` used to be called `Widget.notes`.
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Widget" do |t|
+  #       t.field "description", "String" do |f|
+  #         f.renamed_from "notes"
+  #       end
+  #     end
+  #   end
+  def renamed_from(old_name)
+    schema_def_state.register_renamed_field(
+      parent_type.name,
+      from: old_name,
+      to: name,
+      defined_at: caller_locations(1, 1).first, # : ::Thread::Backtrace::Location
+      defined_via: %(field.renamed_from "#{old_name}")
+    )
+  end
+
+  # @private
+  def to_sdl(type_structure_only: false, default_value_sdl: nil, &arg_selector)
+    if type_structure_only
+      "#{name}#{args_sdl(joiner: ", ", &arg_selector)}: #{type.name}"
+    else
+      args_sdl = args_sdl(joiner: "\n  ", after_opening_paren: "\n  ", &arg_selector)
+      "#{formatted_documentation}#{name}#{args_sdl}: #{type.name}#{default_value_sdl} #{directives_sdl}".strip
+    end
+  end
+
+  # Indicates if this field is sortable. Sortable fields will have corresponding `_ASC` and `_DESC` values generated in the
+  # sort order {EnumType} of the parent indexed type.
+  #
+  # By default, the sortability is inferred by the field type and mapping. For example, list fields are not sortable,
+  # and fields mapped as `text` are not sortable either. Fields are sortable in most other cases.
+  #
+  # The `sortable: true` option can be used to force a field to be sortable.
+  #
+  # @return [Boolean] true if this field is sortable
+  def sortable?
+    return sortable unless sortable.nil?
+
+    # List fields are not sortable by default. We'd need to provide the datastore a sort mode option:
+    # https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#_sort_mode_option
+    return false if type.list?
+
+    # Boolean fields are not sortable by default.
+    #   - Boolean: sorting all falses before all trues (or whatever) is not generally interesting.
+    return false if type.unwrap_non_null.boolean?
+
+    # Elasticsearch/OpenSearch do not support sorting text fields:
+    # > Text fields are not used for sorting...
+    # (from https://www.elastic.co/guide/en/elasticsearch/reference/current/the datastore.html#text)
+    return false if text?
+
+    # If the type uses custom mapping type we don't know how if the datastore can sort by it, so we assume it's not sortable.
+    return false if type.as_object_type&.has_custom_mapping_type?
+
+    # Default every other field to being sortable.
+    true
+  end
+
+  # Indicates if this field is filterable. Filterable fields will be available in the GraphQL schema under the `filter` argument.
+  #
+  # Most fields are filterable, except when:
+  #
+  # - It's a relation. Relation fields require us to load the related data from another index and can't be filtered on.
+  # - The field is an object type that isn't itself filterable (e.g. due to having no filterable fields or whatever).
+  # - Explicitly disabled with `filterable: false`.
+  #
+  # @return [Boolean]
+  def filterable?
+    # Object types that use custom index mappings (as `GeoLocation` does) aren't filterable
+    # by default since we can't guess what datastore filtering capabilities they have. We've implemented
+    # filtering support for `GeoLocation` fields, though, so we need to explicitly make it fliterable here.
+    # TODO: clean this up using an interface instead of checking for `GeoLocation`.
+    return true if type.fully_unwrapped.name == "GeoLocation"
+
+    return false if relationship || type.fully_unwrapped.as_object_type&.does_not_support?(&:filterable?)
+    return true if filterable.nil?
+    filterable
+  end
+
+  # Indicates if this field is groupable. Groupable fields will be available under `groupedBy` for an aggregations query.
+  #
+  # Groupability is inferred based on the field type and mapping type, or you can use the `groupable: true` option to force it.
+  #
+  # @return [Boolean]
+  def groupable?
+    # If the groupability of the field was specified explicitly when the field was defined, use the specified value.
+    return groupable unless groupable.nil?
+
+    # We don't want the `id` field of an indexed type to be available to group by, because it's the unique primary key
+    # and the groupings would each contain one document. It's simpler and more efficient to just query the raw documents
+    # instead.
+    return false if parent_type.indexed? && name == "id"
+
+    return false if relationship || type.fully_unwrapped.as_object_type&.does_not_support?(&:groupable?)
+
+    # We don't support grouping an entire list of values, but we do support grouping on individual values in a list.
+    # However, we only do so when a `singular_name` has been provided (so that we know what to call the grouped_by field).
+    # The semantics are a little odd (since one document can be duplicated in multiple grouping buckets) so we're ok
+    # with not offering it by default--the user has to opt-in by telling us what to call the field in its singular form.
+    return list_field_groupable_by_single_values? if type.list? && type.fully_unwrapped.leaf?
+
+    # Nested fields will be supported through specific nested aggregation support, and do not
+    # work as expected when grouping on the root document type.
+    return false if nested?
+
+    # Text fields cannot be efficiently grouped on, so make them non-groupable by default.
+    return false if text?
+
+    # In all other cases, default to being groupable.
+    true
+  end
+
+  # Indicates if this field is aggregatable. Aggregatable fields will be available under `aggregatedValues` for an aggregations query.
+  #
+  # Aggregatability is inferred based on the field type and mapping type, or you can use the `aggregatable: true` option to force it.
+  #
+  # @return [Boolean]
+  def aggregatable?
+    return aggregatable unless aggregatable.nil?
+    return false if relationship
+
+    # We don't yet support aggregating over subfields of a `nested` field.
+    # TODO: add support for aggregating over subfields of `nested` fields.
+    return false if nested?
+
+    # Text fields are not efficiently aggregatable (and you'll often get errors from the datastore if you attempt to aggregate them).
+    return false if text?
+
+    type_for_derived_types.fully_unwrapped.as_object_type&.supports?(&:aggregatable?) || index_leaf?
+  end
+
+  # Indicates if this field can be used as the basis for a sub-aggregation. Sub-aggregatable fields will be available under
+  # `subAggregations` for an aggregations query.
+  #
+  # Only nested fields, and object fields which have nested fields, can be sub-aggregated.
+  #
+  # @return [Boolean]
+  def sub_aggregatable?
+    return false if relationship
+
+    nested? || type_for_derived_types.fully_unwrapped.as_object_type&.supports?(&:sub_aggregatable?)
+  end
+
+  # Defines an argument on the field.
+  #
+  # @note ElasticGraph takes care of defining arguments for all the query features it supports, so there is generally no need to use
+  #   this API, and it has no way to interpret arbitrary arguments defined on a field. However, it can be useful for extensions that
+  #   extend the {ElasticGraph::GraphQL} query engine. For example, {ElasticGraph::Apollo} uses this API to satisfy the [Apollo
+  #   federation subgraph spec](https://www.apollographql.com/docs/federation/federation-spec/).
+  #
+  # @param name [String] name of the argument
+  # @param value_type [String] type of the argument in GraphQL SDL syntax
+  # @yield [Argument] for further customization
+  #
+  # @example Define an argument on a field
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Product" do |t|
+  #       t.field "name", "String" do |f|
+  #         f.argument "language", "String"
+  #       end
+  #     end
+  #   end
+  def argument(name, value_type, &block)
+    args[name] = schema_def_state.factory.new_argument(
+      self,
+      name,
+      schema_def_state.type_ref(value_type),
+      &block
+    )
+  end
+
+  # The index mapping type in effect for this field. This could come from either the field definition or from the type definition.
+  #
+  # @return [String]
+  def mapping_type
+    backing_indexing_field&.mapping_type || (resolve_mapping || {})["type"]
+  end
+
+  # @private
+  def list_field_groupable_by_single_values?
+    (type.list? || backing_indexing_field&.type&.list?) && !singular_name.nil?
+  end
+
+  # @private
+  def define_aggregated_values_field(parent_type)
+    return unless aggregatable?
+
+    unwrapped_type_for_derived_types = type_for_derived_types.fully_unwrapped
+    aggregated_values_type =
+      if index_leaf?
+        unwrapped_type_for_derived_types.resolved.aggregated_values_type
+      else
+        unwrapped_type_for_derived_types.as_aggregated_values
+      end
+
+    parent_type.field name, aggregated_values_type.name, name_in_index: name_in_index, graphql_only: true do |f|
+      f.documentation derived_documentation("Computed aggregate values for the `#{name}` field")
+      aggregated_values_customizations.each { |block| block.call(f) }
+    end
+  end
+
+  # @private
+  def define_grouped_by_field(parent_type)
+    return unless (field_name = grouped_by_field_name)
+
+    parent_type.field field_name, grouped_by_field_type_name, name_in_index: name_in_index, graphql_only: true do |f|
+      add_grouped_by_field_documentation(f)
+
+      define_legacy_timestamp_grouping_arguments_if_needed(f) if legacy_grouping_schema
+
+      grouped_by_customizations.each { |block| block.call(f) }
+    end
+  end
+
+  # @private
+  def grouped_by_field_type_name
+    unwrapped_type = type_for_derived_types.fully_unwrapped
+    if unwrapped_type.scalar_type_needing_grouped_by_object? && !legacy_grouping_schema
+      unwrapped_type.with_reverted_override.as_grouped_by.name
+    elsif unwrapped_type.leaf?
+      unwrapped_type.name
+    else
+      unwrapped_type.as_grouped_by.name
+    end
+  end
+
+  # @private
+  def add_grouped_by_field_documentation(field)
+    text = if list_field_groupable_by_single_values?
+      derived_documentation(
+        "The individual value from `#{name}` for this group",
+        list_field_grouped_by_doc_note("`#{name}`")
+      )
+    elsif type.list? && type.fully_unwrapped.object?
+      derived_documentation(
+        "The `#{name}` field value for this group",
+        list_field_grouped_by_doc_note("the selected subfields of `#{name}`")
+      )
+    elsif type_for_derived_types.fully_unwrapped.scalar_type_needing_grouped_by_object? && !legacy_grouping_schema
+      derived_documentation("Offers the different grouping options for the `#{name}` value within this group")
+    else
+      derived_documentation("The `#{name}` field value for this group")
+    end
+
+    field.documentation text
+  end
+
+  # @private
+  def grouped_by_field_name
+    return nil unless groupable?
+    list_field_groupable_by_single_values? ? singular_name : name
+  end
+
+  # @private
+  def define_sub_aggregations_field(parent_type:, type:)
+    parent_type.field name, type, name_in_index: name_in_index, graphql_only: true do |f|
+      f.documentation derived_documentation("Used to perform a sub-aggregation of `#{name}`")
+      sub_aggregations_customizations.each { |c| c.call(f) }
+
+      yield f if block_given?
+    end
+  end
+
+  # @private
+  def to_filter_field(parent_type:, for_single_value: !type_for_derived_types.list?)
+    type_prefix = text? ? "Text" : type_for_derived_types.fully_unwrapped.name
+    filter_type = schema_def_state
+      .type_ref(type_prefix)
+      .as_static_derived_type(filter_field_category(for_single_value))
+      .name
+
+    params = to_h
+      .slice(*@@initialize_param_names)
+      .merge(type: filter_type, parent_type: parent_type, name_in_index: name_in_index, type_for_derived_types: nil)
+
+    schema_def_state.factory.new_field(**params).tap do |f|
+      f.documentation derived_documentation(
+        "Used to filter on the `#{name}` field",
+        "Will be ignored if `null` or an empty object is passed"
+      )
+
+      filter_customizations.each { |c| c.call(f) }
+    end
+  end
+
+  # @private
+  def define_relay_pagination_arguments!
+    argument schema_def_state.schema_elements.first.to_sym, "Int" do |a|
+      a.documentation <<~EOS
+        Used in conjunction with the `after` argument to forward-paginate through the `#{name}`.
+        When provided, limits the number of returned results to the first `n` after the provided
+        `after` cursor (or from the start of the `#{name}`, if no `after` cursor is provided).
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+
+    argument schema_def_state.schema_elements.after.to_sym, "Cursor" do |a|
+      a.documentation <<~EOS
+        Used to forward-paginate through the `#{name}`. When provided, the next page after the
+        provided cursor will be returned.
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+
+    argument schema_def_state.schema_elements.last.to_sym, "Int" do |a|
+      a.documentation <<~EOS
+        Used in conjunction with the `before` argument to backward-paginate through the `#{name}`.
+        When provided, limits the number of returned results to the last `n` before the provided
+        `before` cursor (or from the end of the `#{name}`, if no `before` cursor is provided).
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+
+    argument schema_def_state.schema_elements.before.to_sym, "Cursor" do |a|
+      a.documentation <<~EOS
+        Used to backward-paginate through the `#{name}`. When provided, the previous page before the
+        provided cursor will be returned.
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+  end
+
+  # Converts this field to an `Indexing::FieldReference`, which contains all the attributes involved
+  # in building an `Indexing::Field`. Notably, we cannot actually convert to an `Indexing::Field` at
+  # the point this method is called, because the referenced field type may not have been defined
+  # yet. We don't need an actual `Indexing::Field` until the very end of the schema definition process,
+  # when we are dumping the artifacts. However, we need this at field definition time so that we
+  # can correctly detect duplicate indexing field issues when a field is defined. (This is used
+  # in `TypeWithSubfields#field`).
+  #
+  # @private
+  def to_indexing_field_reference
+    return nil if graphql_only
+
+    Indexing::FieldReference.new(
+      name: name,
+      name_in_index: name_in_index,
+      type: non_nullable_in_json_schema ? type.wrap_non_null : type,
+      mapping_options: mapping_options,
+      json_schema_options: json_schema_options,
+      accuracy_confidence: accuracy_confidence,
+      source: source,
+      runtime_field_script: runtime_field_script
+    )
+  end
+
+  # Converts this field to its `IndexingField` form.
+  #
+  # @private
+  def to_indexing_field
+    to_indexing_field_reference&.resolve
+  end
+
+  # @private
+  def resolve_mapping
+    to_indexing_field&.mapping
+  end
+
+  # Returns the string paths to the list fields that we need to index counts for.
+  # We do this to support the ability to filter on the size of a list.
+  #
+  # @private
+  def paths_to_lists_for_count_indexing(has_list_ancestor: false)
+    self_path = (has_list_ancestor || type.list?) ? [name_in_index] : []
+
+    nested_paths =
+      # Nested fields get indexed as separate hidden documents:
+      # https://www.elastic.co/guide/en/elasticsearch/reference/8.8/nested.html
+      #
+      # Given that, the counts of any `nested` list subfields will go in a `__counts` field on the
+      # separate hidden document.
+      if !nested? && (object_type = type.fully_unwrapped.as_object_type)
+        object_type.indexing_fields_by_name_in_index.values.flat_map do |sub_field|
+          sub_field.paths_to_lists_for_count_indexing(has_list_ancestor: has_list_ancestor || type.list?).map do |sub_path|
+            "#{name_in_index}#{LIST_COUNTS_FIELD_PATH_KEY_SEPARATOR}#{sub_path}"
+          end
+        end
+      else
+        []
+      end
+
+    self_path + nested_paths
+  end
+
+  # Indicates if this field is a leaf value in the index.  Note that GraphQL leaf values
+  # are always leaf values in the index but the inverse is not always true. For example,
+  # a `GeoLocation` field is not a leaf in GraphQL (because `GeoLocation` is an object
+  # type with subfields) but in the index we use a single `geo_point` mapping type, which
+  # is a single unit, so we consider it an index leaf.
+  #
+  # @private
+  def index_leaf?
+    type_for_derived_types.fully_unwrapped.leaf? || DATASTORE_PROPERTYLESS_OBJECT_TYPES.include?(mapping_type)
+  end
+
+  # @private
+  ACCURACY_SCORES = {
+    # :high is assigned to `Field`s that are generated directly from GraphQL fields or :extra_fields.
+    # For these, we know everything available to us in the schema about them.
+    high: 3,
+
+    # :medium is assigned to `Field`s that are inferred from the id fields required by a relation.
+    # We make logical guesses about the `indexing_field_type` but if the field is also manually defined,
+    # it could be slightly different (e.g. additional json schema validations), so we have medium
+    # confidence of these.
+    medium: 2,
+
+    # :low is assigned to the ElastcField inferred for the foreign key of an inbound relation. The
+    # nullability/cardinality of the foreign key field cannot be known from the relation metadata,
+    # so we just guess what seems safest (`[:nullable]`). If the field is defined another way
+    # we should prefer it, so we give these fields :low confidence.
+    low: 1
+  }
+
+  # Given two fields, picks the one that is most accurate. If they have the same accuracy
+  # confidence, yields to a block to force it to deal with the discrepancy, unless the fields
+  # are exactly equal (in which case we can return either).
+  #
+  # @private
+  def self.pick_most_accurate_from(field1, field2, to_comparable: ->(it) { it })
+    return field1 if to_comparable.call(field1) == to_comparable.call(field2)
+    yield if field1.accuracy_confidence == field2.accuracy_confidence
+    # Array#max_by can return nil (when called on an empty array), but our steep type is non-nil.
+    # Since it's not smart enough to realize the non-empty-array-usage of `max_by` won't return nil,
+    # we have to cast it to untyped here.
+    _ = [field1, field2].max_by { |f| ACCURACY_SCORES.fetch(f.accuracy_confidence) }
+  end
+
+  # Indicates if the field uses the `nested` mapping type.
+  #
+  # @private
+  def nested?
+    mapping_type == "nested"
+  end
+
+  # Records the `ComputationDetail` that should be on the `runtime_metadata_graphql_field`.
+  #
+  # @private
+  def (empty_bucket_value:, function:)
+    self.computation_detail = SchemaArtifacts::RuntimeMetadata::ComputationDetail.new(
+      empty_bucket_value: empty_bucket_value,
+      function: function
+    )
+  end
+
+  # Lazily creates and returns a GraphQLField using the field's {#name_in_index}, {#computation_detail},
+  # and {#relationship}.
+  #
+  # @private
+  def 
+    SchemaArtifacts::RuntimeMetadata::GraphQLField.new(
+      name_in_index: name_in_index,
+      computation_detail: computation_detail,
+      relation: relationship&.
+    )
+  end
+
+  private
+
+  def args_sdl(joiner:, after_opening_paren: "", &arg_selector)
+    selected_args = args.values.select(&arg_selector)
+    args_sdl = selected_args.map(&:to_sdl).flat_map { |s| s.split("\n") }.join(joiner)
+    return nil if args_sdl.empty?
+    "(#{after_opening_paren}#{args_sdl})"
+  end
+
+  # Indicates if the field uses the `text` mapping type.
+  def text?
+    mapping_type == "text"
+  end
+
+  def define_legacy_timestamp_grouping_arguments_if_needed(grouping_field)
+    case type.fully_unwrapped.name
+    when "Date"
+      grouping_field.argument schema_def_state.schema_elements.granularity, "DateGroupingGranularity!" do |a|
+        a.documentation "Determines the grouping granularity for this field."
+      end
+
+      grouping_field.argument schema_def_state.schema_elements.offset_days, "Int" do |a|
+        a.documentation <<~EOS
+          Number of days (positive or negative) to shift the `Date` boundaries of each date grouping bucket.
+
+          For example, when grouping by `YEAR`, this can be used to align the buckets with fiscal or school years instead of calendar years.
+        EOS
+      end
+    when "DateTime"
+      grouping_field.argument schema_def_state.schema_elements.granularity, "DateTimeGroupingGranularity!" do |a|
+        a.documentation "Determines the grouping granularity for this field."
+      end
+
+      grouping_field.argument schema_def_state.schema_elements.time_zone, "TimeZone" do |a|
+        a.documentation "The time zone to use when determining which grouping a `DateTime` value falls in."
+        a.default "UTC"
+      end
+
+      grouping_field.argument schema_def_state.schema_elements.offset, "DateTimeGroupingOffsetInput" do |a|
+        a.documentation <<~EOS
+          Amount of offset (positive or negative) to shift the `DateTime` boundaries of each grouping bucket.
+
+          For example, when grouping by `WEEK`, you can shift by 24 hours to change what day-of-week weeks are considered to start on.
+        EOS
+      end
+    end
+  end
+
+  def list_field_grouped_by_doc_note(individual_value_selection_description)
+    <<~EOS.strip
+      Note: `#{name}` is a collection field, but selecting this field will group on individual values of #{individual_value_selection_description}.
+      That means that a document may be grouped into multiple aggregation groupings (i.e. when its `#{name}`
+      field has multiple values) leading to some data duplication in the response. However, if a value shows
+      up in `#{name}` multiple times for a single document, that document will only be included in the group
+      once
+    EOS
+  end
+
+  # Determines the suffix of the filter field derived for this field. The suffix used determines
+  # the filtering capabilities (e.g. filtering on a single value vs a list of values with `any_satisfy`).
+  def filter_field_category(for_single_value)
+    return :filter_input if for_single_value
+
+    # For an index leaf field, there are no further nesting paths to traverse. We want to directly
+    # use a `ListFilterInput` type (e.g. `IntListFilterInput`) to offer `any_satisfy` filtering at this level.
+    return :list_filter_input if index_leaf?
+
+    # If it's a list-of-objects field we require the user to tell us what mapping type they want to
+    # use, which determines the suffix (and is handled below). Otherwise, we want to use `FieldsListFilterInput`.
+    # We are within a list filtering context (as indicated by `for_single_value` being false) without
+    # being at an index leaf field, so we must use `FieldsListFilterInput` as there are further nesting paths
+    # on the document and we want to provide `any_satisfy` at the leaf fields.
+    return :fields_list_filter_input unless type_for_derived_types.list?
+
+    case mapping_type
+    when "nested" then :list_filter_input
+    when "object" then :fields_list_filter_input
+    else
+      raise Errors::SchemaError, <<~EOS
+        `#{parent_type.name}.#{name}` is a list-of-objects field, but the mapping type has not been explicitly specified. Elasticsearch and OpenSearch
+        offer two ways to index list-of-objects fields. It cannot be changed on an existing field without dropping the index and recreating it (losing
+        any existing indexed data!), and there are nuanced tradeoffs involved here, so ElasticGraph provides no default mapping in this situation.
+
+        If you're currently prototyping and don't want to spend time weighing this tradeoff, we recommend you do this:
+
+        ```
+        t.field "#{name}", "#{type.name}" do |f|
+          # Here we are opting for flexibility (nested) over pure performance (object).
+          # TODO: evaluate if we want to stick with `nested` before going to production.
+          f.mapping type: "nested"
+        end
+        ```
+
+        Read on for details of the tradeoff involved here.
+
+        -----------------------------------------------------------------------------------------------------------------------------
+
+        Here are the options:
+
+        1) `f.mapping type: "object"` will cause each field path to be indexed as a separate "flattened" list.
+
+        For example, given a `Film` document like this:
+
+        ```
+        {
+          "name": "The Empire Strikes Back",
+          "characters": [
+            {"first": "Luke", "last": "Skywalker"},
+            {"first": "Han", "last": "Solo"}
+          ]
+        }
+        ```
+
+        ...the data will look like this in the inverted Lucene index:
+
+        ```
+        {
+          "name": "The Empire Strikes Back",
+          "characters.first": ["Luke", "Han"],
+          "characters.last": ["Skywalker", "Solo"]
+        }
+        ```
+
+        This is highly efficient, but there is no way to search on multiple fields of a character and be sure that the matching values came from the same character.
+        ElasticGraph models this in the filtering API it offers for this case:
+
+        ```
+        query {
+          films(filter: {
+            characters: {
+              first: {#{schema_def_state.schema_elements.any_satisfy}: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Luke"]}}
+              last: {#{schema_def_state.schema_elements.any_satisfy}: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Skywalker"]}}
+            }
+          }) {
+            # ...
+          }
+        }
+        ```
+
+        As suggested by this filtering API, this will match any film that has a character with a first name of "Luke" and a character
+        with the last name of "Skywalker", but this could be satisfied by two separate characters.
+
+        2) `f.mapping type: "nested"` will cause each _object_ in the list to be indexed as a separate hidden document, preserving the independence of each.
+
+        Given a `Film` document like "The Empire Strikes Back" from above, the `nested` type will index separate hidden documents for each character. This
+        allows ElasticGraph to offer this filtering API instead:
+
+        ```
+        query {
+          films(filter: {
+            characters: {#{schema_def_state.schema_elements.any_satisfy}: {
+              first: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Luke"]}
+              last: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Skywalker"]}
+            }}
+          }) {
+            # ...
+          }
+        }
+        ```
+
+        As suggested by this filtering API, this will only match films that have a character named "Luke Skywalker". However, the Elasticsearch docs[^1][^2] warn
+        that the `nested` mapping type can lead to performance problems, and index sorting cannot be configured[^3] when the `nested` type is used.
+
+        [^1]: https://www.elastic.co/guide/en/elasticsearch/reference/8.10/nested.html
+        [^2]: https://www.elastic.co/guide/en/elasticsearch/reference/8.10/joining-queries.html
+        [^3]: https://www.elastic.co/guide/en/elasticsearch/reference/8.10/index-modules-index-sorting.html
+      EOS
+    end
+  end
+end
+
+
+ + + +
+

+ + #schema_def_stateState (readonly) + + + + + +

+
+

Returns schema definition state.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (State) + + + + — +

    schema definition state

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 89
+
+class Field < Struct.new(
+  :name, :original_type, :parent_type, :original_type_for_derived_types, :schema_def_state, :accuracy_confidence,
+  :filter_customizations, :grouped_by_customizations, :sub_aggregations_customizations,
+  :aggregated_values_customizations, :sort_order_enum_value_customizations,
+  :args, :sortable, :filterable, :aggregatable, :groupable, :graphql_only, :source, :runtime_field_script, :relationship, :singular_name,
+  :computation_detail, :non_nullable_in_json_schema, :backing_indexing_field, :as_input,
+  :legacy_grouping_schema, :name_in_index
+)
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasTypeInfo
+  include Mixins::HasReadableToSAndInspect.new { |f| "#{f.parent_type.name}.#{f.name}: #{f.type}" }
+
+  # @private
+  def initialize(
+    name:, type:, parent_type:, schema_def_state:,
+    accuracy_confidence: :high, name_in_index: name,
+    runtime_metadata_graphql_field: SchemaArtifacts::RuntimeMetadata::GraphQLField::EMPTY,
+    type_for_derived_types: nil, graphql_only: nil, singular: nil,
+    sortable: nil, filterable: nil, aggregatable: nil, groupable: nil,
+    backing_indexing_field: nil, as_input: false, legacy_grouping_schema: false
+  )
+    type_ref = schema_def_state.type_ref(type)
+    super(
+      name: name,
+      original_type: type_ref,
+      parent_type: parent_type,
+      original_type_for_derived_types: type_for_derived_types ? schema_def_state.type_ref(type_for_derived_types) : type_ref,
+      schema_def_state: schema_def_state,
+      accuracy_confidence: accuracy_confidence,
+      filter_customizations: [],
+      grouped_by_customizations: [],
+      sub_aggregations_customizations: [],
+      aggregated_values_customizations: [],
+      sort_order_enum_value_customizations: [],
+      args: {},
+      sortable: sortable,
+      filterable: filterable,
+      aggregatable: aggregatable,
+      groupable: groupable,
+      graphql_only: graphql_only,
+      source: nil,
+      runtime_field_script: nil,
+      # Note: we named the keyword argument `singular` (with no `_name` suffix) for consistency with
+      # other schema definition APIs, which also use `singular:` instead of `singular_name:`. We include
+      # the `_name` suffix on the attribute for clarity.
+      singular_name: singular,
+      name_in_index: name_in_index,
+      non_nullable_in_json_schema: false,
+      backing_indexing_field: backing_indexing_field,
+      as_input: as_input,
+      legacy_grouping_schema: legacy_grouping_schema
+    )
+
+    if name != name_in_index && name_in_index&.include?(".") && !graphql_only
+      raise Errors::SchemaError, "#{self} has an invalid `name_in_index`: #{name_in_index.inspect}. Only `graphql_only: true` fields can have a `name_in_index` that references a child field."
+    end
+
+    schema_def_state.register_user_defined_field(self)
+    yield self if block_given?
+  end
+
+  # @private
+  @@initialize_param_names = instance_method(:initialize).parameters.map(&:last).to_set
+
+  # must come after we capture the initialize params.
+  prepend Mixins::VerifiesGraphQLName
+
+  # @return [TypeReference] the type of this field
+  def type
+    # Here we lazily convert the `original_type` to an input type as needed. This must be lazy because
+    # the logic of `as_input` depends on detecting whether the type is an enum type, which it may not
+    # be able to do right away--we assume not if we can't tell, and retry every time this method is called.
+    original_type.to_final_form(as_input: as_input)
+  end
+
+  # @return [TypeReference] the type of the corresponding field on derived types (usually this is the same as {#type}).
+  #
+  # @private
+  def type_for_derived_types
+    original_type_for_derived_types.to_final_form(as_input: as_input)
+  end
+
+  # @note For each field defined in your schema that is filterable, a corresponding filtering field will be created on the
+  #   `*FilterInput` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding filtering field that will be generated for this
+  # field.
+  #
+  # @yield [Field] derived filtering field
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignFilterInput.organizationId` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "organizationId", "ID" do |f|
+  #         f.customize_filter_field do |ff|
+  #           ff.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_filter_field(&customization_block)
+    filter_customizations << customization_block
+  end
+
+  # @note For each field defined in your schema that is aggregatable, a corresponding `aggregatedValues` field will be created on the
+  #   `*AggregatedValues` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding `aggregatedValues` field that will be generated for
+  # this field.
+  #
+  # @yield [Field] derived aggregated values field
+  # @return [void]
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignAggregatedValues.adImpressions` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "adImpressions", "Int" do |f|
+  #         f.customize_aggregated_values_field do |avf|
+  #           avf.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_aggregated_values_field(&customization_block)
+    aggregated_values_customizations << customization_block
+  end
+
+  # @note For each field defined in your schema that is groupable, a corresponding `groupedBy` field will be created on the
+  #   `*AggregationGroupedBy` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding `groupedBy` field that will be generated for this
+  # field.
+  #
+  # @yield [Field] derived grouped by field
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignGroupedBy.organizationId` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "organizationId", "ID" do |f|
+  #         f.customize_grouped_by_field do |gbf|
+  #           gbf.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_grouped_by_field(&customization_block)
+    grouped_by_customizations << customization_block
+  end
+
+  # @note For each field defined in your schema that is sub-aggregatable (e.g. list fields indexed using the `nested` mapping type),
+  # a corresponding field will be created on the `*AggregationSubAggregations` type derived from the parent object type.
+  #
+  # Registers a customization callback that will be applied to the corresponding `subAggregations` field that will be generated for
+  # this field.
+  #
+  # @yield [Field] derived sub-aggregations field
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `TransactionAggregationSubAggregations.fees` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Transaction" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "fees", "[Money!]!" do |f|
+  #         f.mapping type: "nested"
+  #
+  #         f.customize_sub_aggregations_field do |saf|
+  #           # Adds a `@deprecated` directive to the `PaymentAggregationSubAggregations.fees`
+  #           # field without also adding it to the `Payment.fees` field.
+  #           saf.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "transactions"
+  #     end
+  #
+  #     schema.object_type "Money" do |t|
+  #       t.field "amount", "Int"
+  #       t.field "currency", "String"
+  #     end
+  #   end
+  def customize_sub_aggregations_field(&customization_block)
+    sub_aggregations_customizations << customization_block
+  end
+
+  # @note for each sortable field, enum values will be generated on the derived sort order enum type allowing you to
+  #   sort by the field `ASC` or `DESC`.
+  #
+  # Registers a customization callback that will be applied to the corresponding enum values that will be generated for this field
+  # on the derived `SortOrder` enum type.
+  #
+  # @yield [SortOrderEnumValue] derived sort order enum value
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sub_aggregations_field
+  # @see #on_each_generated_schema_element
+  #
+  # @example Mark `CampaignSortOrder.organizationId_(ASC|DESC)` with `@deprecated`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Campaign" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "organizationId", "ID" do |f|
+  #         f.customize_sort_order_enum_values do |soev|
+  #           soev.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "campaigns"
+  #     end
+  #   end
+  def customize_sort_order_enum_values(&customization_block)
+    sort_order_enum_value_customizations << customization_block
+  end
+
+  # When you define a {Field} on an {ObjectType} or {InterfaceType}, ElasticGraph generates up to 6 different GraphQL schema elements
+  # for it:
+  #
+  # * A {Field} is generated on the parent {ObjectType} or {InterfaceType} (that is, this field itself). This is used by clients to
+  #   ask for values for the field in a response.
+  # * A {Field} may be generated on the `*FilterInput` {InputType} derived from the parent {ObjectType} or {InterfaceType}. This is
+  #   used by clients to specify how the query should filter.
+  # * A {Field} may be generated on the `*AggregationGroupedBy` {ObjectType} derived from the parent {ObjectType} or {InterfaceType}.
+  #   This is used by clients to specify how aggregations should be grouped.
+  # * A {Field} may be generated on the `*AggregatedValues` {ObjectType} derived from the parent {ObjectType} or {InterfaceType}.
+  #   This is used by clients to apply aggregation functions (e.g. `sum`, `max`, `min`, etc) to a set of field values for a group.
+  # * A {Field} may be generated on the `*AggregationSubAggregations` {ObjectType} derived from the parent {ObjectType} or
+  #   {InterfaceType}. This is used by clients to perform sub-aggregations on list fields indexed using the `nested` mapping type.
+  # * Multiple {EnumValue}s (both `*_ASC` and `*_DESC`) are generated on the `*SortOrder` {EnumType} derived from the parent indexed
+  #   {ObjectType}. This is used by clients to sort by a field.
+  #
+  # This method registers a customization callback which is applied to every element that is generated for this field.
+  #
+  # @yield [Field, EnumValue] the schema element
+  # @return [void]
+  # @see #customize_aggregated_values_field
+  # @see #customize_filter_field
+  # @see #customize_grouped_by_field
+  # @see #customize_sort_order_enum_values
+  # @see #customize_sub_aggregations_field
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Transaction" do |t|
+  #       t.field "id", "ID"
+  #
+  #       t.field "amount", "Int" do |f|
+  #         f.on_each_generated_schema_element do |element|
+  #           # Adds a `@deprecated` directive to every GraphQL schema element generated for `amount`:
+  #           #
+  #           # - The `Transaction.amount` field.
+  #           # - The `TransactionFilterInput.amount` field.
+  #           # - The `TransactionAggregationGroupedBy.amount` field.
+  #           # - The `TransactionAggregatedValues.amount` field.
+  #           # - The `TransactionSortOrder.amount_ASC` and`TransactionSortOrder.amount_DESC` enum values.
+  #           element.directive "deprecated"
+  #         end
+  #       end
+  #
+  #       t.index "transactions"
+  #     end
+  #   end
+  def on_each_generated_schema_element(&customization_block)
+    customization_block.call(self)
+    customize_filter_field(&customization_block)
+    customize_aggregated_values_field(&customization_block)
+    customize_grouped_by_field(&customization_block)
+    customize_sub_aggregations_field(&customization_block)
+    customize_sort_order_enum_values(&customization_block)
+  end
+
+  # (see Mixins::HasTypeInfo#json_schema)
+  def json_schema(nullable: nil, **options)
+    if options.key?(:type)
+      raise Errors::SchemaError, "Cannot override JSON schema type of field `#{name}` with `#{options.fetch(:type)}`"
+    end
+
+    case nullable
+    when true
+      raise Errors::SchemaError, "`nullable: true` is not allowed on a field--just declare the GraphQL field as being nullable (no `!` suffix) instead."
+    when false
+      self.non_nullable_in_json_schema = true
+    end
+
+    super(**options)
+  end
+
+  # Configures ElasticGraph to source a field’s value from a related object. This can be used to denormalize data at ingestion time to
+  # support filtering, grouping, sorting, or aggregating data on a field from a related object.
+  #
+  # @param relationship [String] name of a relationship defined with {TypeWithSubfields#relates_to_one} using an inbound foreign key
+  #   which contains the the field you wish to source values from
+  # @param field_path [String] dot-separated path to the field on the related type containing values that should be copied to this
+  #   field
+  # @return [void]
+  #
+  # @example Source `City.currency` from `Country.currency`
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Country" do |t|
+  #       t.field "id", "ID"
+  #       t.field "name", "String"
+  #       t.field "currency", "String"
+  #       t.relates_to_one "capitalCity", "City", via: "capitalCityId", dir: :out
+  #       t.index "countries"
+  #     end
+  #
+  #     schema.object_type "City" do |t|
+  #       t.field "id", "ID"
+  #       t.field "name", "String"
+  #       t.relates_to_one "capitalOf", "Country", via: "capitalCityId", dir: :in
+  #
+  #       t.field "currency", "String" do |f|
+  #         f.sourced_from "capitalOf", "currency"
+  #       end
+  #
+  #       t.index "cities"
+  #     end
+  #   end
+  def sourced_from(relationship, field_path)
+    self.source = schema_def_state.factory.new_field_source(
+      relationship_name: relationship,
+      field_path: field_path
+    )
+  end
+
+  # @private
+  def runtime_script(script)
+    self.runtime_field_script = script
+  end
+
+  # Registers an old name that this field used to have in a prior version of the schema.
+  #
+  # @note In situations where this API applies, ElasticGraph will give you an error message indicating that you need to use this API
+  #   or {TypeWithSubfields#deleted_field}. Likewise, when ElasticGraph no longer needs to know about this, it'll give you a warning
+  #   indicating the call to this method can be removed.
+  #
+  # @param old_name [String] old name this field used to have in a prior version of the schema
+  # @return [void]
+  #
+  # @example Indicate that `Widget.description` used to be called `Widget.notes`.
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Widget" do |t|
+  #       t.field "description", "String" do |f|
+  #         f.renamed_from "notes"
+  #       end
+  #     end
+  #   end
+  def renamed_from(old_name)
+    schema_def_state.register_renamed_field(
+      parent_type.name,
+      from: old_name,
+      to: name,
+      defined_at: caller_locations(1, 1).first, # : ::Thread::Backtrace::Location
+      defined_via: %(field.renamed_from "#{old_name}")
+    )
+  end
+
+  # @private
+  def to_sdl(type_structure_only: false, default_value_sdl: nil, &arg_selector)
+    if type_structure_only
+      "#{name}#{args_sdl(joiner: ", ", &arg_selector)}: #{type.name}"
+    else
+      args_sdl = args_sdl(joiner: "\n  ", after_opening_paren: "\n  ", &arg_selector)
+      "#{formatted_documentation}#{name}#{args_sdl}: #{type.name}#{default_value_sdl} #{directives_sdl}".strip
+    end
+  end
+
+  # Indicates if this field is sortable. Sortable fields will have corresponding `_ASC` and `_DESC` values generated in the
+  # sort order {EnumType} of the parent indexed type.
+  #
+  # By default, the sortability is inferred by the field type and mapping. For example, list fields are not sortable,
+  # and fields mapped as `text` are not sortable either. Fields are sortable in most other cases.
+  #
+  # The `sortable: true` option can be used to force a field to be sortable.
+  #
+  # @return [Boolean] true if this field is sortable
+  def sortable?
+    return sortable unless sortable.nil?
+
+    # List fields are not sortable by default. We'd need to provide the datastore a sort mode option:
+    # https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#_sort_mode_option
+    return false if type.list?
+
+    # Boolean fields are not sortable by default.
+    #   - Boolean: sorting all falses before all trues (or whatever) is not generally interesting.
+    return false if type.unwrap_non_null.boolean?
+
+    # Elasticsearch/OpenSearch do not support sorting text fields:
+    # > Text fields are not used for sorting...
+    # (from https://www.elastic.co/guide/en/elasticsearch/reference/current/the datastore.html#text)
+    return false if text?
+
+    # If the type uses custom mapping type we don't know how if the datastore can sort by it, so we assume it's not sortable.
+    return false if type.as_object_type&.has_custom_mapping_type?
+
+    # Default every other field to being sortable.
+    true
+  end
+
+  # Indicates if this field is filterable. Filterable fields will be available in the GraphQL schema under the `filter` argument.
+  #
+  # Most fields are filterable, except when:
+  #
+  # - It's a relation. Relation fields require us to load the related data from another index and can't be filtered on.
+  # - The field is an object type that isn't itself filterable (e.g. due to having no filterable fields or whatever).
+  # - Explicitly disabled with `filterable: false`.
+  #
+  # @return [Boolean]
+  def filterable?
+    # Object types that use custom index mappings (as `GeoLocation` does) aren't filterable
+    # by default since we can't guess what datastore filtering capabilities they have. We've implemented
+    # filtering support for `GeoLocation` fields, though, so we need to explicitly make it fliterable here.
+    # TODO: clean this up using an interface instead of checking for `GeoLocation`.
+    return true if type.fully_unwrapped.name == "GeoLocation"
+
+    return false if relationship || type.fully_unwrapped.as_object_type&.does_not_support?(&:filterable?)
+    return true if filterable.nil?
+    filterable
+  end
+
+  # Indicates if this field is groupable. Groupable fields will be available under `groupedBy` for an aggregations query.
+  #
+  # Groupability is inferred based on the field type and mapping type, or you can use the `groupable: true` option to force it.
+  #
+  # @return [Boolean]
+  def groupable?
+    # If the groupability of the field was specified explicitly when the field was defined, use the specified value.
+    return groupable unless groupable.nil?
+
+    # We don't want the `id` field of an indexed type to be available to group by, because it's the unique primary key
+    # and the groupings would each contain one document. It's simpler and more efficient to just query the raw documents
+    # instead.
+    return false if parent_type.indexed? && name == "id"
+
+    return false if relationship || type.fully_unwrapped.as_object_type&.does_not_support?(&:groupable?)
+
+    # We don't support grouping an entire list of values, but we do support grouping on individual values in a list.
+    # However, we only do so when a `singular_name` has been provided (so that we know what to call the grouped_by field).
+    # The semantics are a little odd (since one document can be duplicated in multiple grouping buckets) so we're ok
+    # with not offering it by default--the user has to opt-in by telling us what to call the field in its singular form.
+    return list_field_groupable_by_single_values? if type.list? && type.fully_unwrapped.leaf?
+
+    # Nested fields will be supported through specific nested aggregation support, and do not
+    # work as expected when grouping on the root document type.
+    return false if nested?
+
+    # Text fields cannot be efficiently grouped on, so make them non-groupable by default.
+    return false if text?
+
+    # In all other cases, default to being groupable.
+    true
+  end
+
+  # Indicates if this field is aggregatable. Aggregatable fields will be available under `aggregatedValues` for an aggregations query.
+  #
+  # Aggregatability is inferred based on the field type and mapping type, or you can use the `aggregatable: true` option to force it.
+  #
+  # @return [Boolean]
+  def aggregatable?
+    return aggregatable unless aggregatable.nil?
+    return false if relationship
+
+    # We don't yet support aggregating over subfields of a `nested` field.
+    # TODO: add support for aggregating over subfields of `nested` fields.
+    return false if nested?
+
+    # Text fields are not efficiently aggregatable (and you'll often get errors from the datastore if you attempt to aggregate them).
+    return false if text?
+
+    type_for_derived_types.fully_unwrapped.as_object_type&.supports?(&:aggregatable?) || index_leaf?
+  end
+
+  # Indicates if this field can be used as the basis for a sub-aggregation. Sub-aggregatable fields will be available under
+  # `subAggregations` for an aggregations query.
+  #
+  # Only nested fields, and object fields which have nested fields, can be sub-aggregated.
+  #
+  # @return [Boolean]
+  def sub_aggregatable?
+    return false if relationship
+
+    nested? || type_for_derived_types.fully_unwrapped.as_object_type&.supports?(&:sub_aggregatable?)
+  end
+
+  # Defines an argument on the field.
+  #
+  # @note ElasticGraph takes care of defining arguments for all the query features it supports, so there is generally no need to use
+  #   this API, and it has no way to interpret arbitrary arguments defined on a field. However, it can be useful for extensions that
+  #   extend the {ElasticGraph::GraphQL} query engine. For example, {ElasticGraph::Apollo} uses this API to satisfy the [Apollo
+  #   federation subgraph spec](https://www.apollographql.com/docs/federation/federation-spec/).
+  #
+  # @param name [String] name of the argument
+  # @param value_type [String] type of the argument in GraphQL SDL syntax
+  # @yield [Argument] for further customization
+  #
+  # @example Define an argument on a field
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Product" do |t|
+  #       t.field "name", "String" do |f|
+  #         f.argument "language", "String"
+  #       end
+  #     end
+  #   end
+  def argument(name, value_type, &block)
+    args[name] = schema_def_state.factory.new_argument(
+      self,
+      name,
+      schema_def_state.type_ref(value_type),
+      &block
+    )
+  end
+
+  # The index mapping type in effect for this field. This could come from either the field definition or from the type definition.
+  #
+  # @return [String]
+  def mapping_type
+    backing_indexing_field&.mapping_type || (resolve_mapping || {})["type"]
+  end
+
+  # @private
+  def list_field_groupable_by_single_values?
+    (type.list? || backing_indexing_field&.type&.list?) && !singular_name.nil?
+  end
+
+  # @private
+  def define_aggregated_values_field(parent_type)
+    return unless aggregatable?
+
+    unwrapped_type_for_derived_types = type_for_derived_types.fully_unwrapped
+    aggregated_values_type =
+      if index_leaf?
+        unwrapped_type_for_derived_types.resolved.aggregated_values_type
+      else
+        unwrapped_type_for_derived_types.as_aggregated_values
+      end
+
+    parent_type.field name, aggregated_values_type.name, name_in_index: name_in_index, graphql_only: true do |f|
+      f.documentation derived_documentation("Computed aggregate values for the `#{name}` field")
+      aggregated_values_customizations.each { |block| block.call(f) }
+    end
+  end
+
+  # @private
+  def define_grouped_by_field(parent_type)
+    return unless (field_name = grouped_by_field_name)
+
+    parent_type.field field_name, grouped_by_field_type_name, name_in_index: name_in_index, graphql_only: true do |f|
+      add_grouped_by_field_documentation(f)
+
+      define_legacy_timestamp_grouping_arguments_if_needed(f) if legacy_grouping_schema
+
+      grouped_by_customizations.each { |block| block.call(f) }
+    end
+  end
+
+  # @private
+  def grouped_by_field_type_name
+    unwrapped_type = type_for_derived_types.fully_unwrapped
+    if unwrapped_type.scalar_type_needing_grouped_by_object? && !legacy_grouping_schema
+      unwrapped_type.with_reverted_override.as_grouped_by.name
+    elsif unwrapped_type.leaf?
+      unwrapped_type.name
+    else
+      unwrapped_type.as_grouped_by.name
+    end
+  end
+
+  # @private
+  def add_grouped_by_field_documentation(field)
+    text = if list_field_groupable_by_single_values?
+      derived_documentation(
+        "The individual value from `#{name}` for this group",
+        list_field_grouped_by_doc_note("`#{name}`")
+      )
+    elsif type.list? && type.fully_unwrapped.object?
+      derived_documentation(
+        "The `#{name}` field value for this group",
+        list_field_grouped_by_doc_note("the selected subfields of `#{name}`")
+      )
+    elsif type_for_derived_types.fully_unwrapped.scalar_type_needing_grouped_by_object? && !legacy_grouping_schema
+      derived_documentation("Offers the different grouping options for the `#{name}` value within this group")
+    else
+      derived_documentation("The `#{name}` field value for this group")
+    end
+
+    field.documentation text
+  end
+
+  # @private
+  def grouped_by_field_name
+    return nil unless groupable?
+    list_field_groupable_by_single_values? ? singular_name : name
+  end
+
+  # @private
+  def define_sub_aggregations_field(parent_type:, type:)
+    parent_type.field name, type, name_in_index: name_in_index, graphql_only: true do |f|
+      f.documentation derived_documentation("Used to perform a sub-aggregation of `#{name}`")
+      sub_aggregations_customizations.each { |c| c.call(f) }
+
+      yield f if block_given?
+    end
+  end
+
+  # @private
+  def to_filter_field(parent_type:, for_single_value: !type_for_derived_types.list?)
+    type_prefix = text? ? "Text" : type_for_derived_types.fully_unwrapped.name
+    filter_type = schema_def_state
+      .type_ref(type_prefix)
+      .as_static_derived_type(filter_field_category(for_single_value))
+      .name
+
+    params = to_h
+      .slice(*@@initialize_param_names)
+      .merge(type: filter_type, parent_type: parent_type, name_in_index: name_in_index, type_for_derived_types: nil)
+
+    schema_def_state.factory.new_field(**params).tap do |f|
+      f.documentation derived_documentation(
+        "Used to filter on the `#{name}` field",
+        "Will be ignored if `null` or an empty object is passed"
+      )
+
+      filter_customizations.each { |c| c.call(f) }
+    end
+  end
+
+  # @private
+  def define_relay_pagination_arguments!
+    argument schema_def_state.schema_elements.first.to_sym, "Int" do |a|
+      a.documentation <<~EOS
+        Used in conjunction with the `after` argument to forward-paginate through the `#{name}`.
+        When provided, limits the number of returned results to the first `n` after the provided
+        `after` cursor (or from the start of the `#{name}`, if no `after` cursor is provided).
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+
+    argument schema_def_state.schema_elements.after.to_sym, "Cursor" do |a|
+      a.documentation <<~EOS
+        Used to forward-paginate through the `#{name}`. When provided, the next page after the
+        provided cursor will be returned.
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+
+    argument schema_def_state.schema_elements.last.to_sym, "Int" do |a|
+      a.documentation <<~EOS
+        Used in conjunction with the `before` argument to backward-paginate through the `#{name}`.
+        When provided, limits the number of returned results to the last `n` before the provided
+        `before` cursor (or from the end of the `#{name}`, if no `before` cursor is provided).
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+
+    argument schema_def_state.schema_elements.before.to_sym, "Cursor" do |a|
+      a.documentation <<~EOS
+        Used to backward-paginate through the `#{name}`. When provided, the previous page before the
+        provided cursor will be returned.
+
+        See the [Relay GraphQL Cursor Connections
+        Specification](https://relay.dev/graphql/connections.htm#sec-Arguments) for more info.
+      EOS
+    end
+  end
+
+  # Converts this field to an `Indexing::FieldReference`, which contains all the attributes involved
+  # in building an `Indexing::Field`. Notably, we cannot actually convert to an `Indexing::Field` at
+  # the point this method is called, because the referenced field type may not have been defined
+  # yet. We don't need an actual `Indexing::Field` until the very end of the schema definition process,
+  # when we are dumping the artifacts. However, we need this at field definition time so that we
+  # can correctly detect duplicate indexing field issues when a field is defined. (This is used
+  # in `TypeWithSubfields#field`).
+  #
+  # @private
+  def to_indexing_field_reference
+    return nil if graphql_only
+
+    Indexing::FieldReference.new(
+      name: name,
+      name_in_index: name_in_index,
+      type: non_nullable_in_json_schema ? type.wrap_non_null : type,
+      mapping_options: mapping_options,
+      json_schema_options: json_schema_options,
+      accuracy_confidence: accuracy_confidence,
+      source: source,
+      runtime_field_script: runtime_field_script
+    )
+  end
+
+  # Converts this field to its `IndexingField` form.
+  #
+  # @private
+  def to_indexing_field
+    to_indexing_field_reference&.resolve
+  end
+
+  # @private
+  def resolve_mapping
+    to_indexing_field&.mapping
+  end
+
+  # Returns the string paths to the list fields that we need to index counts for.
+  # We do this to support the ability to filter on the size of a list.
+  #
+  # @private
+  def paths_to_lists_for_count_indexing(has_list_ancestor: false)
+    self_path = (has_list_ancestor || type.list?) ? [name_in_index] : []
+
+    nested_paths =
+      # Nested fields get indexed as separate hidden documents:
+      # https://www.elastic.co/guide/en/elasticsearch/reference/8.8/nested.html
+      #
+      # Given that, the counts of any `nested` list subfields will go in a `__counts` field on the
+      # separate hidden document.
+      if !nested? && (object_type = type.fully_unwrapped.as_object_type)
+        object_type.indexing_fields_by_name_in_index.values.flat_map do |sub_field|
+          sub_field.paths_to_lists_for_count_indexing(has_list_ancestor: has_list_ancestor || type.list?).map do |sub_path|
+            "#{name_in_index}#{LIST_COUNTS_FIELD_PATH_KEY_SEPARATOR}#{sub_path}"
+          end
+        end
+      else
+        []
+      end
+
+    self_path + nested_paths
+  end
+
+  # Indicates if this field is a leaf value in the index.  Note that GraphQL leaf values
+  # are always leaf values in the index but the inverse is not always true. For example,
+  # a `GeoLocation` field is not a leaf in GraphQL (because `GeoLocation` is an object
+  # type with subfields) but in the index we use a single `geo_point` mapping type, which
+  # is a single unit, so we consider it an index leaf.
+  #
+  # @private
+  def index_leaf?
+    type_for_derived_types.fully_unwrapped.leaf? || DATASTORE_PROPERTYLESS_OBJECT_TYPES.include?(mapping_type)
+  end
+
+  # @private
+  ACCURACY_SCORES = {
+    # :high is assigned to `Field`s that are generated directly from GraphQL fields or :extra_fields.
+    # For these, we know everything available to us in the schema about them.
+    high: 3,
+
+    # :medium is assigned to `Field`s that are inferred from the id fields required by a relation.
+    # We make logical guesses about the `indexing_field_type` but if the field is also manually defined,
+    # it could be slightly different (e.g. additional json schema validations), so we have medium
+    # confidence of these.
+    medium: 2,
+
+    # :low is assigned to the ElastcField inferred for the foreign key of an inbound relation. The
+    # nullability/cardinality of the foreign key field cannot be known from the relation metadata,
+    # so we just guess what seems safest (`[:nullable]`). If the field is defined another way
+    # we should prefer it, so we give these fields :low confidence.
+    low: 1
+  }
+
+  # Given two fields, picks the one that is most accurate. If they have the same accuracy
+  # confidence, yields to a block to force it to deal with the discrepancy, unless the fields
+  # are exactly equal (in which case we can return either).
+  #
+  # @private
+  def self.pick_most_accurate_from(field1, field2, to_comparable: ->(it) { it })
+    return field1 if to_comparable.call(field1) == to_comparable.call(field2)
+    yield if field1.accuracy_confidence == field2.accuracy_confidence
+    # Array#max_by can return nil (when called on an empty array), but our steep type is non-nil.
+    # Since it's not smart enough to realize the non-empty-array-usage of `max_by` won't return nil,
+    # we have to cast it to untyped here.
+    _ = [field1, field2].max_by { |f| ACCURACY_SCORES.fetch(f.accuracy_confidence) }
+  end
+
+  # Indicates if the field uses the `nested` mapping type.
+  #
+  # @private
+  def nested?
+    mapping_type == "nested"
+  end
+
+  # Records the `ComputationDetail` that should be on the `runtime_metadata_graphql_field`.
+  #
+  # @private
+  def (empty_bucket_value:, function:)
+    self.computation_detail = SchemaArtifacts::RuntimeMetadata::ComputationDetail.new(
+      empty_bucket_value: empty_bucket_value,
+      function: function
+    )
+  end
+
+  # Lazily creates and returns a GraphQLField using the field's {#name_in_index}, {#computation_detail},
+  # and {#relationship}.
+  #
+  # @private
+  def 
+    SchemaArtifacts::RuntimeMetadata::GraphQLField.new(
+      name_in_index: name_in_index,
+      computation_detail: computation_detail,
+      relation: relationship&.
+    )
+  end
+
+  private
+
+  def args_sdl(joiner:, after_opening_paren: "", &arg_selector)
+    selected_args = args.values.select(&arg_selector)
+    args_sdl = selected_args.map(&:to_sdl).flat_map { |s| s.split("\n") }.join(joiner)
+    return nil if args_sdl.empty?
+    "(#{after_opening_paren}#{args_sdl})"
+  end
+
+  # Indicates if the field uses the `text` mapping type.
+  def text?
+    mapping_type == "text"
+  end
+
+  def define_legacy_timestamp_grouping_arguments_if_needed(grouping_field)
+    case type.fully_unwrapped.name
+    when "Date"
+      grouping_field.argument schema_def_state.schema_elements.granularity, "DateGroupingGranularity!" do |a|
+        a.documentation "Determines the grouping granularity for this field."
+      end
+
+      grouping_field.argument schema_def_state.schema_elements.offset_days, "Int" do |a|
+        a.documentation <<~EOS
+          Number of days (positive or negative) to shift the `Date` boundaries of each date grouping bucket.
+
+          For example, when grouping by `YEAR`, this can be used to align the buckets with fiscal or school years instead of calendar years.
+        EOS
+      end
+    when "DateTime"
+      grouping_field.argument schema_def_state.schema_elements.granularity, "DateTimeGroupingGranularity!" do |a|
+        a.documentation "Determines the grouping granularity for this field."
+      end
+
+      grouping_field.argument schema_def_state.schema_elements.time_zone, "TimeZone" do |a|
+        a.documentation "The time zone to use when determining which grouping a `DateTime` value falls in."
+        a.default "UTC"
+      end
+
+      grouping_field.argument schema_def_state.schema_elements.offset, "DateTimeGroupingOffsetInput" do |a|
+        a.documentation <<~EOS
+          Amount of offset (positive or negative) to shift the `DateTime` boundaries of each grouping bucket.
+
+          For example, when grouping by `WEEK`, you can shift by 24 hours to change what day-of-week weeks are considered to start on.
+        EOS
+      end
+    end
+  end
+
+  def list_field_grouped_by_doc_note(individual_value_selection_description)
+    <<~EOS.strip
+      Note: `#{name}` is a collection field, but selecting this field will group on individual values of #{individual_value_selection_description}.
+      That means that a document may be grouped into multiple aggregation groupings (i.e. when its `#{name}`
+      field has multiple values) leading to some data duplication in the response. However, if a value shows
+      up in `#{name}` multiple times for a single document, that document will only be included in the group
+      once
+    EOS
+  end
+
+  # Determines the suffix of the filter field derived for this field. The suffix used determines
+  # the filtering capabilities (e.g. filtering on a single value vs a list of values with `any_satisfy`).
+  def filter_field_category(for_single_value)
+    return :filter_input if for_single_value
+
+    # For an index leaf field, there are no further nesting paths to traverse. We want to directly
+    # use a `ListFilterInput` type (e.g. `IntListFilterInput`) to offer `any_satisfy` filtering at this level.
+    return :list_filter_input if index_leaf?
+
+    # If it's a list-of-objects field we require the user to tell us what mapping type they want to
+    # use, which determines the suffix (and is handled below). Otherwise, we want to use `FieldsListFilterInput`.
+    # We are within a list filtering context (as indicated by `for_single_value` being false) without
+    # being at an index leaf field, so we must use `FieldsListFilterInput` as there are further nesting paths
+    # on the document and we want to provide `any_satisfy` at the leaf fields.
+    return :fields_list_filter_input unless type_for_derived_types.list?
+
+    case mapping_type
+    when "nested" then :list_filter_input
+    when "object" then :fields_list_filter_input
+    else
+      raise Errors::SchemaError, <<~EOS
+        `#{parent_type.name}.#{name}` is a list-of-objects field, but the mapping type has not been explicitly specified. Elasticsearch and OpenSearch
+        offer two ways to index list-of-objects fields. It cannot be changed on an existing field without dropping the index and recreating it (losing
+        any existing indexed data!), and there are nuanced tradeoffs involved here, so ElasticGraph provides no default mapping in this situation.
+
+        If you're currently prototyping and don't want to spend time weighing this tradeoff, we recommend you do this:
+
+        ```
+        t.field "#{name}", "#{type.name}" do |f|
+          # Here we are opting for flexibility (nested) over pure performance (object).
+          # TODO: evaluate if we want to stick with `nested` before going to production.
+          f.mapping type: "nested"
+        end
+        ```
+
+        Read on for details of the tradeoff involved here.
+
+        -----------------------------------------------------------------------------------------------------------------------------
+
+        Here are the options:
+
+        1) `f.mapping type: "object"` will cause each field path to be indexed as a separate "flattened" list.
+
+        For example, given a `Film` document like this:
+
+        ```
+        {
+          "name": "The Empire Strikes Back",
+          "characters": [
+            {"first": "Luke", "last": "Skywalker"},
+            {"first": "Han", "last": "Solo"}
+          ]
+        }
+        ```
+
+        ...the data will look like this in the inverted Lucene index:
+
+        ```
+        {
+          "name": "The Empire Strikes Back",
+          "characters.first": ["Luke", "Han"],
+          "characters.last": ["Skywalker", "Solo"]
+        }
+        ```
+
+        This is highly efficient, but there is no way to search on multiple fields of a character and be sure that the matching values came from the same character.
+        ElasticGraph models this in the filtering API it offers for this case:
+
+        ```
+        query {
+          films(filter: {
+            characters: {
+              first: {#{schema_def_state.schema_elements.any_satisfy}: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Luke"]}}
+              last: {#{schema_def_state.schema_elements.any_satisfy}: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Skywalker"]}}
+            }
+          }) {
+            # ...
+          }
+        }
+        ```
+
+        As suggested by this filtering API, this will match any film that has a character with a first name of "Luke" and a character
+        with the last name of "Skywalker", but this could be satisfied by two separate characters.
+
+        2) `f.mapping type: "nested"` will cause each _object_ in the list to be indexed as a separate hidden document, preserving the independence of each.
+
+        Given a `Film` document like "The Empire Strikes Back" from above, the `nested` type will index separate hidden documents for each character. This
+        allows ElasticGraph to offer this filtering API instead:
+
+        ```
+        query {
+          films(filter: {
+            characters: {#{schema_def_state.schema_elements.any_satisfy}: {
+              first: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Luke"]}
+              last: {#{schema_def_state.schema_elements.equal_to_any_of}: ["Skywalker"]}
+            }}
+          }) {
+            # ...
+          }
+        }
+        ```
+
+        As suggested by this filtering API, this will only match films that have a character named "Luke Skywalker". However, the Elasticsearch docs[^1][^2] warn
+        that the `nested` mapping type can lead to performance problems, and index sorting cannot be configured[^3] when the `nested` type is used.
+
+        [^1]: https://www.elastic.co/guide/en/elasticsearch/reference/8.10/nested.html
+        [^2]: https://www.elastic.co/guide/en/elasticsearch/reference/8.10/joining-queries.html
+        [^3]: https://www.elastic.co/guide/en/elasticsearch/reference/8.10/index-modules-index-sorting.html
+      EOS
+    end
+  end
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #aggregatable?Boolean + + + + + +

+
+

Indicates if this field is aggregatable. Aggregatable fields will be available under aggregatedValues for an aggregations query.

+ +

Aggregatability is inferred based on the field type and mapping type, or you can use the aggregatable: true option to force it.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 584
+
+def aggregatable?
+  return aggregatable unless aggregatable.nil?
+  return false if relationship
+
+  # We don't yet support aggregating over subfields of a `nested` field.
+  # TODO: add support for aggregating over subfields of `nested` fields.
+  return false if nested?
+
+  # Text fields are not efficiently aggregatable (and you'll often get errors from the datastore if you attempt to aggregate them).
+  return false if text?
+
+  type_for_derived_types.fully_unwrapped.as_object_type&.supports?(&:aggregatable?) || index_leaf?
+end
+
+
+ +
+

+ + #argument(name, value_type) {|Argument| ... } ⇒ Object + + + + + +

+
+ +
+ Note: +

ElasticGraph takes care of defining arguments for all the query features it supports, so there is generally no need to use +this API, and it has no way to interpret arbitrary arguments defined on a field. However, it can be useful for extensions that +extend the GraphQL query engine. For example, Apollo uses this API to satisfy the Apollo +federation subgraph spec.

+
+
+ +

Defines an argument on the field.

+ + +
+
+
+ +
+

Examples:

+ + +

Define an argument on a field

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Product" do |t|
+    t.field "name", "String" do |f|
+      f.argument "language", "String"
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    name of the argument

    +
    + +
  • + +
  • + + value_type + + + (String) + + + + — +

    type of the argument in GraphQL SDL syntax

    +
    + +
  • + +
+ +

Yields:

+
    + +
  • + + + (Argument) + + + + — +

    for further customization

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+629
+630
+631
+632
+633
+634
+635
+636
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 629
+
+def argument(name, value_type, &block)
+  args[name] = schema_def_state.factory.new_argument(
+    self,
+    name,
+    schema_def_state.type_ref(value_type),
+    &block
+  )
+end
+
+
+ +
+

+ + #customize_aggregated_values_field {|Field| ... } ⇒ void + + + + + +

+
+ +
+ Note: +

For each field defined in your schema that is aggregatable, a corresponding aggregatedValues field will be created on the +*AggregatedValues type derived from the parent object type.

+
+
+ +

This method returns an undefined value.

Registers a customization callback that will be applied to the corresponding aggregatedValues field that will be generated for +this field.

+ + +
+
+
+ +
+

Examples:

+ + +

Mark CampaignAggregatedValues.adImpressions with @deprecated

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID"
+
+    t.field "adImpressions", "Int" do |f|
+      f.customize_aggregated_values_field do |avf|
+        avf.directive "deprecated"
+      end
+    end
+
+    t.index "campaigns"
+  end
+end
+ +
+ +

Yields:

+
    + +
  • + + + (Field) + + + + — +

    derived aggregated values field

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+232
+233
+234
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 232
+
+def customize_aggregated_values_field(&customization_block)
+  aggregated_values_customizations << customization_block
+end
+
+
+ +
+

+ + #customize_filter_field {|Field| ... } ⇒ void + + + + + +

+
+ +
+ Note: +

For each field defined in your schema that is filterable, a corresponding filtering field will be created on the +*FilterInput type derived from the parent object type.

+
+
+ +

This method returns an undefined value.

Registers a customization callback that will be applied to the corresponding filtering field that will be generated for this +field.

+ + +
+
+
+ +
+

Examples:

+ + +

Mark CampaignFilterInput.organizationId with @deprecated

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID"
+
+    t.field "organizationId", "ID" do |f|
+      f.customize_filter_field do |ff|
+        ff.directive "deprecated"
+      end
+    end
+
+    t.index "campaigns"
+  end
+end
+ +
+ +

Yields:

+
    + +
  • + + + (Field) + + + + — +

    derived filtering field

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+200
+201
+202
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 200
+
+def customize_filter_field(&customization_block)
+  filter_customizations << customization_block
+end
+
+
+ +
+

+ + #customize_grouped_by_field {|Field| ... } ⇒ void + + + + + +

+
+ +
+ Note: +

For each field defined in your schema that is groupable, a corresponding groupedBy field will be created on the +*AggregationGroupedBy type derived from the parent object type.

+
+
+ +

This method returns an undefined value.

Registers a customization callback that will be applied to the corresponding groupedBy field that will be generated for this +field.

+ + +
+
+
+ +
+

Examples:

+ + +

Mark CampaignGroupedBy.organizationId with @deprecated

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID"
+
+    t.field "organizationId", "ID" do |f|
+      f.customize_grouped_by_field do |gbf|
+        gbf.directive "deprecated"
+      end
+    end
+
+    t.index "campaigns"
+  end
+end
+ +
+ +

Yields:

+
    + +
  • + + + (Field) + + + + — +

    derived grouped by field

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+264
+265
+266
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 264
+
+def customize_grouped_by_field(&customization_block)
+  grouped_by_customizations << customization_block
+end
+
+
+ +
+

+ + #customize_sort_order_enum_values {|SortOrderEnumValue| ... } ⇒ void + + + + + +

+
+ +
+ Note: +

for each sortable field, enum values will be generated on the derived sort order enum type allowing you to +sort by the field ASC or DESC.

+
+
+ +

This method returns an undefined value.

Registers a customization callback that will be applied to the corresponding enum values that will be generated for this field +on the derived SortOrder enum type.

+ + +
+
+
+ +
+

Examples:

+ + +

Mark CampaignSortOrder.organizationId_(ASC|DESC) with @deprecated

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID"
+
+    t.field "organizationId", "ID" do |f|
+      f.customize_sort_order_enum_values do |soev|
+        soev.directive "deprecated"
+      end
+    end
+
+    t.index "campaigns"
+  end
+end
+ +
+ +

Yields:

+ + +

See Also:

+ + +
+ + + + +
+
+
+
+337
+338
+339
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 337
+
+def customize_sort_order_enum_values(&customization_block)
+  sort_order_enum_value_customizations << customization_block
+end
+
+
+ +
+

+ + #customize_sub_aggregations_field {|Field| ... } ⇒ void + + + + + +

+
+ +
+ Note: +

For each field defined in your schema that is sub-aggregatable (e.g. list fields indexed using the nested mapping type),

+
+
+ +

This method returns an undefined value.

a corresponding field will be created on the *AggregationSubAggregations type derived from the parent object type.

+ +

Registers a customization callback that will be applied to the corresponding subAggregations field that will be generated for +this field.

+ + +
+
+
+ +
+

Examples:

+ + +

Mark TransactionAggregationSubAggregations.fees with @deprecated

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Transaction" do |t|
+    t.field "id", "ID"
+
+    t.field "fees", "[Money!]!" do |f|
+      f.mapping type: "nested"
+
+      f.customize_sub_aggregations_field do |saf|
+        # Adds a `@deprecated` directive to the `PaymentAggregationSubAggregations.fees`
+        # field without also adding it to the `Payment.fees` field.
+        saf.directive "deprecated"
+      end
+    end
+
+    t.index "transactions"
+  end
+
+  schema.object_type "Money" do |t|
+    t.field "amount", "Int"
+    t.field "currency", "String"
+  end
+end
+ +
+ +

Yields:

+
    + +
  • + + + (Field) + + + + — +

    derived sub-aggregations field

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+305
+306
+307
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 305
+
+def customize_sub_aggregations_field(&customization_block)
+  sub_aggregations_customizations << customization_block
+end
+
+
+ +
+

+ + #filterable?Boolean + + + + + +

+
+

Indicates if this field is filterable. Filterable fields will be available in the GraphQL schema under the filter argument.

+ +

Most fields are filterable, except when:

+ +
    +
  • It’s a relation. Relation fields require us to load the related data from another index and can’t be filtered on.
  • +
  • The field is an object type that isn’t itself filterable (e.g. due to having no filterable fields or whatever).
  • +
  • Explicitly disabled with filterable: false.
  • +
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 534
+
+def filterable?
+  # Object types that use custom index mappings (as `GeoLocation` does) aren't filterable
+  # by default since we can't guess what datastore filtering capabilities they have. We've implemented
+  # filtering support for `GeoLocation` fields, though, so we need to explicitly make it fliterable here.
+  # TODO: clean this up using an interface instead of checking for `GeoLocation`.
+  return true if type.fully_unwrapped.name == "GeoLocation"
+
+  return false if relationship || type.fully_unwrapped.as_object_type&.does_not_support?(&:filterable?)
+  return true if filterable.nil?
+  filterable
+end
+
+
+ +
+

+ + #groupable?Boolean + + + + + +

+
+

Indicates if this field is groupable. Groupable fields will be available under groupedBy for an aggregations query.

+ +

Groupability is inferred based on the field type and mapping type, or you can use the groupable: true option to force it.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 551
+
+def groupable?
+  # If the groupability of the field was specified explicitly when the field was defined, use the specified value.
+  return groupable unless groupable.nil?
+
+  # We don't want the `id` field of an indexed type to be available to group by, because it's the unique primary key
+  # and the groupings would each contain one document. It's simpler and more efficient to just query the raw documents
+  # instead.
+  return false if parent_type.indexed? && name == "id"
+
+  return false if relationship || type.fully_unwrapped.as_object_type&.does_not_support?(&:groupable?)
+
+  # We don't support grouping an entire list of values, but we do support grouping on individual values in a list.
+  # However, we only do so when a `singular_name` has been provided (so that we know what to call the grouped_by field).
+  # The semantics are a little odd (since one document can be duplicated in multiple grouping buckets) so we're ok
+  # with not offering it by default--the user has to opt-in by telling us what to call the field in its singular form.
+  return list_field_groupable_by_single_values? if type.list? && type.fully_unwrapped.leaf?
+
+  # Nested fields will be supported through specific nested aggregation support, and do not
+  # work as expected when grouping on the root document type.
+  return false if nested?
+
+  # Text fields cannot be efficiently grouped on, so make them non-groupable by default.
+  return false if text?
+
+  # In all other cases, default to being groupable.
+  true
+end
+
+
+ +
+

+ + #json_schema(nullable: nil, **options) ⇒ void + + + + + +

+
+ +
+ Note: +

We recommend using JSON schema validations in a limited fashion. Validations that are appropriate to apply when data is +entering the system-of-record are often not appropriate on a secondary index like ElasticGraph. Events that violate a JSON +schema validation will fail to index (typically they will be sent to the dead letter queue and page an oncall engineer). If an +ElasticGraph instance is meant to contain all the data of some source system, you probably don’t want it applying stricter +validations than the source system itself has. We recommend limiting your JSON schema validations to situations where +violations would prevent ElasticGraph from operating correctly.

+
+
+ +

This method returns an undefined value.

Defines the JSON schema validations for this field or type. Validations +defined here will be included in the generated json_schemas.yaml artifact, which is used by the ElasticGraph indexer to +validate events before indexing their data in the datastore. In addition, the publisher may use json_schemas.yaml for code +generation and to apply validation before publishing an event to ElasticGraph.

+ +

Can be called multiple times; each time, the options will be merged into the existing options.

+ +

This is required on a ScalarType (since we don’t know how a custom scalar type should be represented in +JSON!). On a ElasticGraph::SchemaDefinition::SchemaElements::Field, this is optional, but can be used to make the JSON schema validation stricter then it +would otherwise be. For example, you could use json_schema maxLength: 30 on a String field to limit the length.

+ +

You can use any of the JSON schema validation keywords here. In addition, nullable: false is supported to configure the +generated JSON schema to disallow null values for the field. Note that if you define a field with a non-nullable GraphQL type +(e.g. Int!), the JSON schema will automatically disallow nulls. However, as explained in the +TypeWithSubfields#field documentation, we generally recommend against defining non-nullable GraphQL fields. +json_schema nullable: false will disallow null values from being indexed, while still keeping the field nullable in the +GraphQL schema. If you think you might want to make a field non-nullable in the GraphQL schema some day, it’s a good idea to use +json_schema nullable: false now to ensure every indexed record has a non-null value for the field.

+ + +
+
+
+ +
+

Examples:

+ + +

Define the JSON schema validations of a custom scalar type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.scalar_type "URL" do |t|
+    t.mapping type: "keyword"
+
+    # JSON schema has a built-in URI format validator:
+    # https://json-schema.org/understanding-json-schema/reference/string.html#resource-identifiers
+    t.json_schema type: "string", format: "uri"
+  end
+end
+ + +

Define additional validations on a field

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Card" do |t|
+    t.field "id", "ID!"
+
+    t.field "expYear", "Int" do |f|
+      # Use JSON schema to ensure the publisher is sending us 4 digit years, not 2 digit years.
+      f.json_schema minimum: 2000, maximum: 2099
+    end
+
+    t.field "expMonth", "Int" do |f|
+      f.json_schema minimum: 1, maximum: 12
+    end
+
+    t.index "cards"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + options + + + (Hash<Symbol, Object>) + + + + — +

    JSON schema options

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 398
+
+def json_schema(nullable: nil, **options)
+  if options.key?(:type)
+    raise Errors::SchemaError, "Cannot override JSON schema type of field `#{name}` with `#{options.fetch(:type)}`"
+  end
+
+  case nullable
+  when true
+    raise Errors::SchemaError, "`nullable: true` is not allowed on a field--just declare the GraphQL field as being nullable (no `!` suffix) instead."
+  when false
+    self.non_nullable_in_json_schema = true
+  end
+
+  super(**options)
+end
+
+
+ +
+

+ + #mapping_typeString + + + + + +

+
+

The index mapping type in effect for this field. This could come from either the field definition or from the type definition.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + +
  • + +
+ +
+ + + + +
+
+
+
+641
+642
+643
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 641
+
+def mapping_type
+  backing_indexing_field&.mapping_type || (resolve_mapping || {})["type"]
+end
+
+
+ +
+

+ + #on_each_generated_schema_element {|Field, EnumValue| ... } ⇒ void + + + + + +

+
+

This method returns an undefined value.

When you define a ElasticGraph::SchemaDefinition::SchemaElements::Field on an ObjectType or InterfaceType, ElasticGraph generates up to 6 different GraphQL schema elements +for it:

+ + + +

This method registers a customization callback which is applied to every element that is generated for this field.

+ + +
+
+
+ +
+

Examples:

+ + +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Transaction" do |t|
+    t.field "id", "ID"
+
+    t.field "amount", "Int" do |f|
+      f.on_each_generated_schema_element do |element|
+        # Adds a `@deprecated` directive to every GraphQL schema element generated for `amount`:
+        #
+        # - The `Transaction.amount` field.
+        # - The `TransactionFilterInput.amount` field.
+        # - The `TransactionAggregationGroupedBy.amount` field.
+        # - The `TransactionAggregatedValues.amount` field.
+        # - The `TransactionSortOrder.amount_ASC` and`TransactionSortOrder.amount_DESC` enum values.
+        element.directive "deprecated"
+      end
+    end
+
+    t.index "transactions"
+  end
+end
+ +
+ +

Yields:

+
    + +
  • + + + (Field, EnumValue) + + + + — +

    the schema element

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+388
+389
+390
+391
+392
+393
+394
+395
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 388
+
+def on_each_generated_schema_element(&customization_block)
+  customization_block.call(self)
+  customize_filter_field(&customization_block)
+  customize_aggregated_values_field(&customization_block)
+  customize_grouped_by_field(&customization_block)
+  customize_sub_aggregations_field(&customization_block)
+  customize_sort_order_enum_values(&customization_block)
+end
+
+
+ +
+

+ + #renamed_from(old_name) ⇒ void + + + + + +

+
+ +
+ Note: +

In situations where this API applies, ElasticGraph will give you an error message indicating that you need to use this API +or TypeWithSubfields#deleted_field. Likewise, when ElasticGraph no longer needs to know about this, it’ll give you a warning +indicating the call to this method can be removed.

+
+
+ +

This method returns an undefined value.

Registers an old name that this field used to have in a prior version of the schema.

+ + +
+
+
+ +
+

Examples:

+ + +

Indicate that Widget.description used to be called Widget.notes.

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Widget" do |t|
+    t.field "description", "String" do |f|
+      f.renamed_from "notes"
+    end
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + old_name + + + (String) + + + + — +

    old name this field used to have in a prior version of the schema

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+473
+474
+475
+476
+477
+478
+479
+480
+481
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 473
+
+def renamed_from(old_name)
+  schema_def_state.register_renamed_field(
+    parent_type.name,
+    from: old_name,
+    to: name,
+    defined_at: caller_locations(1, 1).first, # : ::Thread::Backtrace::Location
+    defined_via: %(field.renamed_from "#{old_name}")
+  )
+end
+
+
+ +
+

+ + #sortable?Boolean + + + + + +

+
+

Indicates if this field is sortable. Sortable fields will have corresponding _ASC and _DESC values generated in the +sort order EnumType of the parent indexed type.

+ +

By default, the sortability is inferred by the field type and mapping. For example, list fields are not sortable, +and fields mapped as text are not sortable either. Fields are sortable in most other cases.

+ +

The sortable: true option can be used to force a field to be sortable.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + + — +

    true if this field is sortable

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 502
+
+def sortable?
+  return sortable unless sortable.nil?
+
+  # List fields are not sortable by default. We'd need to provide the datastore a sort mode option:
+  # https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#_sort_mode_option
+  return false if type.list?
+
+  # Boolean fields are not sortable by default.
+  #   - Boolean: sorting all falses before all trues (or whatever) is not generally interesting.
+  return false if type.unwrap_non_null.boolean?
+
+  # Elasticsearch/OpenSearch do not support sorting text fields:
+  # > Text fields are not used for sorting...
+  # (from https://www.elastic.co/guide/en/elasticsearch/reference/current/the datastore.html#text)
+  return false if text?
+
+  # If the type uses custom mapping type we don't know how if the datastore can sort by it, so we assume it's not sortable.
+  return false if type.as_object_type&.has_custom_mapping_type?
+
+  # Default every other field to being sortable.
+  true
+end
+
+
+ +
+

+ + #sourced_from(relationship, field_path) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Configures ElasticGraph to source a field’s value from a related object. This can be used to denormalize data at ingestion time to +support filtering, grouping, sorting, or aggregating data on a field from a related object.

+ + +
+
+
+ +
+

Examples:

+ + +

Source City.currency from Country.currency

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Country" do |t|
+    t.field "id", "ID"
+    t.field "name", "String"
+    t.field "currency", "String"
+    t.relates_to_one "capitalCity", "City", via: "capitalCityId", dir: :out
+    t.index "countries"
+  end
+
+  schema.object_type "City" do |t|
+    t.field "id", "ID"
+    t.field "name", "String"
+    t.relates_to_one "capitalOf", "Country", via: "capitalCityId", dir: :in
+
+    t.field "currency", "String" do |f|
+      f.sourced_from "capitalOf", "currency"
+    end
+
+    t.index "cities"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + relationship + + + (String) + + + + — +

    name of a relationship defined with TypeWithSubfields#relates_to_one using an inbound foreign key +which contains the the field you wish to source values from

    +
    + +
  • + +
  • + + field_path + + + (String) + + + + — +

    dot-separated path to the field on the related type containing values that should be copied to this +field

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+444
+445
+446
+447
+448
+449
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 444
+
+def sourced_from(relationship, field_path)
+  self.source = schema_def_state.factory.new_field_source(
+    relationship_name: relationship,
+    field_path: field_path
+  )
+end
+
+
+ +
+

+ + #sub_aggregatable?Boolean + + + + + +

+
+

Indicates if this field can be used as the basis for a sub-aggregation. Sub-aggregatable fields will be available under +subAggregations for an aggregations query.

+ +

Only nested fields, and object fields which have nested fields, can be sub-aggregated.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+604
+605
+606
+607
+608
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 604
+
+def sub_aggregatable?
+  return false if relationship
+
+  nested? || type_for_derived_types.fully_unwrapped.as_object_type&.supports?(&:sub_aggregatable?)
+end
+
+
+ +
+

+ + #typeTypeReference + + + + + +

+
+

Returns the type of this field.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (TypeReference) + + + + — +

    the type of this field

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+158
+159
+160
+161
+162
+163
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/field.rb', line 158
+
+def type
+  # Here we lazily convert the `original_type` to an input type as needed. This must be lazy because
+  # the logic of `as_input` depends on detecting whether the type is an enum type, which it may not
+  # be able to do right away--we assume not if we can't tell, and retry every time this method is called.
+  original_type.to_final_form(as_input: as_input)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/InterfaceType.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/InterfaceType.html new file mode 100644 index 00000000..deaf0de2 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/InterfaceType.html @@ -0,0 +1,280 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::SchemaElements::InterfaceType + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::SchemaElements::InterfaceType + + + +

+
+ +
+
Inherits:
+
+ TypeWithSubfields + +
    +
  • Object
  • + + + + + + + +
+ show all + +
+
+ + + + + + +
+
Includes:
+
Mixins::HasIndices, Mixins::ImplementsInterfaces
+
+ + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/interface_type.rb
+
+ +
+ +

Overview

+
+

Defines a GraphQL interface. Use it to define an abstract supertype with +one or more fields that concrete implementations of the interface must also define. Each implementation can be an +ObjectType or InterfaceType.

+ + +
+
+
+ +
+

Examples:

+ + +

Define an interface

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.interface_type "Athlete" do |t|
+    # in the block, `t` is an InterfaceType
+  end
+end
+ +
+ + +
+ + +

Constant Summary

+ +

Constants included + from Mixins::HasTypeInfo

+

Mixins::HasTypeInfo::CUSTOMIZABLE_DATASTORE_PARAMS

+ + + + +

Instance Attribute Summary

+ +

Attributes included from Mixins::HasDocumentation

+

#doc_comment

+ + + + + + + + + + + + + + + +

Method Summary

+ +

Methods included from Mixins::HasIndices

+

#derive_indexed_type_fields, #derived_indexed_types, #index, #indexed?, #plural_root_query_field_name, #root_query_fields, #singular_root_query_field_name

+ + + + + + + + + + + + + + + +

Methods included from Mixins::ImplementsInterfaces

+

#implemented_interfaces, #implements, #to_sdl

+ + + + + + + + + +

Methods inherited from TypeWithSubfields

+

#deleted_field, #field, #name, #paginated_collection_field, #relates_to_many, #relates_to_one, #renamed_from

+ + + + + + + + + +

Methods included from Mixins::HasTypeInfo

+

#json_schema, #json_schema_options, #mapping, #mapping_options

+ + + + + + + + + +

Methods included from Mixins::HasDerivedGraphQLTypeCustomizations

+

#customize_derived_type_fields, #customize_derived_types

+ + + + + + + + + +

Methods included from Mixins::HasDirectives

+

#directive, #directives, #directives_sdl

+ + + + + + + + + +

Methods included from Mixins::HasDocumentation

+

#append_to_documentation, #derived_documentation, #documentation, #formatted_documentation

+ + + + + + + + + +

Methods included from Mixins::CanBeGraphQLOnly

+

#graphql_only, #graphql_only?

+ + + + + + + + + +

Methods included from Mixins::VerifiesGraphQLName

+

verify_name!

+ + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/ObjectType.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/ObjectType.html new file mode 100644 index 00000000..fb529277 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/ObjectType.html @@ -0,0 +1,274 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::SchemaElements::ObjectType + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::SchemaElements::ObjectType + + + +

+
+ +
+
Inherits:
+
+ TypeWithSubfields + +
    +
  • Object
  • + + + + + + + +
+ show all + +
+
+ + + + + + +
+
Includes:
+
Mixins::HasIndices, Mixins::ImplementsInterfaces
+
+ + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/object_type.rb
+
+ +
+ +

Overview

+
+

Defines a GraphQL object type Use it to define a concrete type that +has subfields. Object types can either be indexed (e.g. directly indexed in the datastore, and available to query from the +root Query object) or embedded in other indexed types.

+ + +
+
+
+ +
+

Examples:

+ + +

Define an object type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Money" do |t|
+    # in the block, `t` is an ObjectType
+  end
+end
+ +
+ + +
+ + +

Constant Summary

+ +

Constants included + from Mixins::HasTypeInfo

+

Mixins::HasTypeInfo::CUSTOMIZABLE_DATASTORE_PARAMS

+ + + + +

Instance Attribute Summary

+ +

Attributes included from Mixins::HasDocumentation

+

#doc_comment

+ + + + + + + + + +

Method Summary

+ +

Methods included from Mixins::ImplementsInterfaces

+

#implemented_interfaces, #implements, #to_sdl

+ + + + + + + + + +

Methods included from Mixins::HasIndices

+

#derive_indexed_type_fields, #derived_indexed_types, #index, #indexed?, #plural_root_query_field_name, #root_query_fields, #singular_root_query_field_name

+ + + + + + + + + + + + + + + +

Methods inherited from TypeWithSubfields

+

#deleted_field, #field, #name, #paginated_collection_field, #relates_to_many, #relates_to_one, #renamed_from

+ + + + + + + + + +

Methods included from Mixins::HasTypeInfo

+

#json_schema, #json_schema_options, #mapping, #mapping_options

+ + + + + + + + + +

Methods included from Mixins::HasDerivedGraphQLTypeCustomizations

+

#customize_derived_type_fields, #customize_derived_types

+ + + + + + + + + +

Methods included from Mixins::HasDirectives

+

#directive, #directives, #directives_sdl

+ + + + + + + + + +

Methods included from Mixins::HasDocumentation

+

#append_to_documentation, #derived_documentation, #documentation, #formatted_documentation

+ + + + + + + + + +

Methods included from Mixins::CanBeGraphQLOnly

+

#graphql_only, #graphql_only?

+ + + + + + + + + +

Methods included from Mixins::VerifiesGraphQLName

+

verify_name!

+ + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/Relationship.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/Relationship.html new file mode 100644 index 00000000..fef8780a --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/Relationship.html @@ -0,0 +1,611 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::SchemaElements::Relationship + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::SchemaElements::Relationship + + + +

+
+ +
+
Inherits:
+
+ Field + +
    +
  • Object
  • + + + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/relationship.rb
+
+ +
+ +

Overview

+
+

Wraps a Field to provide additional relationship-specific functionality when defining a field via +TypeWithSubfields#relates_to_one or TypeWithSubfields#relates_to_many.

+ + +
+
+
+ +
+

Examples:

+ + +

Define relationships between two types

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Orchestra" do |t|
+    t.field "id", "ID"
+    t.relates_to_many "musicians", "Musician", via: "orchestraId", dir: :in, singular: "musician" do |r|
+      # In this block, `r` is a `Relationship`.
+    end
+    t.index "orchestras"
+  end
+
+  schema.object_type "Musician" do |t|
+    t.field "id", "ID"
+    t.field "instrument", "String"
+    t.relates_to_one "orchestra", "Orchestra", via: "orchestraId", dir: :out do |r|
+      # In this block, `r` is a `Relationship`.
+    end
+    t.index "musicians"
+  end
+end
+ +
+ + +
+ + +

Constant Summary

+ +

Constants included + from Mixins::HasTypeInfo

+

Mixins::HasTypeInfo::CUSTOMIZABLE_DATASTORE_PARAMS

+ + +

Instance Attribute Summary collapse

+ + + + + + +

Attributes inherited from Field

+

#graphql_only, #name, #name_in_index, #schema_def_state

+ + + +

Attributes included from Mixins::HasDocumentation

+

#doc_comment

+ + + +

+ Instance Method Summary + collapse +

+ + + + + + + + + + + + + +

Methods inherited from Field

+

#aggregatable?, #argument, #customize_aggregated_values_field, #customize_filter_field, #customize_grouped_by_field, #customize_sort_order_enum_values, #customize_sub_aggregations_field, #filterable?, #groupable?, #json_schema, #mapping_type, #on_each_generated_schema_element, #renamed_from, #sortable?, #sourced_from, #sub_aggregatable?, #type

+ + + + + + + + + +

Methods included from Mixins::HasTypeInfo

+

#json_schema, #json_schema_options, #mapping, #mapping_options

+ + + + + + + + + +

Methods included from Mixins::HasDirectives

+

#directive, #directives, #directives_sdl

+ + + + + + + + + +

Methods included from Mixins::HasDocumentation

+

#append_to_documentation, #derived_documentation, #documentation, #formatted_documentation

+ + + + + + + + + +

Methods included from Mixins::VerifiesGraphQLName

+

verify_name!

+ + +
+

Instance Attribute Details

+ + + +
+
+
+

Returns the type this relationship relates to.

+ + +
+
+
+ +

Returns:

+ + +
+ + + + +
+
+
+
+43
+44
+45
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/relationship.rb', line 43
+
+def related_type
+  @related_type
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #additional_filter(filter) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Adds additional filter conditions to a relationship beyond the foreign key.

+ + +
+
+
+ +
+

Examples:

+ + +

Define additional filter conditions on a relates_to_one relationship

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Orchestra" do |t|
+    t.field "id", "ID"
+    t.relates_to_many "musicians", "Musician", via: "orchestraId", dir: :in, singular: "musician"
+    t.relates_to_one "firstViolin", "Musician", via: "orchestraId", dir: :in do |r|
+      r.additional_filter isFirstViolon: true
+    end
+
+    t.index "orchestras"
+  end
+
+  schema.object_type "Musician" do |t|
+    t.field "id", "ID"
+    t.field "instrument", "String"
+    t.field "isFirstViolon", "Boolean"
+    t.relates_to_one "orchestra", "Orchestra", via: "orchestraId", dir: :out
+    t.index "musicians"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + filter + + + (Hash<Symbol, Object>, Hash<String, Object>) + + + + — +

    additional filter conditions for this relationship

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+81
+82
+83
+84
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/relationship.rb', line 81
+
+def additional_filter(filter)
+  stringified_filter = Support::HashUtil.stringify_keys(filter)
+  @additional_filter = Support::HashUtil.deep_merge(@additional_filter, stringified_filter)
+end
+
+
+ +
+

+ + #equivalent_field(path, locally_named: path) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Indicates that path (a field on the related type) is the equivalent of locally_named on this type.

+ +

Use this API to specify a local field’s equivalent path on the related type. This must be used on relationships used by +Field#sourced_from when the local type uses Indexing::Index#route_with or Indexing::Index#rollover so that +ElasticGraph can determine what field from the related type to use to route the update requests to the correct index and shard.

+ + +
+
+
+ +
+

Examples:

+ + +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID!"
+    t.field "name", "String"
+    t.field "createdAt", "DateTime"
+
+    t.relates_to_one "launchPlan", "CampaignLaunchPlan", via: "campaignId", dir: :in do |r|
+      r.equivalent_field "campaignCreatedAt", locally_named: "createdAt"
+    end
+
+    t.field "launchDate", "Date" do |f|
+      f.sourced_from "launchPlan", "launchDate"
+    end
+
+    t.index "campaigns"do |i|
+      i.rollover :yearly, "createdAt"
+    end
+  end
+
+  schema.object_type "CampaignLaunchPlan" do |t|
+    t.field "id", "ID"
+    t.field "campaignId", "ID"
+    t.field "campaignCreatedAt", "DateTime"
+    t.field "launchDate", "Date"
+
+    t.index "campaign_launch_plans"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + path + + + (String) + + + + — +

    path to a routing or rollover field on the related type

    +
    + +
  • + +
  • + + locally_named + + + (String) + + + (defaults to: path) + + + — +

    path on the local type to the equivalent field

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+125
+126
+127
+128
+129
+130
+131
+132
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/relationship.rb', line 125
+
+def equivalent_field(path, locally_named: path)
+  if @equivalent_field_paths_by_local_path.key?(locally_named)
+    raise Errors::SchemaError, "`equivalent_field` has been called multiple times on `#{parent_type.name}.#{name}` with the same " \
+      "`locally_named` value (#{locally_named.inspect}), but each local field can have only one `equivalent_field`."
+  else
+    @equivalent_field_paths_by_local_path[locally_named] = path
+  end
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/ScalarType.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/ScalarType.html new file mode 100644 index 00000000..517d9857 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/ScalarType.html @@ -0,0 +1,1456 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::SchemaElements::ScalarType + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::SchemaElements::ScalarType + + + +

+
+ +
+
Inherits:
+
+ Struct + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + +
+
Includes:
+
Mixins::CanBeGraphQLOnly, Mixins::HasDerivedGraphQLTypeCustomizations, Mixins::HasDirectives, Mixins::HasDocumentation, Mixins::HasTypeInfo, Mixins::VerifiesGraphQLName
+
+ + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb
+
+ +
+ +

Overview

+
+

Defines a GraphQL scalar type. ElasticGraph itself uses this to define a few +common scalar types (e.g. Date and DateTime), but it is also available to you to use to define your own custom scalar types.

+ + +
+
+
+ +
+

Examples:

+ + +

Define a scalar type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.scalar_type "URL" do |t|
+    t.mapping type: "keyword"
+    t.json_schema type: "string", format: "uri"
+  end
+end
+ +
+ + +
+ + +

Constant Summary

+ +

Constants included + from Mixins::HasTypeInfo

+

Mixins::HasTypeInfo::CUSTOMIZABLE_DATASTORE_PARAMS

+ + +

Instance Attribute Summary collapse

+ + + + + + +

Attributes included from Mixins::HasDocumentation

+

#doc_comment

+ + + +

+ Instance Method Summary + collapse +

+ + + + + + + + + + + + + +

Methods included from Mixins::HasTypeInfo

+

#json_schema, #json_schema_options, #mapping_options

+ + + + + + + + + +

Methods included from Mixins::HasDerivedGraphQLTypeCustomizations

+

#customize_derived_type_fields, #customize_derived_types

+ + + + + + + + + +

Methods included from Mixins::HasDirectives

+

#directive, #directives, #directives_sdl

+ + + + + + + + + +

Methods included from Mixins::HasDocumentation

+

#append_to_documentation, #derived_documentation, #documentation, #formatted_documentation

+ + + + + + + + + +

Methods included from Mixins::CanBeGraphQLOnly

+

#graphql_only, #graphql_only?

+ + + + + + + + + +

Methods included from Mixins::VerifiesGraphQLName

+

verify_name!

+ + +
+

Instance Attribute Details

+ + + +
+

+ + #schema_def_stateState (readonly) + + + + + +

+
+

Returns schema definition state.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (State) + + + + — +

    schema definition state

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb', line 42
+
+class ScalarType < Struct.new(:schema_def_state, :type_ref, :mapping_type, :runtime_metadata, :aggregated_values_customizations)
+  # `Struct.new` provides the following methods:
+  # @dynamic type_ref, runtime_metadata
+  prepend Mixins::VerifiesGraphQLName
+  include Mixins::CanBeGraphQLOnly
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::HasDerivedGraphQLTypeCustomizations
+  include Mixins::HasReadableToSAndInspect.new { |t| t.name }
+
+  # `HasTypeInfo` provides the following methods:
+  # @dynamic mapping_options, json_schema_options
+  include Mixins::HasTypeInfo
+
+  # @dynamic graphql_only?
+
+  # @private
+  def initialize(schema_def_state, name)
+    super(schema_def_state, schema_def_state.type_ref(name).to_final_form)
+
+    # Default the runtime metadata before yielding, so it can be overridden as needed.
+    self. = SchemaArtifacts::RuntimeMetadata::ScalarType.new(
+      coercion_adapter_ref: SchemaArtifacts::RuntimeMetadata::ScalarType::DEFAULT_COERCION_ADAPTER_REF,
+      indexing_preparer_ref: SchemaArtifacts::RuntimeMetadata::ScalarType::DEFAULT_INDEXING_PREPARER_REF
+    )
+
+    yield self
+
+    missing = [
+      ("`mapping`" if mapping_options.empty?),
+      ("`json_schema`" if json_schema_options.empty?)
+    ].compact
+
+    if missing.any?
+      raise Errors::SchemaError, "Scalar types require `mapping` and `json_schema` to be configured, but `#{name}` lacks #{missing.join(" and ")}."
+    end
+  end
+
+  # @return [String] name of the scalar type
+  def name
+    type_ref.name
+  end
+
+  # (see Mixins::HasTypeInfo#mapping)
+  def mapping(**options)
+    self.mapping_type = options.fetch(:type) do
+      raise Errors::SchemaError, "Must specify a mapping `type:` on custom scalars but was missing on the `#{name}` type."
+    end
+
+    super
+  end
+
+  # Specifies the scalar coercion adapter that should be used for this scalar type. The scalar coercion adapter is responsible
+  # for validating and coercing scalar input values, and converting scalar return values to a form suitable for JSON serialization.
+  #
+  # @note For examples of scalar coercion adapters, see `ElasticGraph::GraphQL::ScalarCoercionAdapters`.
+  # @note If the `defined_at` require path requires any directories be put on the Ruby `$LOAD_PATH`, you are responsible for doing
+  #   that before booting {ElasticGraph::GraphQL}.
+  #
+  # @param adapter_name [String] fully qualified Ruby class name of the adapter
+  # @param defined_at [String] the `require` path of the adapter
+  # @return [void]
+  #
+  # @example Register a coercion adapter
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.scalar_type "PhoneNumber" do |t|
+  #       t.mapping type: "keyword"
+  #       t.json_schema type: "string", pattern: "^\\+[1-9][0-9]{1,14}$"
+  #       t.coerce_with "CoercionAdapters::PhoneNumber", defined_at: "./coercion_adapters/phone_number"
+  #     end
+  #   end
+  def coerce_with(adapter_name, defined_at:)
+    self. = .with(coercion_adapter_ref: {
+      "extension_name" => adapter_name,
+      "require_path" => defined_at
+    }).tap(&:load_coercion_adapter) # verify the adapter is valid.
+  end
+
+  # Specifies an indexing preparer that should be used for this scalar type. The indexing preparer is responsible for preparing
+  # scalar values before indexing them, performing any desired formatting or normalization.
+  #
+  # @note For examples of scalar coercion adapters, see `ElasticGraph::Indexer::IndexingPreparers`.
+  # @note If the `defined_at` require path requires any directories be put on the Ruby `$LOAD_PATH`, you are responsible for doing
+  #   that before booting {ElasticGraph::GraphQL}.
+  #
+  # @param preparer_name [String] fully qualified Ruby class name of the indexing preparer
+  # @param defined_at [String] the `require` path of the preparer
+  # @return [void]
+  #
+  # @example Register an indexing preparer
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.scalar_type "PhoneNumber" do |t|
+  #       t.mapping type: "keyword"
+  #       t.json_schema type: "string", pattern: "^\\+[1-9][0-9]{1,14}$"
+  #
+  #       t.prepare_for_indexing_with "IndexingPreparers::PhoneNumber",
+  #         defined_at: "./indexing_preparers/phone_number"
+  #     end
+  #   end
+  def prepare_for_indexing_with(preparer_name, defined_at:)
+    self. = .with(indexing_preparer_ref: {
+      "extension_name" => preparer_name,
+      "require_path" => defined_at
+    }).tap(&:load_indexing_preparer) # verify the preparer is valid.
+  end
+
+  # @return [String] the GraphQL SDL form of this scalar
+  def to_sdl
+    "#{formatted_documentation}scalar #{name} #{directives_sdl}"
+  end
+
+  # Registers a block which will be used to customize the derived `*AggregatedValues` object type.
+  #
+  # @private
+  def customize_aggregated_values_type(&block)
+    self.aggregated_values_customizations = block
+  end
+
+  # @private
+  def aggregated_values_type
+    if aggregated_values_customizations
+      type_ref.as_aggregated_values
+    else
+      schema_def_state.type_ref("NonNumeric").as_aggregated_values
+    end
+  end
+
+  # @private
+  def to_indexing_field_type
+    Indexing::FieldType::Scalar.new(scalar_type: self)
+  end
+
+  # @private
+  def derived_graphql_types
+    return [] if graphql_only?
+
+    pagination_types =
+      if schema_def_state.paginated_collection_element_types.include?(name)
+        schema_def_state.factory.build_relay_pagination_types(name, include_total_edge_count: true)
+      else
+        [] # : ::Array[ObjectType]
+      end
+
+    (to_input_filters + pagination_types).tap do |derived_types|
+      if (aggregated_values_type = to_aggregated_values_type)
+        derived_types << aggregated_values_type
+      end
+    end
+  end
+
+  # @private
+  def indexed?
+    false
+  end
+
+  private
+
+  EQUAL_TO_ANY_OF_DOC = <<~EOS
+    Matches records where the field value is equal to any of the provided values.
+    This works just like an IN operator in SQL.
+
+    Will be ignored when `null` is passed. When an empty list is passed, will cause this
+    part of the filter to match no documents. When `null` is passed in the list, will
+    match records where the field value is `null`.
+  EOS
+
+  GT_DOC = <<~EOS
+    Matches records where the field value is greater than (>) the provided value.
+
+    Will be ignored when `null` is passed.
+  EOS
+
+  GTE_DOC = <<~EOS
+    Matches records where the field value is greater than or equal to (>=) the provided value.
+
+    Will be ignored when `null` is passed.
+  EOS
+
+  LT_DOC = <<~EOS
+    Matches records where the field value is less than (<) the provided value.
+
+    Will be ignored when `null` is passed.
+  EOS
+
+  LTE_DOC = <<~EOS
+    Matches records where the field value is less than or equal to (<=) the provided value.
+
+    Will be ignored when `null` is passed.
+  EOS
+
+  def to_input_filters
+    # Note: all fields on inputs should be nullable, to support parameterized queries where
+    # the parameters are allowed to be set to `null`. We also now support nulls within lists.
+
+    # For floats, we may want to remove the `equal_to_any_of` operator at some point.
+    # In many languages. checking exact equality with floats is problematic.
+    # For example, in IRB:
+    #
+    # 2.7.1 :003 > 0.3 == (0.1 + 0.2)
+    # => false
+    #
+    # However, it's not yet clear if that issue will come up with GraphQL, because
+    # float values are serialized on the wire as JSON, using an exact decimal
+    # string representation. So for now we are keeping `equal_to_any_of`.
+    schema_def_state.factory.build_standard_filter_input_types_for_index_leaf_type(name) do |t|
+      # Normally, we use a nullable type for `equal_to_any_of`, to allow a filter expression like this:
+      #
+      # filter: {optional_field: {equal_to_any_of: [null]}}
+      #
+      # That filter expression matches documents where `optional_field == null`. However,
+      # we cannot support this:
+      #
+      # filter: {tags: {any_satisfy: {equal_to_any_of: [null]}}}
+      #
+      # We can't support that because we implement filtering on `null` using an `exists` query:
+      # https://www.elastic.co/guide/en/elasticsearch/reference/8.10/query-dsl-exists-query.html
+      #
+      # ...but that works based on the field existing (or not), and does not let us filter on the
+      # presence or absence of `null` within a list.
+      #
+      # So, here we make the field non-null if we're in an `any_satisfy` context (as indicated by
+      # the type ending with `ListElementFilterInput`).
+      equal_to_any_of_type = t.type_ref.list_element_filter_input? ? "[#{name}!]" : "[#{name}]"
+
+      t.field schema_def_state.schema_elements.equal_to_any_of, equal_to_any_of_type do |f|
+        f.documentation EQUAL_TO_ANY_OF_DOC
+      end
+
+      if mapping_type_efficiently_comparable?
+        t.field schema_def_state.schema_elements.gt, name do |f|
+          f.documentation GT_DOC
+        end
+
+        t.field schema_def_state.schema_elements.gte, name do |f|
+          f.documentation GTE_DOC
+        end
+
+        t.field schema_def_state.schema_elements.lt, name do |f|
+          f.documentation LT_DOC
+        end
+
+        t.field schema_def_state.schema_elements.lte, name do |f|
+          f.documentation LTE_DOC
+        end
+      end
+    end
+  end
+
+  def to_aggregated_values_type
+    return nil unless (customization_block = aggregated_values_customizations)
+    schema_def_state.factory.new_aggregated_values_type_for_index_leaf_type(name, &customization_block)
+  end
+
+  # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html
+  # https://www.elastic.co/guide/en/elasticsearch/reference/7.13/number.html#number
+  NUMERIC_TYPES = %w[long integer short byte double float half_float scaled_float unsigned_long].to_set
+  DATE_TYPES = %w[date date_nanos].to_set
+  # The Elasticsearch/OpenSearch docs do not exhaustively give a list of types on which range queries are efficient,
+  # but the docs are clear that it is efficient on numeric and date types, and is inefficient on string
+  # types: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html
+  COMPARABLE_TYPES = NUMERIC_TYPES | DATE_TYPES
+
+  def mapping_type_efficiently_comparable?
+    COMPARABLE_TYPES.include?(mapping_type)
+  end
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #coerce_with(adapter_name, defined_at:) ⇒ void + + + + + +

+
+ +
+ Note: +

For examples of scalar coercion adapters, see ElasticGraph::GraphQL::ScalarCoercionAdapters.

+
+
+ +
+ Note: +

If the defined_at require path requires any directories be put on the Ruby $LOAD_PATH, you are responsible for doing +that before booting GraphQL.

+
+
+ +

This method returns an undefined value.

Specifies the scalar coercion adapter that should be used for this scalar type. The scalar coercion adapter is responsible +for validating and coercing scalar input values, and converting scalar return values to a form suitable for JSON serialization.

+ + +
+
+
+ +
+

Examples:

+ + +

Register a coercion adapter

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.scalar_type "PhoneNumber" do |t|
+    t.mapping type: "keyword"
+    t.json_schema type: "string", pattern: "^\\+[1-9][0-9]{1,14}$"
+    t.coerce_with "CoercionAdapters::PhoneNumber", defined_at: "./coercion_adapters/phone_number"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + adapter_name + + + (String) + + + + — +

    fully qualified Ruby class name of the adapter

    +
    + +
  • + +
  • + + defined_at + + + (String) + + + + — +

    the require path of the adapter

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+113
+114
+115
+116
+117
+118
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb', line 113
+
+def coerce_with(adapter_name, defined_at:)
+  self. = .with(coercion_adapter_ref: {
+    "extension_name" => adapter_name,
+    "require_path" => defined_at
+  }).tap(&:load_coercion_adapter) # verify the adapter is valid.
+end
+
+
+ +
+

+ + #mapping(**options) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Defines the Elasticsearch/OpenSearch field mapping type +and mapping parameters for a field or type. +The options passed here will be included in the generated datastore_config.yaml artifact that ElasticGraph uses to configure +Elasticsearch/OpenSearch.

+ +

Can be called multiple times; each time, the options will be merged into the existing options.

+ +

This is required on a ElasticGraph::SchemaDefinition::SchemaElements::ScalarType; without it, ElasticGraph would have no way to know how the datatype should be +indexed in the datastore.

+ +

On a Field, this can be used to customize how a field is indexed. For example, String fields are normally +indexed as keywords; to instead index a String +field for full text search, you’d need to configure mapping type: "text".

+ +

On a ObjectType, this can be used to use a specific Elasticsearch/OpenSearch data type for something that is +modeled as an object in GraphQL. For example, we use it for the GeoLocation type so they get indexed in Elasticsearch using the +geo_point type.

+ + +
+
+
+ +
+

Examples:

+ + +

Define the mapping of a custom scalar type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.scalar_type "URL" do |t|
+    t.mapping type: "keyword"
+    t.json_schema type: "string", format: "uri"
+  end
+end
+ + +

Customize the mapping of a field

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Card" do |t|
+    t.field "id", "ID!"
+
+    t.field "cardholderName", "String" do |f|
+      # index this field for full text search
+      f.mapping type: "text"
+    end
+
+    t.field "expYear", "Int" do |f|
+      # Use a smaller numeric type to save space in the datastore
+      f.mapping type: "short"
+      f.json_schema minimum: 2000, maximum: 2099
+    end
+
+    t.field "expMonth", "Int" do |f|
+      # Use a smaller numeric type to save space in the datastore
+      f.mapping type: "byte"
+      f.json_schema minimum: 1, maximum: 12
+    end
+
+    t.index "cards"
+  end
+end
+ +
+

Parameters:

+ + + +
+ + + + +
+
+
+
+86
+87
+88
+89
+90
+91
+92
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb', line 86
+
+def mapping(**options)
+  self.mapping_type = options.fetch(:type) do
+    raise Errors::SchemaError, "Must specify a mapping `type:` on custom scalars but was missing on the `#{name}` type."
+  end
+
+  super
+end
+
+
+ +
+

+ + #nameString + + + + + +

+
+

Returns name of the scalar type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    name of the scalar type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+81
+82
+83
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb', line 81
+
+def name
+  type_ref.name
+end
+
+
+ +
+

+ + #prepare_for_indexing_with(preparer_name, defined_at:) ⇒ void + + + + + +

+
+ +
+ Note: +

For examples of scalar coercion adapters, see ElasticGraph::Indexer::IndexingPreparers.

+
+
+ +
+ Note: +

If the defined_at require path requires any directories be put on the Ruby $LOAD_PATH, you are responsible for doing +that before booting GraphQL.

+
+
+ +

This method returns an undefined value.

Specifies an indexing preparer that should be used for this scalar type. The indexing preparer is responsible for preparing +scalar values before indexing them, performing any desired formatting or normalization.

+ + +
+
+
+ +
+

Examples:

+ + +

Register an indexing preparer

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.scalar_type "PhoneNumber" do |t|
+    t.mapping type: "keyword"
+    t.json_schema type: "string", pattern: "^\\+[1-9][0-9]{1,14}$"
+
+    t.prepare_for_indexing_with "IndexingPreparers::PhoneNumber",
+      defined_at: "./indexing_preparers/phone_number"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + preparer_name + + + (String) + + + + — +

    fully qualified Ruby class name of the indexing preparer

    +
    + +
  • + +
  • + + defined_at + + + (String) + + + + — +

    the require path of the preparer

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+141
+142
+143
+144
+145
+146
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb', line 141
+
+def prepare_for_indexing_with(preparer_name, defined_at:)
+  self. = .with(indexing_preparer_ref: {
+    "extension_name" => preparer_name,
+    "require_path" => defined_at
+  }).tap(&:load_indexing_preparer) # verify the preparer is valid.
+end
+
+
+ +
+

+ + #to_sdlString + + + + + +

+
+

Returns the GraphQL SDL form of this scalar.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    the GraphQL SDL form of this scalar

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+149
+150
+151
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb', line 149
+
+def to_sdl
+  "#{formatted_documentation}scalar #{name} #{directives_sdl}"
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/SortOrderEnumValue.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/SortOrderEnumValue.html new file mode 100644 index 00000000..fc55acf0 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/SortOrderEnumValue.html @@ -0,0 +1,287 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::SchemaElements::SortOrderEnumValue + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::SchemaElements::SortOrderEnumValue + + + +

+
+ +
+
Inherits:
+
+ EnumValue + +
    +
  • Object
  • + + + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/sort_order_enum_value.rb
+
+ +
+ +

Overview

+
+

Simple wrapper around an EnumValue so that we can expose the sort_order_field_path to Field customization callbacks.

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

Attributes inherited from EnumValue

+

#name, #runtime_metadata, #schema_def_state

+ + + +

Attributes included from Mixins::HasDocumentation

+

#doc_comment

+ + + + + + + + + +

Method Summary

+ +

Methods inherited from EnumValue

+

#duplicate_on, #to_sdl, #update_runtime_metadata

+ + + + + + + + + +

Methods included from Mixins::HasDirectives

+

#directive, #directives, #directives_sdl

+ + + + + + + + + +

Methods included from Mixins::HasDocumentation

+

#append_to_documentation, #derived_documentation, #documentation, #formatted_documentation

+ + + + + + + + + +

Methods included from Mixins::VerifiesGraphQLName

+

verify_name!

+ + +
+

Instance Attribute Details

+ + + +
+

+ + #sort_order_field_pathArray<Field> (readonly) + + + + + +

+
+

Returns path to the field from the root of the indexed ObjectType.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Array<Field>) + + + + — +

    path to the field from the root of the indexed ObjectType

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+23
+24
+25
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/sort_order_enum_value.rb', line 23
+
+def sort_order_field_path
+  @sort_order_field_path
+end
+
+
+ +
+ + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/TypeNamer.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/TypeNamer.html new file mode 100644 index 00000000..058e21d0 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/TypeNamer.html @@ -0,0 +1,186 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::SchemaElements::TypeNamer + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::SchemaElements::TypeNamer + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_namer.rb
+
+ +
+ +

Overview

+
+

Abstraction for generating derived GraphQL type names based on a collection of formats. A default set of formats is included, and +overrides can be provided to customize the format we use for naming derived types.

+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
DEFAULT_FORMATS = +
+
+

The default formats used for derived GraphQL type names. These formats can be customized by providing derived_type_name_formats +to RakeTasks or Local::RakeTasks.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<Symbol, String>) + + + +
  • + +
+ +
+
+
{
+  AggregatedValues: "%{base}AggregatedValues",
+  Aggregation: "%{base}Aggregation",
+  Connection: "%{base}Connection",
+  Edge: "%{base}Edge",
+  FieldsListFilterInput: "%{base}FieldsListFilterInput",
+  FilterInput: "%{base}FilterInput",
+  GroupedBy: "%{base}GroupedBy",
+  InputEnum: "%{base}Input",
+  ListElementFilterInput: "%{base}ListElementFilterInput",
+  ListFilterInput: "%{base}ListFilterInput",
+  SortOrder: "%{base}SortOrder",
+  SubAggregation: "%{parent_types}%{base}SubAggregation",
+  SubAggregations: "%{parent_agg_type}%{field_path}SubAggregations"
+}.freeze
+ +
+ + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/TypeWithSubfields.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/TypeWithSubfields.html new file mode 100644 index 00000000..9be6ceb7 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/TypeWithSubfields.html @@ -0,0 +1,1630 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::SchemaElements::TypeWithSubfields + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::SchemaElements::TypeWithSubfields + Abstract + + +

+
+ +
+
Inherits:
+
+ Struct + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + +
+
Includes:
+
Mixins::CanBeGraphQLOnly, Mixins::HasDerivedGraphQLTypeCustomizations, Mixins::HasDirectives, Mixins::HasDocumentation, Mixins::HasTypeInfo, Mixins::VerifiesGraphQLName
+
+ + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb
+
+ +
+ +

Overview

+
+
+ This class is abstract. +
+
+
+

Defines common functionality for all GraphQL types that have subfields:

+ + + + +
+
+
+ + +
+

Direct Known Subclasses

+

InterfaceType, ObjectType

+
+ + + +

Constant Summary

+ +

Constants included + from Mixins::HasTypeInfo

+

Mixins::HasTypeInfo::CUSTOMIZABLE_DATASTORE_PARAMS

+ + + + +

Instance Attribute Summary

+ +

Attributes included from Mixins::HasDocumentation

+

#doc_comment

+ + + +

+ Instance Method Summary + collapse +

+ + + + + + + + + + + + + +

Methods included from Mixins::HasTypeInfo

+

#json_schema, #json_schema_options, #mapping, #mapping_options

+ + + + + + + + + +

Methods included from Mixins::HasDerivedGraphQLTypeCustomizations

+

#customize_derived_type_fields, #customize_derived_types

+ + + + + + + + + +

Methods included from Mixins::HasDirectives

+

#directive, #directives, #directives_sdl

+ + + + + + + + + +

Methods included from Mixins::HasDocumentation

+

#append_to_documentation, #derived_documentation, #documentation, #formatted_documentation

+ + + + + + + + + +

Methods included from Mixins::CanBeGraphQLOnly

+

#graphql_only, #graphql_only?

+ + + + + + + + + +

Methods included from Mixins::VerifiesGraphQLName

+

verify_name!

+ + + +
+

Instance Method Details

+ + +
+

+ + #deleted_field(field_name) ⇒ void + + + + + +

+
+ +
+ Note: +

In situations where this API applies, ElasticGraph will give you an error message indicating that you need to use this API +or Field#renamed_from. Likewise, when ElasticGraph no longer needs to know about this, it’ll give you a warning indicating +the call to this method can be removed.

+
+
+ +

This method returns an undefined value.

Registers the name of a field that existed in a prior version of the schema but has been deleted.

+ + +
+
+
+ +
+

Examples:

+ + +

Indicate that Widget.description has been deleted

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Widget" do |t|
+    t.deleted_field "description"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + field_name + + + (String) + + + + — +

    name of field that used to exist but has been deleted

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+238
+239
+240
+241
+242
+243
+244
+245
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb', line 238
+
+def deleted_field(field_name)
+  schema_def_state.register_deleted_field(
+    name,
+    field_name,
+    defined_at: caller_locations(2, 1).first, # : ::Thread::Backtrace::Location
+    defined_via: %(type.deleted_field "#{field_name}")
+  )
+end
+
+
+ +
+

+ + #field(name, type, graphql_only: false, indexing_only: false, **options) {|Field| ... } ⇒ void + + + + + +

+
+ +
+ Note: +

Be careful about defining non-nullable fields. Changing a field’s type from non-nullable (e.g. Int!) to nullable (e.g. +Int) is a breaking change for clients. Making a field non-nullable may also prevent you from applying permissioning to a field +via an AuthZ layer (as such a layer would have no way to force a field value to null when for a client denied field access). +Therefore, we recommend limiting your use of ! to only a few situations such as defining a type’s primary key (e.g. +t.field "id", "ID!") or defining a list field (e.g. t.field "authors", "[String!]!") since empty lists already provide a +“no data” representation. You can still configure the ElasticGraph indexer to require a non-null value for a field using +f.json_schema nullable: false.

+
+
+ +
+ Note: +

ElasticGraph’s understanding of datastore capabilities may override your configured +aggregatable/filterable/groupable/sortable options. For example, a field indexed as text for full text search will +not be sortable or groupable even if you pass sortable: true, groupable: true when defining the field, because text fields +cannot be efficiently sorted by or grouped on.

+
+
+ +

This method returns an undefined value.

Defines a GraphQL field on this type.

+ + +
+
+
+ +
+

Examples:

+ + +

Define a field with documentation

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID" do |f|
+      f.documentation "The Campaign's identifier."
+    end
+  end
+end
+ + +

Omit a new field from the GraphQL schema until its data has been backfilled

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID"
+
+    # TODO: remove `indexing_only: true` once the data for this field has been fully backfilled
+    t.field "endDate", "Date", indexing_only: true
+  end
+end
+ + +

Use graphql_only to introduce a new name for an existing field

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Campaign" do |t|
+    t.field "id", "ID"
+
+    t.field "endOn", "Date" do |f|
+      f.directive "deprecated", reason: "Use `endDate` instead."
+    end
+
+    # We've decided we want to call the field `endDate` instead of `endOn`, but the data
+    # for this field is currently indexed in `endOn`, so we can use `graphql_only` and
+    # `name_in_index` to expose the existing data under a new field name.
+    t.field "endDate", "Date", name_in_index: "endOn", graphql_only: true
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    name of the field

    +
    + +
  • + +
  • + + type + + + (String) + + + + — +

    type of the field as a type reference. The named type must be +one of ElasticGraph’s built-in types or a type that has been defined in your schema.

    +
    + +
  • + +
  • + + graphql_only + + + (Boolean) + + + (defaults to: false) + + + — +

    if true, ElasticGraph will define the field as a GraphQL field but omit it from the indexing +artifacts (json_schemas.yaml and datastore_config.yaml). This can be used along with name_in_index to support careful +schema evolution.

    +
    + +
  • + +
  • + + indexing_only + + + (Boolean) + + + (defaults to: false) + + + — +

    if true, ElasticGraph will define the field for indexing (in the json_schemas.yaml and +datastore_config.yaml schema artifact) but will omit it from the GraphQL schema. This can be useful to begin indexing a field +before you expose it in GraphQL so that you can fully backfill it first.

    +
    + +
  • + +
  • + + options + + + (Hash) + + + + — +

    a customizable set of options

    +
    + +
  • + +
+ + + + + + + + + + + + +

Options Hash (**options):

+
    + +
  • + name_in_index + (String) + + + + + —

    the name of the field in the datastore index. Can be used to back a GraphQL field with a +differently named field in the index.

    +
    + +
  • + +
  • + singular + (String) + + + + + —

    can be used on a list field (e.g. t.field "tags", "[String!]!", singular: "tag") to tell +ElasticGraph what the singular form of a field’s name is. When provided, ElasticGraph will define a groupedBy field (using the +singular form) allowing clients to group by individual values from the field.

    +
    + +
  • + +
  • + aggregatable + (Boolean) + + + + + —

    force-enables or disables the ability for aggregation queries to aggregate over this field. +When not provided, ElasticGraph will infer field aggregatability based on the field’s GraphQL type and mapping type.

    +
    + +
  • + +
  • + filterable + (Boolean) + + + + + —

    force-enables or disables the ability for queries to filter by this field. When not provided, +ElasticGraph will infer field filterability based on the field’s GraphQL type and mapping type.

    +
    + +
  • + +
  • + groupable + (Boolean) + + + + + —

    force-enables or disables the ability for aggregation queries to group by this field. When +not provided, ElasticGraph will infer field groupability based on the field’s GraphQL type and mapping type.

    +
    + +
  • + +
  • + sortable + (Boolean) + + + + + —

    force-enables or disables the ability for queries to sort by this field. When not provided, +ElasticGraph will infer field sortability based on the field’s GraphQL type and mapping type.

    +
    + +
  • + +
+ + +

Yields:

+
    + +
  • + + + (Field) + + + + — +

    the field for further customization

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb', line 192
+
+def field(name, type, graphql_only: false, indexing_only: false, **options)
+  if reserved_field_names.include?(name)
+    raise Errors::SchemaError, "Invalid field name: `#{self.name}.#{name}`. `#{name}` is reserved for use by " \
+      "ElasticGraph as a filtering operator. To use it for a field name, add " \
+      "the `schema_element_name_overrides` option (on `ElasticGraph::SchemaDefinition::RakeTasks.new`) to " \
+      "configure an alternate name for the `#{name}` operator."
+  end
+
+  options = {name_in_index: nil}.merge(options) if graphql_only
+
+  field_factory.call(
+    name: name,
+    type: type,
+    graphql_only: graphql_only,
+    parent_type: wrapping_type,
+    **options
+  ) do |field|
+    yield field if block_given?
+
+    unless indexing_only
+      register_field(field.name, field, graphql_fields_by_name, "GraphQL", :indexing_only)
+    end
+
+    unless graphql_only
+      register_field(field.name_in_index, field, indexing_fields_by_name_in_index, "indexing", :graphql_only) do |f|
+        f.to_indexing_field_reference
+      end
+    end
+  end
+end
+
+
+ +
+

+ + #nameString + + + + + +

+
+

Returns the name of this GraphQL type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    the name of this GraphQL type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+110
+111
+112
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb', line 110
+
+def name
+  type_ref.name
+end
+
+
+ +
+

+ + #paginated_collection_field(name, element_type, name_in_index: name, singular: nil) {|Field| ... } ⇒ void + + + + + +

+
+ +
+ Note: +

Bear in mind that pagination does not have much efficiency benefit in this case: all elements of the collection will be +retrieved when fetching this field from the datastore. The pagination implementation will just trim down the collection before +returning it.

+
+
+ +

This method returns an undefined value.

An alternative to #field for when you have a list field that you want exposed as a paginated Relay +connection rather than as a simple list.

+ + +
+
+
+ +
+

Examples:

+ + +

Define Author.books as a paginated collection field

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Author" do |t|
+    t.field "id", "ID"
+    t.field "name", "String"
+    t.paginated_collection_field "books", "String"
+    t.index "authors"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    name of the field

    +
    + +
  • + +
  • + + element_type + + + (String) + + + + — +

    name of the type of element in the collection

    +
    + +
  • + +
  • + + name_in_index + + + (String) + + + (defaults to: name) + + + — +

    the name of the field in the datastore index. Can be used to back a GraphQL field with a +differently named field in the index.

    +
    + +
  • + +
  • + + singular + + + (String) + + + (defaults to: nil) + + + — +

    indicates what the singular form of a field’s name is. When provided, ElasticGraph will define a +groupedBy field (using the singular form) allowing clients to group by individual values from the field.

    +
    + +
  • + +
+ +

Yields:

+
    + +
  • + + + (Field) + + + + — +

    the field for further customization

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb', line 300
+
+def paginated_collection_field(name, element_type, name_in_index: name, singular: nil, &block)
+  element_type_ref = schema_def_state.type_ref(element_type).to_final_form
+  element_type = element_type_ref.name
+
+  schema_def_state.paginated_collection_element_types << element_type
+
+  backing_indexing_field = field(name, "[#{element_type}!]!", indexing_only: true, name_in_index: name_in_index, &block)
+
+  field(
+    name,
+    element_type_ref.as_connection.name,
+    name_in_index: name_in_index,
+    type_for_derived_types: "[#{element_type}]",
+    groupable: !!singular,
+    sortable: false,
+    graphql_only: true,
+    singular: singular,
+    backing_indexing_field: backing_indexing_field
+  ) do |f|
+    f.define_relay_pagination_arguments!
+    block&.call(f)
+  end
+end
+
+
+ +
+

+ + #relates_to_many(field_name, type, via:, dir:, singular:) {|Relationship| ... } ⇒ void + + + + + +

+
+

This method returns an undefined value.

Defines a “has many” relationship between the current indexed type and another indexed type by defining a pair of fields clients +can use to navigate across indexed types in a single GraphQL query. The pair of generated fields will be Relay Connection +types allowing you to filter, sort, paginate, and aggregated the +related data.

+ + +
+
+
+ +
+

Examples:

+ + +

Use relates_to_many to define Team.players and Team.playerAggregations

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Team" do |t|
+    t.field "id", "ID"
+    t.field "name", "String"
+    t.field "homeCity", "String"
+    t.relates_to_many "players", "Player", via: "teamId", dir: :in, singular: "player"
+    t.index "teams"
+  end
+
+  schema.object_type "Player" do |t|
+    t.field "id", "ID"
+    t.field "name", "String"
+    t.field "teamId", "ID"
+    t.index "players"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + field_name + + + (String) + + + + — +

    name of the relationship field

    +
    + +
  • + +
  • + + type + + + (String) + + + + — +

    name of the related type

    +
    + +
  • + +
  • + + via + + + (String) + + + + — +

    name of the foreign key field

    +
    + +
  • + +
  • + + dir + + + (:in, :out) + + + + — +

    direction of the foreign key. Use :in for an inbound foreign key that resides on the related type and +references the id of this type. Use :out for an outbound foreign key that resides on this type and references the id of +the related type.

    +
    + +
  • + +
  • + + singular + + + (String) + + + + — +

    singular form of the field_name; will be used (along with an Aggregations suffix) for the name of +the generated aggregations field

    +
    + +
  • + +
+ +

Yields:

+
    + +
  • + + + (Relationship) + + + + — +

    the generated relationship fields, for further customization

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb', line 397
+
+def relates_to_many(field_name, type, via:, dir:, singular:)
+  foreign_key_type = (dir == :out) ? "[ID!]!" : "ID"
+  type_ref = schema_def_state.type_ref(type).to_final_form
+
+  relates_to(field_name, type_ref.as_connection.name, via: via, dir: dir, foreign_key_type: foreign_key_type, cardinality: :many, related_type: type) do |f|
+    f.argument schema_def_state.schema_elements.filter, type_ref.as_filter_input.name do |a|
+      a.documentation "Used to filter the returned `#{field_name}` based on the provided criteria."
+    end
+
+    f.argument schema_def_state.schema_elements.order_by, "[#{type_ref.as_sort_order.name}!]" do |a|
+      a.documentation "Used to specify how the returned `#{field_name}` should be sorted."
+    end
+
+    f.define_relay_pagination_arguments!
+
+    yield f if block_given?
+  end
+
+  aggregations_name = schema_def_state.schema_elements.normalize_case("#{singular}_aggregations")
+  relates_to(aggregations_name, type_ref.as_aggregation.as_connection.name, via: via, dir: dir, foreign_key_type: foreign_key_type, cardinality: :many, related_type: type) do |f|
+    f.argument schema_def_state.schema_elements.filter, type_ref.as_filter_input.name do |a|
+      a.documentation "Used to filter the `#{type}` documents that get aggregated over based on the provided criteria."
+    end
+
+    f.define_relay_pagination_arguments!
+
+    yield f if block_given?
+
+    f.documentation f.derived_documentation("Aggregations over the `#{field_name}` data")
+  end
+end
+
+
+ +
+

+ + #relates_to_one(field_name, type, via:, dir:) {|Relationship| ... } ⇒ void + + + + + +

+
+

This method returns an undefined value.

Defines a “has one” relationship between the current indexed type and another indexed type by defining a field clients +can use to navigate across indexed types in a single GraphQL query.

+ + +
+
+
+ +
+

Examples:

+ + +

Use relates_to_one to define Player.team

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Team" do |t|
+    t.field "id", "ID"
+    t.field "name", "String"
+    t.field "homeCity", "String"
+    t.index "teams"
+  end
+
+  schema.object_type "Player" do |t|
+    t.field "id", "ID"
+    t.field "name", "String"
+    t.relates_to_one "team", "Team", via: "teamId", dir: :out
+    t.index "players"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + field_name + + + (String) + + + + — +

    name of the relationship field

    +
    + +
  • + +
  • + + type + + + (String) + + + + — +

    name of the related type

    +
    + +
  • + +
  • + + via + + + (String) + + + + — +

    name of the foreign key field

    +
    + +
  • + +
  • + + dir + + + (:in, :out) + + + + — +

    direction of the foreign key. Use :in for an inbound foreign key that resides on the related type and +references the id of this type. Use :out for an outbound foreign key that resides on this type and references the id of +the related type.

    +
    + +
  • + +
+ +

Yields:

+
    + +
  • + + + (Relationship) + + + + — +

    the generated relationship fields, for further customization

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+355
+356
+357
+358
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb', line 355
+
+def relates_to_one(field_name, type, via:, dir:, &block)
+  foreign_key_type = schema_def_state.type_ref(type).non_null? ? "ID!" : "ID"
+  relates_to(field_name, type, via: via, dir: dir, foreign_key_type: foreign_key_type, cardinality: :one, related_type: type, &block)
+end
+
+
+ +
+

+ + #renamed_from(old_name) ⇒ void + + + + + +

+
+ +
+ Note: +

In situations where this API applies, ElasticGraph will give you an error message indicating that you need to use this API +or API#deleted_type. Likewise, when ElasticGraph no longer needs to know about this, it’ll give you a warning indicating +the call to this method can be removed.

+
+
+ +

This method returns an undefined value.

Registers an old name that this type used to have in a prior version of the schema.

+ + +
+
+
+ +
+

Examples:

+ + +

Indicate that Widget used to be called Component.

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Widget" do |t|
+    t.renamed_from "Component"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + old_name + + + (String) + + + + — +

    old name this field used to have in a prior version of the schema

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+262
+263
+264
+265
+266
+267
+268
+269
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb', line 262
+
+def renamed_from(old_name)
+  schema_def_state.register_renamed_type(
+    name,
+    from: old_name,
+    defined_at: caller_locations(2, 1).first, # : ::Thread::Backtrace::Location
+    defined_via: %(type.renamed_from "#{old_name}")
+  )
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/UnionType.html b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/UnionType.html new file mode 100644 index 00000000..19dc15f2 --- /dev/null +++ b/docs/main/ElasticGraph/SchemaDefinition/SchemaElements/UnionType.html @@ -0,0 +1,950 @@ + + + + + + + Class: ElasticGraph::SchemaDefinition::SchemaElements::UnionType + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: ElasticGraph::SchemaDefinition::SchemaElements::UnionType + + + +

+
+ +
+
Inherits:
+
+ Struct + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + +
+
Includes:
+
Mixins::CanBeGraphQLOnly, Mixins::HasDerivedGraphQLTypeCustomizations, Mixins::HasDirectives, Mixins::HasDocumentation, Mixins::HasIndices, Mixins::VerifiesGraphQLName
+
+ + + + + + +
+
Defined in:
+
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/union_type.rb
+
+ +
+ +

Overview

+
+

Defines a GraphQL union type. Use it to define an abstract supertype with one or +more concrete subtypes. Each subtype must be an ObjectType, but they do not have to share any fields in common.

+ + +
+
+
+ +
+

Examples:

+ + +

Define a union type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Card" do |t|
+    # ...
+  end
+
+  schema.object_type "BankAccount" do |t|
+    # ...
+  end
+
+  schema.object_type "BitcoinWallet" do |t|
+    # ...
+  end
+
+  schema.union_type "FundingSource" do |t|
+    t.subtype "Card"
+    t.subtypes "BankAccount", "BitcoinWallet"
+  end
+end
+ +
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

Attributes included from Mixins::HasDocumentation

+

#doc_comment

+ + + +

+ Instance Method Summary + collapse +

+ + + + + + + + + + + + + +

Methods included from Mixins::HasDerivedGraphQLTypeCustomizations

+

#customize_derived_type_fields, #customize_derived_types

+ + + + + + + + + + + + + + + +

Methods included from Mixins::HasIndices

+

#derive_indexed_type_fields, #derived_indexed_types, #index, #indexed?, #plural_root_query_field_name, #root_query_fields, #singular_root_query_field_name

+ + + + + + + + + + + + + + + +

Methods included from Mixins::HasDirectives

+

#directive, #directives, #directives_sdl

+ + + + + + + + + +

Methods included from Mixins::HasDocumentation

+

#append_to_documentation, #derived_documentation, #documentation, #formatted_documentation

+ + + + + + + + + +

Methods included from Mixins::CanBeGraphQLOnly

+

#graphql_only, #graphql_only?

+ + + + + + + + + +

Methods included from Mixins::VerifiesGraphQLName

+

verify_name!

+ + +
+

Instance Attribute Details

+ + + +
+

+ + #schema_def_stateState (readonly) + + + + + +

+
+

Returns state of the schema.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (State) + + + + — +

    state of the schema

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/union_type.rb', line 51
+
+class UnionType < Struct.new(:schema_def_state, :type_ref, :subtype_refs)
+  prepend Mixins::VerifiesGraphQLName
+  include Mixins::CanBeGraphQLOnly
+  include Mixins::HasDocumentation
+  include Mixins::HasDirectives
+  include Mixins::SupportsFilteringAndAggregation
+  include Mixins::HasIndices
+  include Mixins::HasSubtypes
+  include Mixins::HasDerivedGraphQLTypeCustomizations
+  include Mixins::HasReadableToSAndInspect.new { |t| t.name }
+
+  # @private
+  def initialize(schema_def_state, name)
+    super(schema_def_state, schema_def_state.type_ref(name).to_final_form, Set.new) do
+      yield self
+    end
+  end
+
+  # @return [String] the name of the union type
+  def name
+    type_ref.name
+  end
+
+  # Defines a subtype of this union type.
+  #
+  # @param name [String] the name of an object type which is a member of this union type
+  # @return [void]
+  #
+  # @example
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "Card" do |t|
+  #       # ...
+  #     end
+  #
+  #     schema.union_type "FundingSource" do |t|
+  #       t.subtype "Card"
+  #     end
+  #   end
+  def subtype(name)
+    type_ref = schema_def_state.type_ref(name.to_s).to_final_form
+
+    if subtype_refs.include?(type_ref)
+      raise Errors::SchemaError, "Duplicate subtype on UnionType #{self.name}: #{name}"
+    end
+
+    subtype_refs << type_ref
+  end
+
+  # Defines multiple subtypes of this union type.
+  #
+  # @param names [Array<String>] names of object types which are members of this union type
+  # @return [void]
+  #
+  # @example Define a union type
+  #   ElasticGraph.define_schema do |schema|
+  #     schema.object_type "BankAccount" do |t|
+  #       # ...
+  #     end
+  #
+  #     schema.object_type "BitcoinWallet" do |t|
+  #       # ...
+  #     end
+  #
+  #     schema.union_type "FundingSource" do |t|
+  #       t.subtypes "BankAccount", "BitcoinWallet"
+  #     end
+  #   end
+  def subtypes(*names)
+    names.flatten.each { |n| subtype(n) }
+  end
+
+  # @return [String] the formatted GraphQL SDL of the union type
+  def to_sdl
+    if subtype_refs.empty?
+      raise Errors::SchemaError, "UnionType type #{name} has no subtypes, but must have at least one."
+    end
+
+    "#{formatted_documentation}union #{name} #{directives_sdl(suffix_with: " ")}= #{subtype_refs.map(&:name).to_a.join(" | ")}"
+  end
+
+  # @private
+  def verify_graphql_correctness!
+    # Nothing to verify. `verify_graphql_correctness!` will be called on each subtype automatically.
+  end
+
+  # Various things check `mapping_options` on indexed types (usually object types, but can also happen on union types).
+  # We need to implement `mapping_options` here to satisfy those method calls, but we will never use custom mapping on
+  # a union type so we hardcode it to return nil.
+  #
+  # @private
+  def mapping_options
+    {}
+  end
+
+  private
+
+  def resolve_subtypes
+    subtype_refs.map do |ref|
+      ref.as_object_type || raise(
+        Errors::SchemaError, "The subtype `#{ref}` of the UnionType `#{name}` is not a defined object type."
+      )
+    end
+  end
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #nameString + + + + + +

+
+

Returns the name of the union type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    the name of the union type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+70
+71
+72
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/union_type.rb', line 70
+
+def name
+  type_ref.name
+end
+
+
+ +
+

+ + #subtype(name) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Defines a subtype of this union type.

+ + +
+
+
+ +
+

Examples:

+ + +
ElasticGraph.define_schema do |schema|
+  schema.object_type "Card" do |t|
+    # ...
+  end
+
+  schema.union_type "FundingSource" do |t|
+    t.subtype "Card"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + name + + + (String) + + + + — +

    the name of an object type which is a member of this union type

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+89
+90
+91
+92
+93
+94
+95
+96
+97
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/union_type.rb', line 89
+
+def subtype(name)
+  type_ref = schema_def_state.type_ref(name.to_s).to_final_form
+
+  if subtype_refs.include?(type_ref)
+    raise Errors::SchemaError, "Duplicate subtype on UnionType #{self.name}: #{name}"
+  end
+
+  subtype_refs << type_ref
+end
+
+
+ +
+

+ + #subtypes(*names) ⇒ void + + + + + +

+
+

This method returns an undefined value.

Defines multiple subtypes of this union type.

+ + +
+
+
+ +
+

Examples:

+ + +

Define a union type

+
+ +
ElasticGraph.define_schema do |schema|
+  schema.object_type "BankAccount" do |t|
+    # ...
+  end
+
+  schema.object_type "BitcoinWallet" do |t|
+    # ...
+  end
+
+  schema.union_type "FundingSource" do |t|
+    t.subtypes "BankAccount", "BitcoinWallet"
+  end
+end
+ +
+

Parameters:

+
    + +
  • + + names + + + (Array<String>) + + + + — +

    names of object types which are members of this union type

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+118
+119
+120
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/union_type.rb', line 118
+
+def subtypes(*names)
+  names.flatten.each { |n| subtype(n) }
+end
+
+
+ +
+

+ + #to_sdlString + + + + + +

+
+

Returns the formatted GraphQL SDL of the union type.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (String) + + + + — +

    the formatted GraphQL SDL of the union type

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+123
+124
+125
+126
+127
+128
+129
+
+
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/union_type.rb', line 123
+
+def to_sdl
+  if subtype_refs.empty?
+    raise Errors::SchemaError, "UnionType type #{name} has no subtypes, but must have at least one."
+  end
+
+  "#{formatted_documentation}union #{name} #{directives_sdl(suffix_with: " ")}= #{subtype_refs.map(&:name).to_a.join(" | ")}"
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/ElasticGraph/Support.html b/docs/main/ElasticGraph/Support.html new file mode 100644 index 00000000..681d3975 --- /dev/null +++ b/docs/main/ElasticGraph/Support.html @@ -0,0 +1,118 @@ + + + + + + + Module: ElasticGraph::Support + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: ElasticGraph::Support + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
elasticgraph-support/lib/elastic_graph/support/from_yaml_file.rb,
+ elasticgraph-support/lib/elastic_graph/support/logger.rb,
elasticgraph-support/lib/elastic_graph/support/time_set.rb,
elasticgraph-support/lib/elastic_graph/support/hash_util.rb,
elasticgraph-support/lib/elastic_graph/support/threading.rb,
elasticgraph-support/lib/elastic_graph/support/time_util.rb,
elasticgraph-support/lib/elastic_graph/support/memoizable_data.rb,
elasticgraph-support/lib/elastic_graph/support/monotonic_clock.rb,
elasticgraph-support/lib/elastic_graph/support/untyped_encoder.rb,
elasticgraph-support/lib/elastic_graph/support/graphql_formatter.rb,
elasticgraph-support/lib/elastic_graph/support/faraday_middleware/support_timeouts.rb,
elasticgraph-support/lib/elastic_graph/support/faraday_middleware/msearch_using_get_instead_of_post.rb
+
+
+ +
+ +

Overview

+
+

Provides support utilities for the rest of the ElasticGraph gems. As such, it is not intended +to provide public APIs for ElasticGraph users.

+ + +
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/docs/main/README-1.svg b/docs/main/README-1.svg new file mode 100644 index 00000000..9f8bf431 --- /dev/null +++ b/docs/main/README-1.svg @@ -0,0 +1 @@ +

elasticgraph

elasticgraph-admin

elasticgraph-graphql

elasticgraph-indexer

elasticgraph-local

elasticgraph-datastore_core

elasticgraph-schema_artifacts

elasticgraph-support

rake

graphql

elasticgraph-json_schema

hashdiff

json_schemer

logger

\ No newline at end of file diff --git a/docs/main/README-2.svg b/docs/main/README-2.svg new file mode 100644 index 00000000..762a173d --- /dev/null +++ b/docs/main/README-2.svg @@ -0,0 +1 @@ +

elasticgraph-admin_lambda

rake

elasticgraph-admin

elasticgraph-lambda_support

elasticgraph-graphql_lambda

elasticgraph-graphql

elasticgraph-indexer_autoscaler_lambda

elasticgraph-datastore_core

aws-sdk-lambda

aws-sdk-sqs

ox

elasticgraph-indexer_lambda

elasticgraph-indexer

aws-sdk-s3

elasticgraph-opensearch

faraday_middleware-aws-sigv4

\ No newline at end of file diff --git a/docs/main/README-3.svg b/docs/main/README-3.svg new file mode 100644 index 00000000..1a8fa167 --- /dev/null +++ b/docs/main/README-3.svg @@ -0,0 +1 @@ +

elasticgraph-apollo

elasticgraph-graphql

elasticgraph-support

graphql

apollo-federation

elasticgraph-health_check

elasticgraph-datastore_core

elasticgraph-query_interceptor

elasticgraph-schema_artifacts

elasticgraph-query_registry

rake

\ No newline at end of file diff --git a/docs/main/README-4.svg b/docs/main/README-4.svg new file mode 100644 index 00000000..4ec0e730 --- /dev/null +++ b/docs/main/README-4.svg @@ -0,0 +1 @@ +

elasticgraph-elasticsearch

elasticgraph-support

elasticsearch

faraday

faraday-retry

elasticgraph-opensearch

opensearch-ruby

\ No newline at end of file diff --git a/docs/main/README-5.svg b/docs/main/README-5.svg new file mode 100644 index 00000000..ef912ca0 --- /dev/null +++ b/docs/main/README-5.svg @@ -0,0 +1 @@ +

elasticgraph-local

elasticgraph-admin

elasticgraph-graphql

elasticgraph-indexer

elasticgraph-rack

elasticgraph-schema_definition

rackup

rake

rack

elasticgraph-json_schema

elasticgraph-schema_artifacts

elasticgraph-support

graphql

\ No newline at end of file diff --git a/docs/main/class_list.html b/docs/main/class_list.html new file mode 100644 index 00000000..f48ce3fc --- /dev/null +++ b/docs/main/class_list.html @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + Class List + + + +
+
+

Class List

+ + + +
+ + +
+ + diff --git a/docs/main/css/common.css b/docs/main/css/common.css new file mode 100644 index 00000000..cf25c452 --- /dev/null +++ b/docs/main/css/common.css @@ -0,0 +1 @@ +/* Override this file with custom rules */ \ No newline at end of file diff --git a/docs/main/css/full_list.css b/docs/main/css/full_list.css new file mode 100644 index 00000000..6eef5e4a --- /dev/null +++ b/docs/main/css/full_list.css @@ -0,0 +1,58 @@ +body { + margin: 0; + font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; + font-size: 13px; + height: 101%; + overflow-x: hidden; + background: #fafafa; +} + +h1 { padding: 12px 10px; padding-bottom: 0; margin: 0; font-size: 1.4em; } +.clear { clear: both; } +.fixed_header { position: fixed; background: #fff; width: 100%; padding-bottom: 10px; margin-top: 0; top: 0; z-index: 9999; height: 70px; } +#search { position: absolute; right: 5px; top: 9px; padding-left: 24px; } +#content.insearch #search, #content.insearch #noresults { background: url(data:image/gif;base64,R0lGODlhEAAQAPYAAP///wAAAPr6+pKSkoiIiO7u7sjIyNjY2J6engAAAI6OjsbGxjIyMlJSUuzs7KamppSUlPLy8oKCghwcHLKysqSkpJqamvT09Pj4+KioqM7OzkRERAwMDGBgYN7e3ujo6Ly8vCoqKjY2NkZGRtTU1MTExDw8PE5OTj4+PkhISNDQ0MrKylpaWrS0tOrq6nBwcKysrLi4uLq6ul5eXlxcXGJiYoaGhuDg4H5+fvz8/KKiohgYGCwsLFZWVgQEBFBQUMzMzDg4OFhYWBoaGvDw8NbW1pycnOLi4ubm5kBAQKqqqiQkJCAgIK6urnJyckpKSjQ0NGpqatLS0sDAwCYmJnx8fEJCQlRUVAoKCggICLCwsOTk5ExMTPb29ra2tmZmZmhoaNzc3KCgoBISEiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCAAAACwAAAAAEAAQAAAHaIAAgoMgIiYlg4kACxIaACEJCSiKggYMCRselwkpghGJBJEcFgsjJyoAGBmfggcNEx0flBiKDhQFlIoCCA+5lAORFb4AJIihCRbDxQAFChAXw9HSqb60iREZ1omqrIPdJCTe0SWI09GBACH5BAkIAAAALAAAAAAQABAAAAdrgACCgwc0NTeDiYozCQkvOTo9GTmDKy8aFy+NOBA7CTswgywJDTIuEjYFIY0JNYMtKTEFiRU8Pjwygy4ws4owPyCKwsMAJSTEgiQlgsbIAMrO0dKDGMTViREZ14kYGRGK38nHguHEJcvTyIEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDAggPg4iJAAMJCRUAJRIqiRGCBI0WQEEJJkWDERkYAAUKEBc4Po1GiKKJHkJDNEeKig4URLS0ICImJZAkuQAhjSi/wQyNKcGDCyMnk8u5rYrTgqDVghgZlYjcACTA1sslvtHRgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCQARAtOUoQRGRiFD0kJUYWZhUhKT1OLhR8wBaaFBzQ1NwAlkIszCQkvsbOHL7Y4q4IuEjaqq0ZQD5+GEEsJTDCMmIUhtgk1lo6QFUwJVDKLiYJNUd6/hoEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4uen4ICCA+IkIsDCQkVACWmhwSpFqAABQoQF6ALTkWFnYMrVlhWvIKTlSAiJiVVPqlGhJkhqShHV1lCW4cMqSkAR1ofiwsjJyqGgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCSMhREZGIYYGY2ElYebi56fhyWQniSKAKKfpaCLFlAPhl0gXYNGEwkhGYREUywag1wJwSkHNDU3D0kJYIMZQwk8MjPBLx9eXwuETVEyAC/BOKsuEjYFhoEAIfkECQgAAAAsAAAAABAAEAAAB2eAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4ueICImip6CIQkJKJ4kigynKaqKCyMnKqSEK05StgAGQRxPYZaENqccFgIID4KXmQBhXFkzDgOnFYLNgltaSAAEpxa7BQoQF4aBACH5BAkIAAAALAAAAAAQABAAAAdogACCg4SFggJiPUqCJSWGgkZjCUwZACQkgxGEXAmdT4UYGZqCGWQ+IjKGGIUwPzGPhAc0NTewhDOdL7Ykji+dOLuOLhI2BbaFETICx4MlQitdqoUsCQ2vhKGjglNfU0SWmILaj43M5oEAOwAAAAAAAAAAAA==) no-repeat center left; } +#full_list { padding: 0; list-style: none; margin-left: 0; margin-top: 80px; font-size: 1.1em; } +#full_list ul { padding: 0; } +#full_list li { padding: 0; margin: 0; list-style: none; } +#full_list li .item { padding: 5px 5px 5px 12px; } +#noresults { padding: 7px 12px; background: #fff; } +#content.insearch #noresults { margin-left: 7px; } +li.collapsed ul { display: none; } +li a.toggle { cursor: default; position: relative; left: -5px; top: 4px; text-indent: -999px; width: 10px; height: 9px; margin-left: -10px; display: block; float: left; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK8AAACvABQqw0mAAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTM5jWRgMAAAAVdEVYdENyZWF0aW9uIFRpbWUAMy8xNC8wOeNZPpQAAAE2SURBVDiNrZTBccIwEEXfelIAHUA6CZ24BGaWO+FuzZAK4k6gg5QAdGAq+Bxs2Yqx7BzyL7Llp/VfzZeQhCTc/ezuGzKKnKSzpCxXJM8fwNXda3df5RZETlIt6YUzSQDs93sl8w3wBZxCCE10GM1OcWbWjB2mWgEH4Mfdyxm3PSepBHibgQE2wLe7r4HjEidpnXMYdQPKEMJcsZ4zs2POYQOcaPfwMVOo58zsAdMt18BuoVDPxUJRacELbXv3hUIX2vYmOUvi8C8ydz/ThjXrqKqqLbDIAdsCKBd+Wo7GWa7o9qzOQHVVVXeAbs+yHHCH4aTsaCOQqunmUy1yBUAXkdMIfMlgF5EXLo2OpV/c/Up7jG4hhHcYLgWzAZXUc2b2ixsfvc/RmNNfOXD3Q/oeL9axJE1yT9IOoUu6MGUkAAAAAElFTkSuQmCC) no-repeat bottom left; } +li.collapsed a.toggle { cursor: default; background-position: top left; } +li { color: #666; cursor: pointer; } +li.deprecated { text-decoration: line-through; font-style: italic; } +li.odd { background: #f0f0f0; } +li.even { background: #fafafa; } +.item:hover { background: #ddd; } +li small:before { content: "("; } +li small:after { content: ")"; } +li small.search_info { display: none; } +a, a:visited { text-decoration: none; color: #05a; } +li.clicked > .item { background: #05a; color: #ccc; } +li.clicked > .item a, li.clicked > .item a:visited { color: #eee; } +li.clicked > .item a.toggle { opacity: 0.5; background-position: bottom right; } +li.collapsed.clicked a.toggle { background-position: top right; } +#search input { border: 1px solid #bbb; border-radius: 3px; } +#full_list_nav { margin-left: 10px; font-size: 0.9em; display: block; color: #aaa; } +#full_list_nav a, #nav a:visited { color: #358; } +#full_list_nav a:hover { background: transparent; color: #5af; } +#full_list_nav span:after { content: ' | '; } +#full_list_nav span:last-child:after { content: ''; } + +#content h1 { margin-top: 0; } +li { white-space: nowrap; cursor: normal; } +li small { display: block; font-size: 0.8em; } +li small:before { content: ""; } +li small:after { content: ""; } +li small.search_info { display: none; } +#search { width: 170px; position: static; margin: 3px; margin-left: 10px; font-size: 0.9em; color: #666; padding-left: 0; padding-right: 24px; } +#content.insearch #search { background-position: center right; } +#search input { width: 110px; } + +#full_list.insearch ul { display: block; } +#full_list.insearch .item { display: none; } +#full_list.insearch .found { display: block; padding-left: 11px !important; } +#full_list.insearch li a.toggle { display: none; } +#full_list.insearch li small.search_info { display: block; } diff --git a/docs/main/css/style.css b/docs/main/css/style.css new file mode 100644 index 00000000..f169a651 --- /dev/null +++ b/docs/main/css/style.css @@ -0,0 +1,503 @@ +html { + width: 100%; + height: 100%; +} +body { + font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; + font-size: 13px; + width: 100%; + margin: 0; + padding: 0; + display: flex; + display: -webkit-flex; + display: -ms-flexbox; +} + +#nav { + position: relative; + width: 100%; + height: 100%; + border: 0; + border-right: 1px dotted #eee; + overflow: auto; +} +.nav_wrap { + margin: 0; + padding: 0; + width: 20%; + height: 100%; + position: relative; + display: flex; + display: -webkit-flex; + display: -ms-flexbox; + flex-shrink: 0; + -webkit-flex-shrink: 0; + -ms-flex: 1 0; +} +#resizer { + position: absolute; + right: -5px; + top: 0; + width: 10px; + height: 100%; + cursor: col-resize; + z-index: 9999; +} +#main { + flex: 5 1; + -webkit-flex: 5 1; + -ms-flex: 5 1; + outline: none; + position: relative; + background: #fff; + padding: 1.2em; + padding-top: 0.2em; + box-sizing: border-box; +} + +@media (max-width: 920px) { + .nav_wrap { width: 100%; top: 0; right: 0; overflow: visible; position: absolute; } + #resizer { display: none; } + #nav { + z-index: 9999; + background: #fff; + display: none; + position: absolute; + top: 40px; + right: 12px; + width: 500px; + max-width: 80%; + height: 80%; + overflow-y: scroll; + border: 1px solid #999; + border-collapse: collapse; + box-shadow: -7px 5px 25px #aaa; + border-radius: 2px; + } +} + +@media (min-width: 920px) { + body { height: 100%; overflow: hidden; } + #main { height: 100%; overflow: auto; } + #search { display: none; } +} + +@media (max-width: 320px) { + body { height: 100%; overflow: hidden; overflow-wrap: break-word; } + #main { height: 100%; overflow: auto; } +} + +#main img { max-width: 100%; } +h1 { font-size: 25px; margin: 1em 0 0.5em; padding-top: 4px; border-top: 1px dotted #d5d5d5; } +h1.noborder { border-top: 0px; margin-top: 0; padding-top: 4px; } +h1.title { margin-bottom: 10px; } +h1.alphaindex { margin-top: 0; font-size: 22px; } +h2 { + padding: 0; + padding-bottom: 3px; + border-bottom: 1px #aaa solid; + font-size: 1.4em; + margin: 1.8em 0 0.5em; + position: relative; +} +h2 small { font-weight: normal; font-size: 0.7em; display: inline; position: absolute; right: 0; } +h2 small a { + display: block; + height: 20px; + border: 1px solid #aaa; + border-bottom: 0; + border-top-left-radius: 5px; + background: #f8f8f8; + position: relative; + padding: 2px 7px; +} +a { font-weight: 550; } +.clear { clear: both; } +.inline { display: inline; } +.inline p:first-child { display: inline; } +.docstring, .tags, #filecontents { font-size: 15px; line-height: 1.5145em; } +.docstring p > code, .docstring p > tt, .tags p > code, .tags p > tt { + color: #c7254e; background: #f9f2f4; padding: 2px 4px; font-size: 1em; + border-radius: 4px; +} +.docstring h1, .docstring h2, .docstring h3, .docstring h4 { padding: 0; border: 0; border-bottom: 1px dotted #bbb; } +.docstring h1 { font-size: 1.2em; } +.docstring h2 { font-size: 1.1em; } +.docstring h3, .docstring h4 { font-size: 1em; border-bottom: 0; padding-top: 10px; } +.summary_desc .object_link a, .docstring .object_link a { + font-family: monospace; font-size: 1.05em; + color: #05a; background: #EDF4FA; padding: 2px 4px; font-size: 1em; + border-radius: 4px; +} +.rdoc-term { padding-right: 25px; font-weight: bold; } +.rdoc-list p { margin: 0; padding: 0; margin-bottom: 4px; } +.summary_desc pre.code .object_link a, .docstring pre.code .object_link a { + padding: 0px; background: inherit; color: inherit; border-radius: inherit; +} + +/* style for */ +#filecontents table, .docstring table { border-collapse: collapse; } +#filecontents table th, #filecontents table td, +.docstring table th, .docstring table td { border: 1px solid #ccc; padding: 8px; padding-right: 17px; } +#filecontents table tr:nth-child(odd), +.docstring table tr:nth-child(odd) { background: #eee; } +#filecontents table tr:nth-child(even), +.docstring table tr:nth-child(even) { background: #fff; } +#filecontents table th, .docstring table th { background: #fff; } + +/* style for
a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
"+""+"
",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
t
",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; +f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() +{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/docs/main/method_list.html b/docs/main/method_list.html new file mode 100644 index 00000000..4c99f8c7 --- /dev/null +++ b/docs/main/method_list.html @@ -0,0 +1,1958 @@ + + + + + + + + + + + + + + + + + + Method List + + + +
+
+

Method List

+ + + +
+ +
    + + +
  • +
    + #additional_filter + ElasticGraph::SchemaDefinition::SchemaElements::Relationship +
    +
  • + + +
  • +
    + #aggregatable? + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #aggregated_values_type + ElasticGraph::SchemaDefinition::SchemaElements::EnumType +
    +
  • + + +
  • +
    + #apollo_authenticated + ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Authenticated +
    +
  • + + +
  • +
    + #apollo_extends + ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Extends +
    +
  • + + +
  • +
    + #apollo_external + ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::External +
    +
  • + + +
  • +
    + #apollo_inaccessible + ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Inaccessible +
    +
  • + + +
  • +
    + #apollo_interface_object + ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::InterfaceObject +
    +
  • + + +
  • +
    + #apollo_key + ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Key +
    +
  • + + +
  • +
    + #apollo_override + ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Override +
    +
  • + + +
  • +
    + #apollo_policy + ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Policy +
    +
  • + + +
  • +
    + #apollo_provides + ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Provides +
    +
  • + + +
  • +
    + #apollo_requires + ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Requires +
    +
  • + + +
  • +
    + #apollo_requires_scopes + ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::RequiresScopes +
    +
  • + + +
  • +
    + #apollo_shareable + ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Shareable +
    +
  • + + +
  • +
    + #apollo_tag + ElasticGraph::Apollo::SchemaDefinition::ApolloDirectives::Tag +
    +
  • + + +
  • +
    + #append_only_set + ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType +
    +
  • + + +
  • +
    + #append_to_documentation + ElasticGraph::SchemaDefinition::Mixins::HasDocumentation +
    +
  • + + +
  • +
    + #apply_operation_returning_update_status + ElasticGraph::SchemaDefinition::Indexing::DerivedFields::AppendOnlySet +
    +
  • + + +
  • +
    + #apply_operation_returning_update_status + ElasticGraph::SchemaDefinition::Indexing::DerivedFields::ImmutableValue +
    +
  • + + +
  • +
    + #apply_operation_returning_update_status + ElasticGraph::SchemaDefinition::Indexing::DerivedFields::MinOrMaxValue +
    +
  • + + +
  • +
    + #argument + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #arguments + ElasticGraph::SchemaDefinition::SchemaElements::Directive +
    +
  • + + +
  • +
    + #as_input + ElasticGraph::SchemaDefinition::SchemaElements::EnumType +
    +
  • + + +
  • +
    + #available_json_schema_versions + ElasticGraph::SchemaDefinition::Results +
    +
  • + + +
  • +
    + build_empty_value_initializers + ElasticGraph::SchemaDefinition::Indexing::DerivedFields::FieldInitializerSupport +
    +
  • + + +
  • +
    + #call + ElasticGraph::Rack::GraphQLEndpoint +
    +
  • + + +
  • +
    + #coerce_with + ElasticGraph::SchemaDefinition::SchemaElements::ScalarType +
    +
  • + + +
  • +
    + #customize_aggregated_values_field + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #customize_derived_type_fields + ElasticGraph::SchemaDefinition::Mixins::HasDerivedGraphQLTypeCustomizations +
    +
  • + + +
  • +
    + #customize_derived_types + ElasticGraph::SchemaDefinition::Mixins::HasDerivedGraphQLTypeCustomizations +
    +
  • + + +
  • +
    + #customize_filter_field + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #customize_grouped_by_field + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #customize_sort_order_enum_values + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #customize_sub_aggregations_field + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #daemon_timeout + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + #datastore_config + ElasticGraph::SchemaDefinition::Results +
    +
  • + + +
  • +
    + #default + ElasticGraph::SchemaDefinition::Mixins::SupportsDefaultValue +
    +
  • + + +
  • +
    + #default_sort + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + #default_sort_pairs + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + default_source_field_to_empty + ElasticGraph::SchemaDefinition::Indexing::DerivedFields::FieldInitializerSupport +
    +
  • + + +
  • +
    + #default_value_sdl + ElasticGraph::SchemaDefinition::Mixins::SupportsDefaultValue +
    +
  • + + +
  • +
    + #define_fake_data_batch_for + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + define_schema + ElasticGraph +
    +
  • + + +
  • +
    + #deleted_field + ElasticGraph::SchemaDefinition::SchemaElements::TypeWithSubfields +
    +
  • + + +
  • +
    + #deleted_type + ElasticGraph::SchemaDefinition::API +
    +
  • + + +
  • +
    + #derive_indexed_type_fields + ElasticGraph::SchemaDefinition::Mixins::HasIndices +
    +
  • + + +
  • +
    + #derived_documentation + ElasticGraph::SchemaDefinition::Mixins::HasDocumentation +
    +
  • + + +
  • +
    + #derived_indexed_types + ElasticGraph::SchemaDefinition::Mixins::HasIndices +
    +
  • + + +
  • +
    + #derived_type_name_formats + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + #directive + ElasticGraph::SchemaDefinition::Mixins::HasDirectives +
    +
  • + + +
  • +
    + #directives + ElasticGraph::SchemaDefinition::Mixins::HasDirectives +
    +
  • + + +
  • +
    + #directives_sdl + ElasticGraph::SchemaDefinition::Mixins::HasDirectives +
    +
  • + + +
  • +
    + #doc_comment + ElasticGraph::SchemaDefinition::Mixins::HasDocumentation +
    +
  • + + +
  • +
    + #documentation + ElasticGraph::SchemaDefinition::Mixins::HasDocumentation +
    +
  • + + +
  • +
    + #duplicate_on + ElasticGraph::SchemaDefinition::SchemaElements::Directive +
    +
  • + + +
  • +
    + #duplicate_on + ElasticGraph::SchemaDefinition::SchemaElements::EnumValue +
    +
  • + + +
  • +
    + elastic_graph_internal_meta_schema_validator + ElasticGraph::JSONSchema +
    +
  • + + +
  • +
    + #elasticsearch_versions + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + #enforce_json_schema_version + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + #enum_type + ElasticGraph::SchemaDefinition::API +
    +
  • + + +
  • +
    + #enum_value_names + ElasticGraph::SchemaDefinition::Indexing::FieldType::Enum +
    +
  • + + +
  • +
    + #enum_value_overrides_by_type + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + #env_port_mapping + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + #equivalent_field + ElasticGraph::SchemaDefinition::SchemaElements::Relationship +
    +
  • + + +
  • +
    + #factory + ElasticGraph::SchemaDefinition::API +
    +
  • + + +
  • +
    + #field + ElasticGraph::SchemaDefinition::SchemaElements::TypeWithSubfields +
    +
  • + + +
  • +
    + #fields + ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType +
    +
  • + + +
  • +
    + #filterable? + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #for_output + ElasticGraph::SchemaDefinition::SchemaElements::EnumType +
    +
  • + + +
  • +
    + #format_field_json_schema_customizations + ElasticGraph::SchemaDefinition::Indexing::FieldType::Enum +
    +
  • + + +
  • +
    + #format_field_json_schema_customizations + ElasticGraph::SchemaDefinition::Indexing::FieldType::Union +
    +
  • + + +
  • +
    + #format_field_json_schema_customizations + ElasticGraph::SchemaDefinition::Indexing::FieldType::Object +
    +
  • + + +
  • +
    + #format_field_json_schema_customizations + ElasticGraph::SchemaDefinition::Indexing::FieldType::Scalar +
    +
  • + + +
  • +
    + #formatted_documentation + ElasticGraph::SchemaDefinition::Mixins::HasDocumentation +
    +
  • + + +
  • +
    + function_def + ElasticGraph::SchemaDefinition::Indexing::DerivedFields::MinOrMaxValue +
    +
  • + + +
  • +
    + #function_definitions + ElasticGraph::SchemaDefinition::Indexing::DerivedFields::AppendOnlySet +
    +
  • + + +
  • +
    + #function_definitions + ElasticGraph::SchemaDefinition::Indexing::DerivedFields::ImmutableValue +
    +
  • + + +
  • +
    + #function_definitions + ElasticGraph::SchemaDefinition::Indexing::DerivedFields::MinOrMaxValue +
    +
  • + + +
  • +
    + #graphql_only + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #graphql_only + ElasticGraph::SchemaDefinition::Mixins::CanBeGraphQLOnly +
    +
  • + + +
  • +
    + #graphql_only? + ElasticGraph::SchemaDefinition::Mixins::CanBeGraphQLOnly +
    +
  • + + +
  • +
    + #graphql_schema_string + ElasticGraph::SchemaDefinition::Results +
    +
  • + + +
  • +
    + #groupable? + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #id_source + ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType +
    +
  • + + +
  • +
    + #immutable_value + ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType +
    +
  • + + +
  • +
    + #implemented_interfaces + ElasticGraph::SchemaDefinition::Mixins::ImplementsInterfaces +
    +
  • + + +
  • +
    + #implements + ElasticGraph::SchemaDefinition::Mixins::ImplementsInterfaces +
    +
  • + + +
  • +
    + #index + ElasticGraph::SchemaDefinition::Mixins::HasIndices +
    +
  • + + +
  • +
    + #index_document_sizes + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + #indexed? + ElasticGraph::SchemaDefinition::Mixins::HasIndices +
    +
  • + + +
  • +
    + #indexed? + ElasticGraph::SchemaDefinition::SchemaElements::EnumType +
    +
  • + + +
  • +
    + #indexed_type + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + #initialize + ElasticGraph::JSONSchema::ValidatorFactory +
    +
  • + + +
  • +
    + #initialize + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + #initialize + ElasticGraph::Rack::GraphQLEndpoint +
    +
  • + + +
  • +
    + #initialize + ElasticGraph::SchemaDefinition::RakeTasks +
    +
  • + + +
  • +
    + #initialize + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + #initialize + ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType +
    +
  • + + +
  • +
    + #interface_type + ElasticGraph::SchemaDefinition::API +
    +
  • + + +
  • +
    + #json_schema + ElasticGraph::SchemaDefinition::Indexing::Field +
    +
  • + + +
  • +
    + #json_schema + ElasticGraph::SchemaDefinition::Mixins::HasTypeInfo +
    +
  • + + +
  • +
    + #json_schema + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + json_schema + ElasticGraph::SchemaDefinition::Indexing::EventEnvelope +
    +
  • + + +
  • +
    + #json_schema_field_metadata_by_field_name + ElasticGraph::SchemaDefinition::Indexing::FieldType::Enum +
    +
  • + + +
  • +
    + #json_schema_field_metadata_by_field_name + ElasticGraph::SchemaDefinition::Indexing::FieldType::Union +
    +
  • + + +
  • +
    + #json_schema_field_metadata_by_field_name + ElasticGraph::SchemaDefinition::Indexing::FieldType::Object +
    +
  • + + +
  • +
    + #json_schema_field_metadata_by_field_name + ElasticGraph::SchemaDefinition::Indexing::FieldType::Scalar +
    +
  • + + +
  • +
    + #json_schema_metadata + ElasticGraph::SchemaDefinition::Indexing::Field +
    +
  • + + +
  • +
    + #json_schema_options + ElasticGraph::SchemaDefinition::Mixins::HasTypeInfo +
    +
  • + + +
  • +
    + #json_schema_options + ElasticGraph::SchemaDefinition::Indexing::FieldType::Object +
    +
  • + + +
  • +
    + #json_schema_version + ElasticGraph::SchemaDefinition::API +
    +
  • + + +
  • +
    + #json_schemas_for + ElasticGraph::SchemaDefinition::Results +
    +
  • + + +
  • +
    + #latest_json_schema_version + ElasticGraph::SchemaDefinition::Results +
    +
  • + + +
  • +
    + load_strict_validator + ElasticGraph::JSONSchema::MetaSchemaLoader +
    +
  • + + +
  • +
    + #mapping + ElasticGraph::SchemaDefinition::Indexing::Field +
    +
  • + + +
  • +
    + #mapping + ElasticGraph::SchemaDefinition::Mixins::HasTypeInfo +
    +
  • + + +
  • +
    + #mapping + ElasticGraph::SchemaDefinition::SchemaElements::ScalarType +
    +
  • + + +
  • +
    + #mapping_options + ElasticGraph::SchemaDefinition::Mixins::HasTypeInfo +
    +
  • + + +
  • +
    + #mapping_options + ElasticGraph::SchemaDefinition::Indexing::FieldType::Object +
    +
  • + + +
  • +
    + #mapping_type + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #max_value + ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType +
    +
  • + + +
  • +
    + #min_value + ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType +
    +
  • + + +
  • +
    + #name + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + #name + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #name + ElasticGraph::SchemaDefinition::SchemaElements::Argument +
    +
  • + + +
  • +
    + #name + ElasticGraph::SchemaDefinition::SchemaElements::Directive +
    +
  • + + +
  • +
    + #name + ElasticGraph::SchemaDefinition::SchemaElements::EnumType +
    +
  • + + +
  • +
    + #name + ElasticGraph::SchemaDefinition::SchemaElements::EnumValue +
    +
  • + + +
  • +
    + #name + ElasticGraph::SchemaDefinition::SchemaElements::UnionType +
    +
  • + + +
  • +
    + #name + ElasticGraph::SchemaDefinition::SchemaElements::ScalarType +
    +
  • + + +
  • +
    + #name + ElasticGraph::SchemaDefinition::SchemaElements::TypeWithSubfields +
    +
  • + + +
  • +
    + #name_in_index + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #name_in_index + ElasticGraph::SchemaDefinition::Indexing::JSONSchemaFieldMetadata +
    +
  • + + +
  • +
    + new + ElasticGraph::Rack::GraphiQL +
    +
  • + + +
  • +
    + normalized_mapping_hash_for + ElasticGraph::SchemaDefinition::Indexing::Field +
    +
  • + + +
  • +
    + #object_type + ElasticGraph::SchemaDefinition::API +
    +
  • + + +
  • +
    + #on_built_in_types + ElasticGraph::SchemaDefinition::API +
    +
  • + + +
  • +
    + #on_each_generated_schema_element + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #opensearch_versions + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + #original_value_type + ElasticGraph::SchemaDefinition::SchemaElements::Argument +
    +
  • + + +
  • +
    + #output + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + #paginated_collection_field + ElasticGraph::SchemaDefinition::SchemaElements::TypeWithSubfields +
    +
  • + + +
  • +
    + #painless_script + ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType +
    +
  • + + +
  • +
    + #parent_field + ElasticGraph::SchemaDefinition::SchemaElements::Argument +
    +
  • + + +
  • +
    + #plural_root_query_field_name + ElasticGraph::SchemaDefinition::Mixins::HasIndices +
    +
  • + + +
  • +
    + #prepare_for_indexing_with + ElasticGraph::SchemaDefinition::SchemaElements::ScalarType +
    +
  • + + +
  • +
    + #raw_sdl + ElasticGraph::SchemaDefinition::API +
    +
  • + + +
  • +
    + #register_graphql_extension + ElasticGraph::SchemaDefinition::API +
    +
  • + + +
  • +
    + #related_type + ElasticGraph::SchemaDefinition::SchemaElements::Relationship +
    +
  • + + +
  • +
    + #relates_to_many + ElasticGraph::SchemaDefinition::SchemaElements::TypeWithSubfields +
    +
  • + + +
  • +
    + #relates_to_one + ElasticGraph::SchemaDefinition::SchemaElements::TypeWithSubfields +
    +
  • + + +
  • +
    + #renamed_from + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #renamed_from + ElasticGraph::SchemaDefinition::SchemaElements::TypeWithSubfields +
    +
  • + + +
  • +
    + #resolve + ElasticGraph::SchemaDefinition::Indexing::FieldReference +
    +
  • + + +
  • +
    + #results + ElasticGraph::SchemaDefinition::API +
    +
  • + + +
  • +
    + #rollover + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + #rollover_config + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + #rollover_timestamp_value_source + ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType +
    +
  • + + +
  • +
    + #root_query_fields + ElasticGraph::SchemaDefinition::Mixins::HasIndices +
    +
  • + + +
  • +
    + #route_with + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + #routing_field_path + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + #routing_value_source + ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType +
    +
  • + + +
  • +
    + #runtime_metadata + ElasticGraph::SchemaDefinition::Results +
    +
  • + + +
  • +
    + #runtime_metadata + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + #runtime_metadata + ElasticGraph::SchemaDefinition::SchemaElements::EnumType +
    +
  • + + +
  • +
    + #runtime_metadata + ElasticGraph::SchemaDefinition::SchemaElements::EnumValue +
    +
  • + + +
  • +
    + #runtime_metadata_for_source_type + ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType +
    +
  • + + +
  • +
    + #sanitize_pii + ElasticGraph::JSONSchema::Validator +
    +
  • + + +
  • +
    + #scalar_type + ElasticGraph::SchemaDefinition::API +
    +
  • + + +
  • +
    + #scalar_type + ElasticGraph::SchemaDefinition::Indexing::FieldType::Scalar +
    +
  • + + +
  • +
    + #schema + ElasticGraph::JSONSchema::Validator +
    +
  • + + +
  • +
    + #schema_def_state + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + #schema_def_state + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #schema_def_state + ElasticGraph::SchemaDefinition::SchemaElements::Argument +
    +
  • + + +
  • +
    + #schema_def_state + ElasticGraph::SchemaDefinition::SchemaElements::EnumType +
    +
  • + + +
  • +
    + #schema_def_state + ElasticGraph::SchemaDefinition::SchemaElements::EnumValue +
    +
  • + + +
  • +
    + #schema_def_state + ElasticGraph::SchemaDefinition::SchemaElements::UnionType +
    +
  • + + +
  • +
    + #schema_def_state + ElasticGraph::SchemaDefinition::SchemaElements::ScalarType +
    +
  • + + +
  • +
    + #schema_definition_extension_modules + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + #schema_element_name_form + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + #schema_element_name_overrides + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + #settings + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + #setup_statements + ElasticGraph::SchemaDefinition::Indexing::DerivedFields::AppendOnlySet +
    +
  • + + +
  • +
    + #setup_statements + ElasticGraph::SchemaDefinition::Indexing::DerivedFields::ImmutableValue +
    +
  • + + +
  • +
    + #setup_statements + ElasticGraph::SchemaDefinition::Indexing::DerivedFields::MinOrMaxValue +
    +
  • + + +
  • +
    + #singular_root_query_field_name + ElasticGraph::SchemaDefinition::Mixins::HasIndices +
    +
  • + + +
  • +
    + #sort_order_field_path + ElasticGraph::SchemaDefinition::SchemaElements::SortOrderEnumValue +
    +
  • + + +
  • +
    + #sortable? + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #source_type + ElasticGraph::SchemaDefinition::Indexing::DerivedIndexedType +
    +
  • + + +
  • +
    + #sourced_from + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #state + ElasticGraph::SchemaDefinition::API +
    +
  • + + +
  • +
    + strict_meta_schema_validator + ElasticGraph::JSONSchema +
    +
  • + + +
  • +
    + #sub_aggregatable? + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #subfields + ElasticGraph::SchemaDefinition::Indexing::FieldType::Object +
    +
  • + + +
  • +
    + #subtype + ElasticGraph::SchemaDefinition::SchemaElements::UnionType +
    +
  • + + +
  • +
    + #subtypes + ElasticGraph::SchemaDefinition::SchemaElements::UnionType +
    +
  • + + +
  • +
    + #subtypes_by_name + ElasticGraph::SchemaDefinition::Indexing::FieldType::Union +
    +
  • + + +
  • +
    + #tag_built_in_types_with + ElasticGraph::Apollo::SchemaDefinition::APIExtension +
    +
  • + + +
  • +
    + #tag_with + ElasticGraph::Apollo::SchemaDefinition::FieldExtension +
    +
  • + + +
  • +
    + tagged_with? + ElasticGraph::Apollo::SchemaDefinition::FieldExtension +
    +
  • + + +
  • +
    + #target_apollo_federation_version + ElasticGraph::Apollo::SchemaDefinition::APIExtension +
    +
  • + + +
  • +
    + #to_dumpable_hash + ElasticGraph::SchemaDefinition::Indexing::JSONSchemaFieldMetadata +
    +
  • + + +
  • +
    + #to_index_config + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + #to_index_template_config + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + #to_indexing_field_type + ElasticGraph::SchemaDefinition::SchemaElements::EnumType +
    +
  • + + +
  • +
    + #to_json_schema + ElasticGraph::SchemaDefinition::Indexing::FieldType::Enum +
    +
  • + + +
  • +
    + #to_json_schema + ElasticGraph::SchemaDefinition::Indexing::FieldType::Union +
    +
  • + + +
  • +
    + #to_json_schema + ElasticGraph::SchemaDefinition::Indexing::FieldType::Object +
    +
  • + + +
  • +
    + #to_json_schema + ElasticGraph::SchemaDefinition::Indexing::FieldType::Scalar +
    +
  • + + +
  • +
    + #to_mapping + ElasticGraph::SchemaDefinition::Indexing::FieldType::Enum +
    +
  • + + +
  • +
    + #to_mapping + ElasticGraph::SchemaDefinition::Indexing::FieldType::Union +
    +
  • + + +
  • +
    + #to_mapping + ElasticGraph::SchemaDefinition::Indexing::FieldType::Object +
    +
  • + + +
  • +
    + #to_mapping + ElasticGraph::SchemaDefinition::Indexing::FieldType::Scalar +
    +
  • + + +
  • +
    + #to_sdl + ElasticGraph::SchemaDefinition::SchemaElements::Argument +
    +
  • + + +
  • +
    + #to_sdl + ElasticGraph::SchemaDefinition::SchemaElements::Directive +
    +
  • + + +
  • +
    + #to_sdl + ElasticGraph::SchemaDefinition::SchemaElements::EnumType +
    +
  • + + +
  • +
    + #to_sdl + ElasticGraph::SchemaDefinition::SchemaElements::EnumValue +
    +
  • + + +
  • +
    + #to_sdl + ElasticGraph::SchemaDefinition::SchemaElements::UnionType +
    +
  • + + +
  • +
    + #to_sdl + ElasticGraph::SchemaDefinition::SchemaElements::ScalarType +
    +
  • + + +
  • +
    + #to_sdl + ElasticGraph::SchemaDefinition::Mixins::ImplementsInterfaces +
    +
  • + + +
  • +
    + #type + ElasticGraph::SchemaDefinition::SchemaElements::Field +
    +
  • + + +
  • +
    + #type + ElasticGraph::SchemaDefinition::Indexing::JSONSchemaFieldMetadata +
    +
  • + + +
  • +
    + #type_name + ElasticGraph::SchemaDefinition::Indexing::FieldType::Object +
    +
  • + + +
  • +
    + #type_name_overrides + ElasticGraph::Local::RakeTasks +
    +
  • + + +
  • +
    + #union_type + ElasticGraph::SchemaDefinition::API +
    +
  • + + +
  • +
    + #update_runtime_metadata + ElasticGraph::SchemaDefinition::SchemaElements::EnumValue +
    +
  • + + +
  • +
    + #uses_custom_routing? + ElasticGraph::SchemaDefinition::Indexing::Index +
    +
  • + + +
  • +
    + #valid? + ElasticGraph::JSONSchema::Validator +
    +
  • + + +
  • +
    + #validate + ElasticGraph::JSONSchema::Validator +
    +
  • + + +
  • +
    + #validate_with_error_message + ElasticGraph::JSONSchema::Validator +
    +
  • + + +
  • +
    + #validator_for + ElasticGraph::JSONSchema::ValidatorFactory +
    +
  • + + +
  • +
    + #value + ElasticGraph::SchemaDefinition::SchemaElements::EnumType +
    +
  • + + +
  • +
    + #value_type + ElasticGraph::SchemaDefinition::SchemaElements::Argument +
    +
  • + + +
  • +
    + #values + ElasticGraph::SchemaDefinition::SchemaElements::EnumType +
    +
  • + + +
  • +
    + #values_by_name + ElasticGraph::SchemaDefinition::SchemaElements::EnumType +
    +
  • + + +
  • +
    + verify_name! + ElasticGraph::SchemaDefinition::Mixins::VerifiesGraphQLName +
    +
  • + + +
  • +
    + #with_unknown_properties_disallowed + ElasticGraph::JSONSchema::ValidatorFactory +
    +
  • + + + +
+
+ + diff --git a/docs/main/top-level-namespace.html b/docs/main/top-level-namespace.html new file mode 100644 index 00000000..dac33ecf --- /dev/null +++ b/docs/main/top-level-namespace.html @@ -0,0 +1,181 @@ + + + + + + + Top Level Namespace + + — Documentation by YARD 0.9.37 + + + + + + + + + + + + + + + + + + + +
+ + +

Top Level Namespace + + + +

+
+ + + + + + + + + + + +
+ +

Defined Under Namespace

+

+ + + Modules: ElasticGraph + + + + +

+ + +

+ Constant Summary + collapse +

+ +
+ +
HandleAdminRequest = +
+
+

Lambda handler for elasticgraph-admin_lambda.

+ + +
+
+
+ + +
+
+
ElasticGraph::AdminLambda::LambdaFunction.new
+ +
ExecuteGraphQLQuery = +
+
+

Lambda handler for elasticgraph-graphql_lambda.

+ + +
+
+
+ + +
+
+
ElasticGraph::GraphQLLambda::LambdaFunction.new
+ +
AutoscaleIndexer = +
+
+

Lambda handler for elasticgraph-indexer_autoscaler_lambda.

+ + +
+
+
+ + +
+
+
ElasticGraph::IndexerAutoscalerLambda::LambdaFunction.new
+ +
ProcessEventStreamEvent = +
+
+

Lambda handler for elasticgraph-indexer_lambda.

+ + +
+
+
+ + +
+
+
ElasticGraph::IndexerLambda::LambdaFunction.new
+ +
+ + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..5a600ac8 --- /dev/null +++ b/index.html @@ -0,0 +1,143 @@ + + + + + + + ElasticGraph + + + + + + + + + + +
+
+

+ ElasticGraph +

+

+ A general-purpose framework and platform for indexing, searching, + grouping, and aggregating data. +

+ + Documentation + +
+
+ + +
+
+

+ Try ElasticGraph Now +

+

+ Get started by installing ElasticGraph with the following command: +

+
+ + gem install elasticgraph + + +
+
+
+ + +
+
+

+ What People Are Saying +

+
+
+

+ "ElasticGraph has revolutionized the way we manage and analyze our + data." +

+
+ - John Doe, CTO at TechCorp +
+
+
+

+ "A must-have tool for any data-driven organization." +

+
+ - Jane Smith, Data Scientist +
+
+
+

+ "ElasticGraph makes complex data operations simple and efficient." +

+
+ - Gandalf Skywalker, Software Engineer +
+
+
+
+
+ + + + + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/aggregations/aggregated-values/index.html b/query-api/aggregations/aggregated-values/index.html new file mode 100644 index 00000000..78cb7b02 --- /dev/null +++ b/query-api/aggregations/aggregated-values/index.html @@ -0,0 +1,185 @@ + + + + + + + ElasticGraph Query API: Aggregated Values + + + + + + + + + +
+
+
+

ElasticGraph Query API: Aggregated Values

+ +

Aggregated values can be computed from all values of a particular field from all documents backing an aggregation node. +Here’s an example:

+ +
query BluegrassArtistLifetimeSales {
+  artistAggregations(
+    filter: {bio: {description: {matchesQuery: {query: "bluegrass"}}}}
+  ) {
+    nodes {
+      groupedBy {
+        bio { yearFormed }
+      }
+
+      aggregatedValues {
+        lifetimeSales {
+          exactMin
+          exactMax
+
+          exactSum
+          approximateSum
+
+          approximateAvg
+        }
+      }
+    }
+  }
+}
+ +

This example query aggregates the values of the Artist.lifetimeSales field using all 4 of the standard numeric +aggregated values: min, max, avg, and sum. These are qualified with approximate or exact to indicate +the level of precision they offer. The documentation for approximateSum and exactSum provide more detail:

+ +
+
approximateSum
+
The (approximate) sum of the field values within this grouping. + +

Sums of large Int values can result in overflow, where the exact sum cannot +fit in a JsonSafeLong return value. This field, as a double-precision Float, can +represent larger sums, but the value may only be approximate.

+
+
exactSum
+
The exact sum of the field values within this grouping, if it fits in a JsonSafeLong. + +

Sums of large Int values can result in overflow, where the exact sum cannot +fit in a JsonSafeLong. In that case, null will be returned, and approximateSum +can be used to get an approximate value.

+
+
+ +

Besides these standard numeric aggregated values, ElasticGraph offers one more:

+ +
query SkaArtistHomeCountries {
+  artistAggregations(
+    filter: {bio: {description: {matchesQuery: {query: "ska"}}}}
+  ) {
+    nodes {
+      groupedBy {
+        bio { yearFormed }
+      }
+
+      aggregatedValues {
+        bio {
+          homeCountry {
+            approximateDistinctValueCount
+          }
+        }
+      }
+    }
+  }
+}
+ +

The approximateDistinctValueCount field uses the HyperLogLog++ algorithm +to provide an approximate count of distinct values for the field. In this case, it can give us an idea of how many countries ska +bands were formed in, in each year.

+ +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/aggregations/counts/index.html b/query-api/aggregations/counts/index.html new file mode 100644 index 00000000..70b87221 --- /dev/null +++ b/query-api/aggregations/counts/index.html @@ -0,0 +1,128 @@ + + + + + + + ElasticGraph Query API: Aggregation Counts + + + + + + + + + +
+
+
+

ElasticGraph Query API: Aggregation Counts

+ +

The aggregations API allows you to count documents within a grouping:

+ +
query ArtistCountsByCountry {
+  artistAggregations {
+    nodes {
+      groupedBy {
+        bio { homeCountry }
+      }
+
+      count
+    }
+  }
+}
+ +

This query, for example, returns a grouping for each country, and provides a count of how many artists +call each country home.

+ +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/aggregations/grouping/index.html b/query-api/aggregations/grouping/index.html new file mode 100644 index 00000000..b355afd0 --- /dev/null +++ b/query-api/aggregations/grouping/index.html @@ -0,0 +1,322 @@ + + + + + + + ElasticGraph Query API: Aggregation Grouping + + + + + + + + + +
+
+
+

ElasticGraph Query API: Aggregation Grouping

+ +

When aggregating documents, the groupings are defined by groupedBy. Here’s an example:

+ +
query ArtistCountsByYearFormedAndHomeCountry {
+  artistAggregations {
+    nodes {
+      groupedBy {
+        bio {
+          yearFormed
+          homeCountry
+        }
+      }
+
+      count
+    }
+  }
+}
+ +

In this case, we’re grouping by multiple fields; a grouping will be returned for each +combination of Artist.bio.yearFormed and Artist.bio.homeCountry found in the data.

+ +

Date Grouping

+ +

In the example above, the grouping was performed on the raw values of the groupedBy fields. +However, for Date fields it’s generally more useful to group by truncated values. +Here’s an example:

+ +
query AlbumSalesByReleaseYear {
+  artistAggregations {
+    nodes {
+      subAggregations {
+        albums {
+          nodes {
+            groupedBy {
+              releasedOn {
+                asDate(truncationUnit: YEAR)
+              }
+            }
+
+            aggregatedValues {
+              soldUnits {
+                exactSum
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+ +

In this case, we’re truncating the Album.releaseOn dates to the year to give us one grouping per +year rather than one grouping per distinct date. The truncationUnit argument supports DAY, MONTH, +QUARTER, WEEK and YEAR values. In addition, an offset argument is supported, which can be used +to shift what grouping a Date falls into. This is particularly useful when using WEEK:

+ +
query AlbumSalesByReleaseWeek {
+  artistAggregations {
+    nodes {
+      subAggregations {
+        albums {
+          nodes {
+            groupedBy {
+              releasedOn {
+                asDate(truncationUnit: WEEK, offset: {amount: -1, unit: DAY})
+              }
+            }
+
+            aggregatedValues {
+              soldUnits {
+                exactSum
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+ +

With no offset, grouped weeks run Monday to Sunday, but we can shift it using offset. In this case, the weeks have been +shifted to run Sunday to Saturday.

+ +

Finally, we can also group Date fields by what day of week they fall into using asDayOfWeek instead of asDate:

+ +
query AlbumSalesByReleaseDayOfWeek {
+  artistAggregations {
+    nodes {
+      subAggregations {
+        albums {
+          nodes {
+            groupedBy {
+              releasedOn {
+                asDayOfWeek
+              }
+            }
+
+            aggregatedValues {
+              soldUnits {
+                exactSum
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+ +

DateTime Grouping

+ +

DateTime fields offer a similar grouping API. asDate and asDayOfWeek work the same, but they accept an optional timeZone +argument (default is “UTC”):

+ +
query TourAttendanceByYear {
+  artistAggregations {
+    nodes {
+      subAggregations {
+        tours {
+          nodes {
+            subAggregations {
+              shows {
+                nodes {
+                  groupedBy {
+                    startedAt {
+                      asDate(
+                        truncationUnit: YEAR
+                        timeZone: "America/Los_Angeles"
+                      )
+                    }
+                  }
+
+                  aggregatedValues {
+                    attendance {
+                      exactSum
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+ +

Sub-day granualarities (HOUR, MINUTE, SECOND) are supported when you use asDateTime instead of asDate:

+ +
query TourAttendanceByHour {
+  artistAggregations {
+    nodes {
+      subAggregations {
+        tours {
+          nodes {
+            subAggregations {
+              shows {
+                nodes {
+                  groupedBy {
+                    startedAt {
+                      asDateTime(truncationUnit: HOUR)
+                    }
+                  }
+
+                  aggregatedValues {
+                    attendance {
+                      exactSum
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+ +

Finally, you can group by the time of day (while ignoring the date) by using asTimeOfDay:

+ +
query TourAttendanceByHourOfDay {
+  artistAggregations {
+    nodes {
+      subAggregations {
+        tours {
+          nodes {
+            subAggregations {
+              shows {
+                nodes {
+                  groupedBy {
+                    startedAt {
+                      asTimeOfDay(truncationUnit: HOUR)
+                    }
+                  }
+
+                  aggregatedValues {
+                    attendance {
+                      exactSum
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+ + +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/aggregations/index.html b/query-api/aggregations/index.html new file mode 100644 index 00000000..be3a5466 --- /dev/null +++ b/query-api/aggregations/index.html @@ -0,0 +1,202 @@ + + + + + + + ElasticGraph Query API: Aggregations + + + + + + + + + +
+
+
+

ElasticGraph Query API: Aggregations

+ +

ElasticGraph offers a powerful aggregations API. Each indexed type gets a corresponding *Aggregations field. +Here’s a complete example:

+ +
query BluegrassArtistAggregations($cursor: Cursor) {
+  artistAggregations(
+    first: 10
+    after: $cursor
+    filter: {bio: {description: {matchesQuery: {query: "bluegrass"}}}}
+  ) {
+    pageInfo {
+      hasNextPage
+      endCursor
+    }
+
+    nodes {
+      groupedBy {
+        bio { yearFormed }
+      }
+
+      aggregatedValues {
+        lifetimeSales {
+          approximateAvg
+          exactMin
+          exactMax
+        }
+      }
+
+      count
+
+      subAggregations {
+        albums(
+          first: 3
+          filter: {tracks: {count: {gt: 10}}}
+        ) {
+          nodes {
+            countDetail { approximateValue }
+          }
+        }
+      }
+    }
+  }
+}
+ +

Aggregation fields support filtering and pagination +but do not support client-specified sorting1. Under an aggregations field, each node +represents a grouping of documents. When groupedBy fields have been requested, +each node represents the grouping of documents that have the groupedBy values. When no groupedBy fields have been requested, +a single node will be returned containing a grouping for all documents matched by the filter.

+ +

Aggregation nodes in turn offer 4 different aggregation features.

+ +
+

Subpages

+ +
+ +
+
    +
  1. +

    Aggregation sorting is implicitly controlled by the groupings–the + nodes will sort ascending by each of the grouping fields. 

    +
  2. +
+
+ +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/aggregations/sub-aggregations/index.html b/query-api/aggregations/sub-aggregations/index.html new file mode 100644 index 00000000..803cce83 --- /dev/null +++ b/query-api/aggregations/sub-aggregations/index.html @@ -0,0 +1,289 @@ + + + + + + + ElasticGraph Query API: Sub-Aggregations + + + + + + + + + +
+
+
+

ElasticGraph Query API: Sub-Aggregations

+ +

The example schema used throughout this guide has a number of lists-of-object fields nested +within the overall Artist type:

+ +
    +
  • Artist.albums +
      +
    • Artist.albums[].tracks
    • +
    +
  • +
  • Artist.tours +
      +
    • Artist.tours[].shows
    • +
    +
  • +
+ +

ElasticGraph supports aggregations on these nested fields via subAggregations. This can be used +to aggregation directly on the data of one of these fields. For example, this query returns the +total sales for all albums of all artists:

+ +
query TotalAlbumSales {
+  artistAggregations {
+    nodes {
+      subAggregations {
+        albums {
+          nodes {
+            aggregatedValues {
+              soldUnits {
+                exactSum
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+ +

Sub-aggregations can also be performed under the groupings of an outer aggregations. For example, +this query returns the total album sales grouped by the home country of the artist:

+ +
query TotalAlbumSalesByArtistHomeCountry {
+  artistAggregations {
+    nodes {
+      groupedBy {
+        bio {
+          homeCountry
+        }
+      }
+
+      subAggregations {
+        albums {
+          nodes {
+            aggregatedValues {
+              soldUnits {
+                exactSum
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+ +

Sub-aggregation nodes offer the standard set of aggregation operations:

+ + + +

Filtering Sub-Aggregations

+ +

The data included in a sub-aggregation can be filtered. For example, this query gets the total +sales of all albums released in the 21st century:

+ +
query TwentyFirstCenturyAlbumSales {
+  artistAggregations {
+    nodes {
+      subAggregations {
+        albums(filter: {
+          releasedOn: {gte: "2000-01-01"}
+        }) {
+          nodes {
+            aggregatedValues {
+              soldUnits {
+                exactSum
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+ +

Sub-Aggregation Limitations

+ +

Sub-aggregation pagination support is limited. You can use first to request how many +nodes are returned, but there is no pageInfo and you cannot request the next page of data:

+ +
query AlbumSalesByReleaseMonth {
+  artistAggregations {
+    nodes {
+      subAggregations {
+        albums(first: 100) {
+          nodes {
+            groupedBy {
+              releasedOn {
+                asDate(truncationUnit: MONTH)
+              }
+            }
+
+            aggregatedValues {
+              soldUnits {
+                exactSum
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+ +

Sub-aggregation counts are approximate. Instead of count, ElasticGraph offers countDetail +with multiple subfields:

+ +
query AlbumCount {
+  artistAggregations {
+    nodes {
+      subAggregations {
+        albums {
+          nodes {
+            countDetail {
+              approximateValue
+              exactValue
+              upperBound
+            }
+          }
+        }
+      }
+    }
+  }
+}
+ +
+
approximateValue
+
The (approximate) count of documents in this aggregation bucket. + +

When documents in an aggregation bucket are sourced from multiple shards, the count may be only +approximate. The upperBound indicates the maximum value of the true count, but usually +the true count is much closer to this approximate value (which also provides a lower bound on the +true count).

+ +

When this approximation is known to be exact, the same value will be available from exactValue +and upperBound.

+
+
exactValue
+
The exact count of documents in this aggregation bucket, if an exact value can be determined. + +

When documents in an aggregation bucket are sourced from multiple shards, it may not be possible to +efficiently determine an exact value. When no exact value can be determined, this field will be null. +The approximateValue field–which will never be null–can be used to get an approximation +for the count.

+
+
upperBound
+
An upper bound on how large the true count of documents in this aggregation bucket could be. + +

When documents in an aggregation bucket are sourced from multiple shards, it may not be possible to +efficiently determine an exact value. The approximateValue field provides an approximation, +and this field puts an upper bound on the true count.

+
+
+ +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/filtering/available-predicates/index.html b/query-api/filtering/available-predicates/index.html new file mode 100644 index 00000000..eec361bb --- /dev/null +++ b/query-api/filtering/available-predicates/index.html @@ -0,0 +1,203 @@ + + + + + + + ElasticGraph Query API: Available Filter Predicates + + + + + + + + + +
+
+
+

ElasticGraph Query API: Available Filter Predicates

+ +

ElasticGraph offers a variety of filtering predicates:

+ +
+
allOf
+
Matches records where all of the provided sub-filters evaluate to true. +This works just like an AND operator in SQL. + +

Note: multiple filters are automatically ANDed together. This is only needed when you have multiple +filters that can’t be provided on a single filter input because of collisions between key names. +For example, if you want to provide multiple anySatisfy: ... filters, you could do allOf: [{anySatisfy: ...}, {anySatisfy: ...}].

+ +

Will be ignored when null or an empty list is passed.

+
+
anyOf
+
Matches records where any of the provided sub-filters evaluate to true. +This works just like an OR operator in SQL. + +

Will be ignored when null is passed. When an empty list is passed, will +cause this part of the filter to match no documents.

+
+
anySatisfy
+
Matches records where any of the list elements match the provided sub-filter. + +

Will be ignored when null or an empty object is passed.

+
+
count
+
Used to filter on the number of non-null elements in this list field. + +

Will be ignored when null or an empty object is passed.

+
+
equalToAnyOf
+
Matches records where the field value is equal to any of the provided values. +This works just like an IN operator in SQL. + +

Will be ignored when null is passed. +When an empty list is passed, will cause this part of the filter to match no documents. +When null is passed in the list, will match records where the field value is null.

+
+
gt
+
Matches records where the field value is greater than (>) the provided value. + +

Will be ignored when null is passed.

+
+
gte
+
Matches records where the field value is greater than or equal to (>=) the provided value. + +

Will be ignored when null is passed.

+
+
lt
+
Matches records where the field value is less than (<) the provided value. + +

Will be ignored when null is passed.

+
+
lte
+
Matches records where the field value is less than or equal to (<=) the provided value. + +

Will be ignored when null is passed.

+
+
matchesPhrase
+
Matches records where the field value has a phrase matching the provided phrase using +full text search. This is stricter than matchesQuery: all terms must match +and be in the same order as the provided phrase. + +

Will be ignored when null is passed.

+
+
matchesQuery
+
Matches records where the field value matches the provided query using full text search. +This is more lenient than matchesPhrase: the order of terms is ignored, and, by default, +only one search term is required to be in the field value. + +

Will be ignored when null is passed.

+
+
near
+
Matches records where the field’s geographic location is within a specified distance +from the location identified by latitude and longitude. + +

Will be ignored when null or an empty object is passed.

+
+
not
+
Matches records where the provided sub-filter evaluates to false. +This works just like a NOT operator in SQL. + +

Will be ignored when null or an empty object is passed.

+
+
timeOfDay
+
Matches records based on the time-of-day of the DateTime values. + +

Will be ignored when null of an empty object is passed.

+
+
+ + +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/filtering/comparison/index.html b/query-api/filtering/comparison/index.html new file mode 100644 index 00000000..142968d0 --- /dev/null +++ b/query-api/filtering/comparison/index.html @@ -0,0 +1,153 @@ + + + + + + + ElasticGraph Query API: Comparison Filtering + + + + + + + + + +
+
+
+

ElasticGraph Query API: Comparison Filtering

+ +

ElasticGraph offers a standard set of comparison filter predicates:

+ +
+
gt
+
Matches records where the field value is greater than (>) the provided value. + +

Will be ignored when null is passed.

+
+
gte
+
Matches records where the field value is greater than or equal to (>=) the provided value. + +

Will be ignored when null is passed.

+
+
lt
+
Matches records where the field value is less than (<) the provided value. + +

Will be ignored when null is passed.

+
+
lte
+
Matches records where the field value is less than or equal to (<=) the provided value. + +

Will be ignored when null is passed.

+
+
+ +
query FindArtistsFormedIn90s {
+  artists(filter: {
+    bio: {yearFormed: {gte: 1990, lt: 2000}}
+  }) {
+    nodes {
+      name
+      bio {
+        yearFormed
+      }
+      albums {
+        name
+      }
+    }
+  }
+}
+ + +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/filtering/conjunctions/index.html b/query-api/filtering/conjunctions/index.html new file mode 100644 index 00000000..9969646f --- /dev/null +++ b/query-api/filtering/conjunctions/index.html @@ -0,0 +1,292 @@ + + + + + + + ElasticGraph Query API: Filter Conjunctions + + + + + + + + + +
+
+
+

ElasticGraph Query API: Filter Conjunctions

+ +

ElasticGraph supports two conjunction predicates:

+ +
+
allOf
+
Matches records where all of the provided sub-filters evaluate to true. +This works just like an AND operator in SQL. + +

Note: multiple filters are automatically ANDed together. This is only needed when you have multiple +filters that can’t be provided on a single filter input because of collisions between key names. +For example, if you want to provide multiple anySatisfy: ... filters, you could do allOf: [{anySatisfy: ...}, {anySatisfy: ...}].

+ +

Will be ignored when null or an empty list is passed.

+
+
anyOf
+
Matches records where any of the provided sub-filters evaluate to true. +This works just like an OR operator in SQL. + +

Will be ignored when null is passed. When an empty list is passed, will +cause this part of the filter to match no documents.

+
+
+ +

By default, multiple filters are ANDed together. For example, this query finds artists +formed after the year 2000 with “accordion” in their bio:

+ +
query FindRecentAccordionArtists {
+  artists(filter: {
+    bio: {
+      yearFormed: {gt: 2000}
+      description: {matchesQuery: {query: "accordion"}}
+    }
+  }) {
+    nodes {
+      name
+      bio {
+        yearFormed
+        description
+      }
+    }
+  }
+}
+ +

ORing subfilters with anyOf

+ +

To instead find artists formed after the year 2000 OR with “accordion” in their bio, you +can wrap the sub-filters in an anyOf:

+ +
query FindRecentOrAccordionArtists {
+  artists(filter: {
+    bio: {
+      anyOf: [
+        {yearFormed: {gt: 2000}}
+        {description: {matchesQuery: {query: "accordion"}}}
+      ]
+    }
+  }) {
+    nodes {
+      name
+      bio {
+        yearFormed
+        description
+      }
+    }
+  }
+}
+ +

anyOf is available at all levels of the filtering structure so that you can OR +sub-filters anywhere you like.

+ +

ANDing subfilters with allOf

+ +

allOf is rarely needed since multiple filters are ANDed together by default. But it can +come in handy when you’d otherwise have a duplicate key collision on a filter input. One +case where this comes in handy is when using anySatisfy to filter on a +list. Consider this query:

+ +
query ArtistsWithPlatinum90sAlbum {
+  artists(filter: {
+    albums: {
+      anySatisfy: {
+        soldUnits: {gte: 1000000}
+        releasedOn: {gte: "1990-01-01", lt: "2000-01-01"}
+      }
+    }
+  }) {
+    nodes {
+      name
+      albums {
+        name
+        releasedOn
+        soldUnits
+      }
+    }
+  }
+}
+ +

This query finds artists who released an album in the 90’s that sold more than million copies. +If you wanted to broaden the query to find artists with at least one 90’s album and at least one +platinum-selling album–without requiring it to be the same album–you could do this:

+ +
query ArtistsWith90sAlbumAndPlatinumAlbum {
+  artists(filter: {
+    albums: {
+      allOf: [
+        {anySatisfy: {soldUnits: {gte: 1000000}}}
+        {anySatisfy: {releasedOn: {gte: "1990-01-01", lt: "2000-01-01"}}}
+      ]
+    }
+  }) {
+    nodes {
+      name
+      albums {
+        name
+        releasedOn
+        soldUnits
+      }
+    }
+  }
+}
+ +

GraphQL input objects don’t allow duplicate keys, so +albums: {anySatisfy: {...}, anySatisfy: {...}} isn’t supported, but allOf +enables this use case.

+ +

Warning: Always Pass a List

+ +

When using allOf or anyOf, be sure to pass the sub-filters as a list. If you instead +pass them as an object, it won’t work as expected. Consider this query:

+ +
query AnyOfGotcha {
+  artists(filter: {
+    bio: {
+      anyOf: {
+        yearFormed: {gt: 2000}
+        description: {matchesQuery: {query: "accordion"}}
+      }
+    }
+  }) {
+    nodes {
+      name
+      bio {
+        yearFormed
+        description
+      }
+    }
+  }
+}
+ +

While this query will return results, it doesn’t behave as it appears. The GraphQL +spec mandates that list inputs coerce non-list values into a list of one +value. In this case, +that means that the anyOf expression is coerced into this:

+ +
query AnyOfGotcha {
+  artists(filter: {
+    bio: {
+      anyOf: [{
+        yearFormed: {gt: 2000}
+        description: {matchesQuery: {query: "accordion"}}
+      }]
+    }
+  }) {
+    # ...
+  }
+}
+ +

Using anyOf with only a single sub-expression, as we have here, doesn’t do anything; +the query is equivalent to:

+ +
query AnyOfGotcha {
+  artists(filter: {
+    bio: {
+      yearFormed: {gt: 2000}
+      description: {matchesQuery: {query: "accordion"}}
+    }
+  }) {
+    # ...
+  }
+}
+ + +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/filtering/date-time/index.html b/query-api/filtering/date-time/index.html new file mode 100644 index 00000000..5ea49202 --- /dev/null +++ b/query-api/filtering/date-time/index.html @@ -0,0 +1,167 @@ + + + + + + + ElasticGraph Query API: DateTime Filtering + + + + + + + + + +
+
+
+

ElasticGraph Query API: DateTime Filtering

+ +

ElasticGraph supports three different date/time types:

+ +
+
Date
+
A date, represented as an ISO 8601 date string. +Example: "2024-10-15".
+
DateTime
+
A timestamp, represented as an ISO 8601 time string. +Example: "2024-10-15T07:23:15Z".
+
LocalTime
+
A local time such as "23:59:33" or "07:20:47.454" without a time zone or offset, +formatted based on the partial-time portion of RFC3339.
+
+ +

All three support the standard set of equality and +comparison predicates. In addition, DateTime fields +support one more filtering operator:

+ +
+
timeOfDay
+
Matches records based on the time-of-day of the DateTime values. + +

Will be ignored when null of an empty object is passed.

+
+
+ +

For example, you could use it to find shows that started between noon and 3 pm on any date:

+ +
query FindEarlyAfternoonShows {
+  artists(filter: {
+    tours: {anySatisfy: {shows: {anySatisfy: {
+      startedAt: {
+        timeOfDay: {
+          timeZone: "America/Los_Angeles"
+          gte: "12:00:00"
+          lt: "15:00:00"
+        }
+      }
+    }}}}
+  }) {
+    nodes {
+      name
+
+      tours {
+        shows {
+          venue {
+            id
+          }
+          startedAt
+        }
+      }
+    }
+  }
+}
+ + +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/filtering/equality/index.html b/query-api/filtering/equality/index.html new file mode 100644 index 00000000..08d3a969 --- /dev/null +++ b/query-api/filtering/equality/index.html @@ -0,0 +1,155 @@ + + + + + + + ElasticGraph Query API: Equality Filtering + + + + + + + + + +
+
+
+

ElasticGraph Query API: Equality Filtering

+ +

The most commonly used predicate supports equality filtering:

+ +
+
equalToAnyOf
+
Matches records where the field value is equal to any of the provided values. +This works just like an IN operator in SQL. + +

Will be ignored when null is passed. +When an empty list is passed, will cause this part of the filter to match no documents. +When null is passed in the list, will match records where the field value is null.

+
+
+ +

Here’s a basic example:

+ +
query EqualityFilter {
+  artists(filter: {
+    name: {equalToAnyOf: ["U2", "Radiohead"]}
+  }) {
+    nodes {
+      name
+      bio {
+        yearFormed
+      }
+    }
+  }
+}
+ +

Unlike the SQL IN operator, you can find records with null values if you put null in the list:

+ +
query EqualityFilterNull {
+  artists(filter: {
+    name: {equalToAnyOf: [null]}
+  }) {
+    nodes {
+      name
+      bio {
+        yearFormed
+      }
+    }
+  }
+}
+ + +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/filtering/full-text-search/index.html b/query-api/filtering/full-text-search/index.html new file mode 100644 index 00000000..1f98cb0b --- /dev/null +++ b/query-api/filtering/full-text-search/index.html @@ -0,0 +1,213 @@ + + + + + + + ElasticGraph Query API: Full Text Search + + + + + + + + + +
+
+
+

ElasticGraph Query API: Full Text Search

+ +

ElasticGraph supports two full-text search filtering predicates:

+ +
+
matchesPhrase
+
Matches records where the field value has a phrase matching the provided phrase using +full text search. This is stricter than matchesQuery: all terms must match +and be in the same order as the provided phrase. + +

Will be ignored when null is passed.

+
+
matchesQuery
+
Matches records where the field value matches the provided query using full text search. +This is more lenient than matchesPhrase: the order of terms is ignored, and, by default, +only one search term is required to be in the field value. + +

Will be ignored when null is passed.

+
+
+ +

Matches Query

+ +

matchesQuery is the more lenient of the two predicates. It’s designed to match broadly. Here’s an example:

+ +
query AccordionOrViolinSearch {
+  artists(filter: {
+    bio: {
+      description: {
+        matchesQuery: {
+          query: "accordion violin"
+        }
+      }
+    }
+  }) {
+    nodes {
+      name
+      bio {
+        description
+      }
+    }
+  }
+}
+ +

This query will match artists with bios like:

+ +
+

Renowned for his mesmerizing performances, Luca “The Breeze” Fontana captivates audiences with his accordion, +weaving intricate melodies that dance between the notes of traditional folk and modern jazz.

+
+ +
+

Sylvia Varela’s avant-garde violin playing defies tradition, blending haunting dissonance with unexpected rhythms.

+
+ +

Notably, the description needs accordion OR violin, but not both. In addition, it would match an artist bio that +mentioned “viola” since it supports fuzzy matching by default and “viola” is only 2 edits away from “violin”. Arguments +are supported to control both aspects to make matching stricter:

+ +
query AccordionAndViolinStrictSearch {
+  artists(filter: {
+    bio: {
+      description:{
+        matchesQuery: {
+          query: "accordion violin"
+          requireAllTerms: true
+          allowedEditsPerTerm: NONE
+        }
+      }
+    }
+  }) {
+    nodes {
+      name
+      bio {
+        description
+      }
+    }
+  }
+}
+ +

Matches Phrase

+ +

matchesPhrase is even stricter: it requires all terms in the provided order (matchesQuery doesn’t care about order). It’s particularly useful when you want to search on a particular multi-word expression:

+ +
query PhraseSearch {
+  artists(filter: {
+    bio: {
+      description:{
+        matchesPhrase: {
+          phrase: "Ed Sullivan Show"
+        }
+      }
+    }
+  }) {
+    nodes {
+      name
+      bio {
+        description
+      }
+    }
+  }
+}
+ + +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/filtering/geographic/index.html b/query-api/filtering/geographic/index.html new file mode 100644 index 00000000..c8eaed95 --- /dev/null +++ b/query-api/filtering/geographic/index.html @@ -0,0 +1,139 @@ + + + + + + + ElasticGraph Query API: Geographic Filtering + + + + + + + + + +
+
+
+

ElasticGraph Query API: Geographic Filtering

+ +

The GeoLocation type supports a special predicate:

+ +
+
near
+
Matches records where the field’s geographic location is within a specified distance +from the location identified by latitude and longitude. + +

Will be ignored when null or an empty object is passed.

+
+
+ +
query FindSeattleVenues {
+  venues(filter: {
+    location: {near: {
+      latitude: 47.621
+      longitude: -122.349
+      maxDistance: 10
+      unit: MILE
+    }}
+  }) {
+    nodes {
+      name
+      capacity
+    }
+  }
+}
+ + +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/filtering/index.html b/query-api/filtering/index.html new file mode 100644 index 00000000..d889dcf8 --- /dev/null +++ b/query-api/filtering/index.html @@ -0,0 +1,266 @@ + + + + + + + ElasticGraph Query API: Filtering + + + + + + + + + +
+
+
+

ElasticGraph Query API: Filtering

+ +

Use filter: on a root query field to narrow down the returned results:

+ +
query FindArtist {
+  byName: artists(filter: {
+    name: {equalToAnyOf: ["U2"]}
+  }) {
+    nodes {
+      name
+      bio {
+        yearFormed
+      }
+    }
+  }
+
+  byBioYearFounded: artists(filter: {
+    bio: {yearFormed: {gt: 2000}}
+  }) {
+    nodes {
+      name
+      bio {
+        yearFormed
+      }
+    }
+  }
+}
+ +

As shown here, filters have two basic parts:

+ +
    +
  • A field path: this specifies which field you want to filter on. When dealing with a nested field (e.g. bio.yearFormed), +you’ll need to provide a nested object matching the field structure.
  • +
  • A filtering predicate: this specifies a filtering operator to apply at the field path.
  • +
+ +

Ignored Filters

+ +

Filters with a value of null or empty object ({}) are ignored. The filters in this query are all ignored:

+ +
query IgnoredFilters {
+  artists(filter: {
+    name: {equalToAnyOf: null}
+    bio: {yearFormed: {}}
+  }) {
+    nodes {
+      name
+      bio {
+        yearFormed
+      }
+    }
+  }
+}
+ +

This particularly comes in handy when using query variables. +It allows a query to flexibly support a wide array of filters without requiring them to all be used for an +individual request.

+ +
query FindArtists(
+  $names: [String!] = null
+  $yearFormed_gt: Int = null
+  $albumNames: [String!] = null
+) {
+  artists(filter: {
+    name: {equalToAnyOf: $names}
+    bio: {yearFormed: {gt: $yearFormed_gt}}
+    albums: {anySatisfy: {name: {equalToAnyOf: $albumNames}}}
+  }) {
+    nodes {
+      name
+      bio {
+        yearFormed
+      }
+      albums {
+        name
+      }
+    }
+  }
+}
+ + + + +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/filtering/list/index.html b/query-api/filtering/list/index.html new file mode 100644 index 00000000..22b7776c --- /dev/null +++ b/query-api/filtering/list/index.html @@ -0,0 +1,175 @@ + + + + + + + ElasticGraph Query API: List Filtering + + + + + + + + + +
+
+
+

ElasticGraph Query API: List Filtering

+ +

ElasticGraph supports a couple predicates for filtering on list fields:

+ +
+
anySatisfy
+
Matches records where any of the list elements match the provided sub-filter. + +

Will be ignored when null or an empty object is passed.

+
+
count
+
Used to filter on the number of non-null elements in this list field. + +

Will be ignored when null or an empty object is passed.

+
+
+ +

Filtering on list elements with anySatisfy

+ +

When filtering on a list field, use anySatisfy to find records with matching list elements. +This query, for example, will find artists that released a platinum-selling album in the 1990s:

+ +
query ArtistsWithPlatinum90sAlbum {
+  artists(filter: {
+    albums: {
+      anySatisfy: {
+        soldUnits: {gte: 1000000}
+        releasedOn: {gte: "1990-01-01", lt: "2000-01-01"}
+      }
+    }
+  }) {
+    nodes {
+      name
+      albums {
+        name
+        releasedOn
+        soldUnits
+      }
+    }
+  }
+}
+ +

One thing to bear in mind: this query is selecting which artists to return, +not which albums to return. You might expect that the returned nodes.albums would +all be platinum-selling 90s albums, but that’s not how the filtering API works. Only artists +that had a platinum-selling 90s album will be returned, and for each returned artists, all +their albums will be returned–even ones that sold poorly or were released outside the 1990s.

+ +

Filtering on the list size with count

+ +

If you’d rather filter on the size of a list, use count:

+ +
query FindProlificArtists {
+  artists(filter: {
+    albums: {count: {gte: 20}}
+  }) {
+    nodes {
+      name
+      albums {
+        name
+      }
+    }
+  }
+}
+ + +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/filtering/negation/index.html b/query-api/filtering/negation/index.html new file mode 100644 index 00000000..fd2a3fa7 --- /dev/null +++ b/query-api/filtering/negation/index.html @@ -0,0 +1,145 @@ + + + + + + + ElasticGraph Query API: Filter Negation + + + + + + + + + +
+
+
+

ElasticGraph Query API: Filter Negation

+ +

ElasticGraph supports a negation predicate:

+ +
+
not
+
Matches records where the provided sub-filter evaluates to false. +This works just like a NOT operator in SQL. + +

Will be ignored when null or an empty object is passed.

+
+
+ +

One of the more common use cases is to filter to non-null values:

+ +
query FindArtistsWithBios {
+  artists(filter: {
+    bio: {description: {not: {equalToAnyOf: [null]}}}
+  }) {
+    nodes {
+      name
+      bio {
+        description
+      }
+    }
+  }
+}
+ +

not is available at any level of a filter. All of these are equivalent:

+ +
    +
  • bio: {description: {not: {equalToAnyOf: [null]}}}
  • +
  • bio: {not: {description: {equalToAnyOf: [null]}}}
  • +
  • not: {bio: {description: {equalToAnyOf: [null]}}}
  • +
+ +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/index.html b/query-api/index.html new file mode 100644 index 00000000..cfcad63c --- /dev/null +++ b/query-api/index.html @@ -0,0 +1,193 @@ + + + + + + + ElasticGraph Query API + + + + + + + + + +
+
+
+

ElasticGraph Query API

+ +

ElasticGraph provides an extremely flexible GraphQL query API. As with every GraphQL API, you request the fields you want:

+ +
query ListArtistAlbums {
+  artists {
+    nodes {
+      name
+      albums {
+        name
+        releasedOn
+
+        tracks {
+          name
+        }
+      }
+    }
+  }
+}
+ +

If you’re just getting started with GraphQL, we recommend you review the graphql.org learning materials.

+ +

ElasticGraph offers a number of query features that go far beyond a traditional GraphQL +API. Each of these features is implemented directly by the ElasticGraph framework, ensuring +consistent, predictable behavior across your entire schema.

+ +
+

Subpages

+ +
+ + +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/pagination/index.html b/query-api/pagination/index.html new file mode 100644 index 00000000..21a2cc96 --- /dev/null +++ b/query-api/pagination/index.html @@ -0,0 +1,158 @@ + + + + + + + ElasticGraph Query API: Pagination + + + + + + + + + +
+
+
+

ElasticGraph Query API: Pagination

+ +

To provide pagination, ElasticGraph implements the Relay GraphQL Cursor Connections +Specification. Here’s an example query showing +pagination in action:

+ +
query PaginationExample($cursor: Cursor) {
+  artists(first: 10, after: $cursor) {
+    pageInfo {
+      hasNextPage
+      endCursor
+    }
+    edges {
+      node {
+        name
+        albums {
+          name
+        }
+      }
+    }
+  }
+}
+ +

In addition, ElasticGraph offers some additional features beyond the Relay spec.

+ +

Total Edge Count

+ +

As an extension to the Relay spec, ElasticGraph offers a totalEdgeCount field alongside edges and pageInfo. +It can be used to get a total count of matching records:

+ +
query Count21stCenturyArtists {
+  artists(filter: {
+    bio: {yearFormed: {gte: 2000}}
+  }) {
+    totalEdgeCount
+  }
+}
+ +

Note: totalEdgeCount is not available under an aggregations field.

+ +

Nodes

+ +

As an alternative to edges.node, ElasticGraph offers nodes. This is recommended over edges except when you need +a per-node cursor (which is available under edges) since it removes an extra layer of nesting, providing a simpler +response structure:

+ +
query PaginationNodes($cursor: Cursor) {
+  artists(first: 10, after: $cursor) {
+    pageInfo {
+      hasNextPage
+      endCursor
+    }
+    nodes {
+      name
+      albums {
+        name
+      }
+    }
+  }
+}
+ + +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + + diff --git a/query-api/sorting/index.html b/query-api/sorting/index.html new file mode 100644 index 00000000..d238fd11 --- /dev/null +++ b/query-api/sorting/index.html @@ -0,0 +1,113 @@ + + + + + + + ElasticGraph Query API: Sorting + + + + + + + + + +
+
+
+

ElasticGraph Query API: Sorting

+ +

Use orderBy: on a root query field to control how the results are sorted:

+ +
query ListArtists {
+  artists(orderBy: [name_ASC, bio_yearFormed_DESC]) {
+    nodes {
+      name
+      albums {
+        name
+      }
+    }
+  }
+}
+ +

This query, for example, would sort by name (ascending), with bio.yearFormed (descending) as a tie breaker.

+ +
+
+
+ + +
+
+
+

+ ElasticGraph +

+

+ ElasticGraph is an open-source framework for indexing, searching, + grouping, and aggregating data. Join our community and contribute on + GitHub. +

+
+
+
+ + + +