elasticgraph 0.19.0.0 → 0.19.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -0
- data/exe/elasticgraph +11 -0
- data/lib/elastic_graph/cli.rb +106 -0
- data/lib/elastic_graph/project_template/.gitignore +5 -0
- data/lib/elastic_graph/project_template/.standard.yml.tt +8 -0
- data/lib/elastic_graph/project_template/Gemfile.tt +17 -0
- data/lib/elastic_graph/project_template/README.md.tt +176 -0
- data/lib/elastic_graph/project_template/Rakefile.tt +64 -0
- data/lib/elastic_graph/project_template/config/queries/example_client/FindArtist.graphql +24 -0
- data/lib/elastic_graph/project_template/config/queries/example_client/ListArtistAlbums.graphql +16 -0
- data/lib/elastic_graph/project_template/config/schema/artists.rb.tt +65 -0
- data/lib/elastic_graph/project_template/config/schema.rb.tt +21 -0
- data/lib/elastic_graph/project_template/config/settings/local.yaml.tt +36 -0
- data/lib/elastic_graph/project_template/lib/app_name/factories.rb +107 -0
- data/lib/elastic_graph/project_template/lib/app_name/fake_data_batch_generator.rb.tt +14 -0
- data/lib/elastic_graph/project_template/lib/app_name/shared_factories.rb +29 -0
- data/lib/elastic_graph/project_template/spec/project_spec.rb.tt +19 -0
- metadata +35 -100
- data/elasticgraph.gemspec +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2bc0f43e12d65d88384972b991179c77c5ec7856c86c85f151138e0af2d99f2f
|
4
|
+
data.tar.gz: f12ed7e628eba142a6299f5878a97d8d80de3068fbff13606fe6ffbc7e181acd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 276bb3d1e4e9aa8180c01031468d60115ec05567bfbc02d39fbd65e8777dec65f874a19f6e46a5bbeb20aca56d0855c66ba0dd1a989462804ba01cddf6ba81e5
|
7
|
+
data.tar.gz: c191d95111cf81157ef2777bea143d12a0f71aa095b9df0da9bccf27ede6b3f53f250e01bc1bf0d20ab911840dbe33534c9c5fb7557cc521f08496eb8bc2a49f
|
data/README.md
CHANGED
@@ -2,3 +2,11 @@
|
|
2
2
|
|
3
3
|
ElasticGraph meta-gem that pulls in all the core ElasticGraph gems. Intended for use when all
|
4
4
|
parts of ElasticGraph are used from the same deployed app.
|
5
|
+
|
6
|
+
## Getting Started
|
7
|
+
|
8
|
+
Run this command to bootstrap a new local project:
|
9
|
+
|
10
|
+
```bash
|
11
|
+
elasticgraph new my_app
|
12
|
+
```
|
data/exe/elasticgraph
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright 2024 Block, Inc.
|
3
|
+
#
|
4
|
+
# Use of this source code is governed by an MIT-style
|
5
|
+
# license that can be found in the LICENSE file or at
|
6
|
+
# https://opensource.org/licenses/MIT.
|
7
|
+
#
|
8
|
+
# frozen_string_literal: true
|
9
|
+
|
10
|
+
require "elastic_graph/cli"
|
11
|
+
ElasticGraph::CLI.start(ARGV)
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require "bundler"
|
10
|
+
require "elastic_graph/version"
|
11
|
+
require "thor"
|
12
|
+
|
13
|
+
module ElasticGraph
|
14
|
+
class CLI < ::Thor
|
15
|
+
include ::Thor::Actions
|
16
|
+
|
17
|
+
# Tell Thor where our template files live
|
18
|
+
def self.source_root
|
19
|
+
::File.expand_path("project_template", __dir__)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.exit_on_failure?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
VALID_DATASTORES = %w[elasticsearch opensearch]
|
27
|
+
|
28
|
+
option :datastore, desc: "elasticsearch or opensearch", type: :string, default: "opensearch"
|
29
|
+
desc "new APP_NAME", "Generate a new ElasticGraph project in APP_NAME."
|
30
|
+
def new(app_path)
|
31
|
+
new_app_path = ::File.join(::Dir.pwd, app_path)
|
32
|
+
app_name = ::File.basename(new_app_path)
|
33
|
+
|
34
|
+
unless app_name.match?(/\A[a-z_]+\z/)
|
35
|
+
raise ::Thor::Error, "App name must be in `snake_case` form but was not: `#{app_name}`."
|
36
|
+
end
|
37
|
+
|
38
|
+
unless VALID_DATASTORES.include?(options[:datastore])
|
39
|
+
raise ::Thor::Error, "Invalid datastore option: #{options[:datastore]}. Must be #{VALID_DATASTORES.join(" or ")}."
|
40
|
+
end
|
41
|
+
|
42
|
+
setup_env = SetupEnv.new(
|
43
|
+
app_name: app_name,
|
44
|
+
app_module: app_name.split("_").map(&:capitalize).join,
|
45
|
+
datastore: options.fetch(:datastore),
|
46
|
+
gemfile_elasticgraph_details_code_snippet: %(["#{VERSION}"])
|
47
|
+
)
|
48
|
+
|
49
|
+
say "Creating a new #{setup_env.datastore_name} ElasticGraph project called '#{app_name}' at: #{new_app_path}", :green
|
50
|
+
|
51
|
+
ElasticGraph.with_setup_env(setup_env) do
|
52
|
+
# Recursively copy all files from project_template into the new_app_path
|
53
|
+
directory ".", new_app_path, exclude_pattern: %r{/lib/app_name/}
|
54
|
+
directory "lib/app_name", ::File.join(new_app_path, "lib", app_name)
|
55
|
+
end
|
56
|
+
|
57
|
+
inside new_app_path do
|
58
|
+
::Bundler.with_unbundled_env do
|
59
|
+
run "bundle install"
|
60
|
+
run "bundle exec rake schema_artifacts:dump query_registry:dump_variables:all build"
|
61
|
+
end
|
62
|
+
|
63
|
+
run "git init"
|
64
|
+
run "git add ."
|
65
|
+
run "git commit -m 'Bootstrapped ElasticGraph with `elasticgraph new`.'"
|
66
|
+
end
|
67
|
+
|
68
|
+
say "Successfully bootstrapped '#{app_name}' as a new #{setup_env.datastore_name} ElasticGraph project.", :green
|
69
|
+
|
70
|
+
say <<~INSTRUCTIONS, :yellow
|
71
|
+
Next steps:
|
72
|
+
1. cd #{app_path}
|
73
|
+
2. Run `bundle exec rake boot_locally` to try it out in your browser.
|
74
|
+
3. Run `bundle exec rake -T` to view other available tasks.
|
75
|
+
4. Customize your new project as needed. (Search for `TODO` to find things that need updating.)
|
76
|
+
INSTRUCTIONS
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class SetupEnv < ::Data.define(:app_name, :app_module, :datastore, :gemfile_elasticgraph_details_code_snippet)
|
81
|
+
DATASTORE_NAMES = {"elasticsearch" => "Elasticsearch", "opensearch" => "OpenSearch"}
|
82
|
+
DATASTORE_UI_NAMES = {"elasticsearch" => "Kibana", "opensearch" => "OpenSearch Dashboards"}
|
83
|
+
|
84
|
+
def datastore_name
|
85
|
+
DATASTORE_NAMES.fetch(datastore)
|
86
|
+
end
|
87
|
+
|
88
|
+
def datastore_ui_name
|
89
|
+
DATASTORE_UI_NAMES.fetch(datastore)
|
90
|
+
end
|
91
|
+
|
92
|
+
def ruby_major_minor
|
93
|
+
"3.4"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
singleton_class.attr_reader :setup_env
|
98
|
+
|
99
|
+
def self.with_setup_env(setup_env)
|
100
|
+
original_setup_env = self.setup_env
|
101
|
+
@setup_env = setup_env
|
102
|
+
yield
|
103
|
+
ensure
|
104
|
+
@setup_env = original_setup_env
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
# Gem details for the elasticgraph gems.
|
4
|
+
elasticgraph_details = <%= ElasticGraph.setup_env.gemfile_elasticgraph_details_code_snippet %>
|
5
|
+
|
6
|
+
gem "elasticgraph-local", *elasticgraph_details
|
7
|
+
gem "elasticgraph-<%= ElasticGraph.setup_env.datastore %>", *elasticgraph_details
|
8
|
+
gem "elasticgraph-query_registry", *elasticgraph_details
|
9
|
+
|
10
|
+
gem "httpx", "~> 1.3"
|
11
|
+
|
12
|
+
group :development do
|
13
|
+
gem "factory_bot"
|
14
|
+
gem "faker"
|
15
|
+
gem "rspec"
|
16
|
+
gem "standard"
|
17
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# <%= ElasticGraph.setup_env.app_module %> ElasticGraph Project
|
2
|
+
|
3
|
+
This repository contains the files for creating and maintaining the <%= ElasticGraph.setup_env.app_module %> ElasticGraph Project.
|
4
|
+
|
5
|
+
## Development Environment
|
6
|
+
|
7
|
+
Here's what you need:
|
8
|
+
|
9
|
+
| Requirement | Version | Installation Instructions |
|
10
|
+
|----------------|---------|---------------------------------------------------------------------------|
|
11
|
+
| Ruby | <%= ElasticGraph.setup_env.ruby_major_minor %>.x | [ruby-lang.org](https://www.ruby-lang.org/en/documentation/installation/) |
|
12
|
+
| Docker Engine | 27.x | [docker.com](https://docs.docker.com/engine/install/) |
|
13
|
+
| Docker Compose | 2.29.x | [docker.com](https://docs.docker.com/compose/install/) |
|
14
|
+
|
15
|
+
### Ruby
|
16
|
+
|
17
|
+
This project is written in Ruby, a dynamic, open source programming language with a focus on simplicity and productivity.
|
18
|
+
|
19
|
+
You may verify your `ruby` installation via the terminal:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
$ ruby -v
|
23
|
+
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
|
24
|
+
```
|
25
|
+
|
26
|
+
If you do not have Ruby, we recommend installing it using one of the following:
|
27
|
+
|
28
|
+
* [RVM](https://rvm.io/)
|
29
|
+
* [asdf](https://asdf-vm.com/)
|
30
|
+
* [rbenv](https://rbenv.org/)
|
31
|
+
* [ruby-install](https://github.com/postmodern/ruby-install)
|
32
|
+
|
33
|
+
### Ruby Dependencies
|
34
|
+
|
35
|
+
Ruby dependencies are managed using [bundler](https://bundler.io/), which comes installed with Ruby.
|
36
|
+
To install Ruby dependencies, run:
|
37
|
+
|
38
|
+
```bash
|
39
|
+
$ bundle install
|
40
|
+
```
|
41
|
+
|
42
|
+
Once that is done, prefix Ruby commands with `bundle exec` in order to run them in the context of the project bundle.
|
43
|
+
|
44
|
+
### Docker and Docker Compose
|
45
|
+
|
46
|
+
This project uses Docker Engine and Docker Compose to run <%= ElasticGraph.setup_env.datastore_name %> locally. We recommend installing
|
47
|
+
[Docker Desktop](https://docs.docker.com/desktop/) to get both Docker dependencies.
|
48
|
+
|
49
|
+
## Local Development
|
50
|
+
|
51
|
+
Some useful commands to try:
|
52
|
+
|
53
|
+
```bash
|
54
|
+
# The build rake task can be used after making changes to rebuild everything
|
55
|
+
bundle exec rake build
|
56
|
+
|
57
|
+
# See all tasks available for managing your project and schemas
|
58
|
+
bundle exec rake -T
|
59
|
+
|
60
|
+
# Boot a local instance prepopulated with fake data, useful for experimenting
|
61
|
+
bundle exec rake boot_locally
|
62
|
+
|
63
|
+
# The GraphiQL UI should open automatically
|
64
|
+
open http://localhost:9393/
|
65
|
+
|
66
|
+
# You can also visit <%= ElasticGraph.setup_env.datastore_ui_name %> via:
|
67
|
+
open http://localhost:19293/
|
68
|
+
```
|
69
|
+
|
70
|
+
### Run Build Tasks
|
71
|
+
|
72
|
+
Run a complete suite of build tasks with the build `rake` task:
|
73
|
+
|
74
|
+
```bash
|
75
|
+
bundle exec rake build
|
76
|
+
```
|
77
|
+
|
78
|
+
This will:
|
79
|
+
1. (Re)generate your schema artifacts
|
80
|
+
2. Validate all registered queries against the latest schema
|
81
|
+
3. Lint everything (use `bundle exec standardrb --fix` to fix most issues)
|
82
|
+
4. Run tests (including the common shared ElasticGraph tests)
|
83
|
+
|
84
|
+
Note: on CI, you'll want to use `bundle exec rake check` instead of `bundle exec rake build`,
|
85
|
+
so that it verifies that schema artifacts are up-to-date (rather than dumping them).
|
86
|
+
|
87
|
+
### Upgrading ElasticGraph
|
88
|
+
|
89
|
+
Upgrades to the ElasticGraph gems will come with [release notes](https://github.com/block/elasticgraph/releases/tag/v0.19.0.0) that include upgrade instructions, if necessary.
|
90
|
+
|
91
|
+
Here's the bare minimum upgrade process:
|
92
|
+
|
93
|
+
1. Modify `elasticgraph_details` in the root `Gemfile` and run `bundle install`.
|
94
|
+
2. Run `bundle exec rake`.
|
95
|
+
3. Commit the results.
|
96
|
+
|
97
|
+
### Managing <%= ElasticGraph.setup_env.datastore_name %>
|
98
|
+
|
99
|
+
The `<%= ElasticGraph.setup_env.datastore %>:` tasks will boot the desired <%= ElasticGraph.setup_env.datastore_name %> version using docker. You can
|
100
|
+
use either the `:boot` or `:daemon` tasks:
|
101
|
+
|
102
|
+
* The `:boot` task will keep <%= ElasticGraph.setup_env.datastore_name %> in the foreground, allowing you to see the logs.
|
103
|
+
* The `:daemon` task runs <%= ElasticGraph.setup_env.datastore_name %> as a background daemon task. Notably, it waits to return
|
104
|
+
until <%= ElasticGraph.setup_env.datastore_name %> is ready to receive traffic.
|
105
|
+
|
106
|
+
If you use a `:daemon` task, you can later use the corresponding `:halt` task to stop the daemon.
|
107
|
+
|
108
|
+
### Using the GraphiQL interactive GraphQL query editor
|
109
|
+
|
110
|
+
When running `bundle exec rake boot_locally` the GraphiQL editor should open automatically
|
111
|
+
(`open http://localhost:9393/`). Using it you can query your ElasticGraph cluster using GraphQL.
|
112
|
+
|
113
|
+
### Seeding Fake Data
|
114
|
+
|
115
|
+
The `bundle exec rake index_fake_data:<type_name>` tasks generate and index a batch of fake data.
|
116
|
+
You can pass an arg (note quotes) to seed more batches of data:
|
117
|
+
`bundle exec rake "index_fake_data:<type_name>[10]"`.
|
118
|
+
|
119
|
+
### Using <%= ElasticGraph.setup_env.datastore_ui_name %>
|
120
|
+
|
121
|
+
After running `bundle exec rake boot_locally` and opening <%= ElasticGraph.setup_env.datastore_ui_name %>
|
122
|
+
`open http://localhost:19293/` click "Dev Tools" to open the <%= ElasticGraph.setup_env.datastore_name %> console.
|
123
|
+
|
124
|
+
Here are some queries to get you started:
|
125
|
+
|
126
|
+
```
|
127
|
+
# Cluster info
|
128
|
+
GET /_cat/indices?v
|
129
|
+
GET /_cat/shards?v
|
130
|
+
GET /_cat/templates?v
|
131
|
+
GET /_cat/nodes?v
|
132
|
+
GET /_cat/allocation?v
|
133
|
+
|
134
|
+
# Or with a pattern
|
135
|
+
GET /_cat/shards/*_rollover__202*?v
|
136
|
+
|
137
|
+
# More cluster info
|
138
|
+
GET /_cluster/health
|
139
|
+
GET /_cluster/settings
|
140
|
+
|
141
|
+
# Test queries (change from `artists` to your index name)
|
142
|
+
GET /artists/_search
|
143
|
+
{
|
144
|
+
"from": 0,
|
145
|
+
"size": 1
|
146
|
+
}
|
147
|
+
|
148
|
+
GET /artists/_search
|
149
|
+
{
|
150
|
+
"from": 0,
|
151
|
+
"size": 1,
|
152
|
+
"query": {
|
153
|
+
"bool": {
|
154
|
+
"must": [
|
155
|
+
{
|
156
|
+
"match": {
|
157
|
+
"bio": "accordion"
|
158
|
+
}
|
159
|
+
}
|
160
|
+
]
|
161
|
+
}
|
162
|
+
}
|
163
|
+
}
|
164
|
+
```
|
165
|
+
|
166
|
+
### Query Registry
|
167
|
+
|
168
|
+
This project uses the ElasticGraph query registry extension. This is an optional piece you can choose to remove,
|
169
|
+
but provides many benefits--see the [elasticgraph-query_registry
|
170
|
+
README](https://github.com/block/elasticgraph/tree/main/elasticgraph-query_registry#elasticgraphqueryregistry)
|
171
|
+
for details.
|
172
|
+
|
173
|
+
With the registry in place, clients must register their queries in a directory under
|
174
|
+
[config/queries](config/queries) that matches their resolved application name.
|
175
|
+
The CI build will validate that all schema changes are compatible with all registered queries, and
|
176
|
+
your deployed GraphQL endpoints will reject any unregistered queries.
|
@@ -0,0 +1,64 @@
|
|
1
|
+
project_root = File.expand_path(__dir__)
|
2
|
+
|
3
|
+
require "elastic_graph/local/rake_tasks"
|
4
|
+
require "elastic_graph/query_registry/rake_tasks"
|
5
|
+
require "rspec/core/rake_task"
|
6
|
+
require "standard/rake"
|
7
|
+
require_relative "lib/<%= ElasticGraph.setup_env.app_name %>/fake_data_batch_generator"
|
8
|
+
|
9
|
+
settings_file = "#{project_root}/config/settings/local.yaml"
|
10
|
+
|
11
|
+
ElasticGraph::Local::RakeTasks.new(
|
12
|
+
local_config_yaml: settings_file,
|
13
|
+
path_to_schema: "#{project_root}/config/schema.rb"
|
14
|
+
) do |tasks|
|
15
|
+
# Set this to true once you're beyond the prototyping stage.
|
16
|
+
tasks.enforce_json_schema_version = false
|
17
|
+
|
18
|
+
# Determines casing of field names. Can be either `:camelCase` or `:snake_case`.
|
19
|
+
tasks.schema_element_name_form = :camelCase
|
20
|
+
|
21
|
+
# Customizes the names of fields generated by ElasticGraph.
|
22
|
+
tasks.schema_element_name_overrides = {
|
23
|
+
# Example: force inequality operators to be spelled out.
|
24
|
+
# gt: "greaterThan",
|
25
|
+
# gte: "greaterThanOrEqualTo",
|
26
|
+
# lt: "lessThan",
|
27
|
+
# lte: "lessThanOrEqualTo"
|
28
|
+
}
|
29
|
+
|
30
|
+
# Customizes the naming format used by derived types.
|
31
|
+
tasks.derived_type_name_formats = {
|
32
|
+
# Example: change suffix used for filter inputs from `FilterInput` to just `Filter`.
|
33
|
+
# FilterInput: "%{base}Filter",
|
34
|
+
}
|
35
|
+
|
36
|
+
# Use this to override type names generated by ElasticGraph. We generally recommend sticking
|
37
|
+
# with the defaults, but to align with conventions in your organization you may need to override
|
38
|
+
# some type names.
|
39
|
+
tasks.type_name_overrides = {
|
40
|
+
# Example: this would make your ElasticGraph schema use `IDFilter` in place of the standard `IDFilterInput`.
|
41
|
+
# IDFilterInput: "IDFilter"
|
42
|
+
}
|
43
|
+
|
44
|
+
# TODO: replace this with a fake data generator for your own dataset.
|
45
|
+
tasks.define_fake_data_batch_for :artists do
|
46
|
+
<%= ElasticGraph.setup_env.app_module %>::FakeDataBatchGenerator.generate(artists: 100, venues: 10)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
ElasticGraph::QueryRegistry::RakeTasks.from_yaml_file(
|
51
|
+
settings_file,
|
52
|
+
"config/queries",
|
53
|
+
require_eg_latency_slo_directive: false
|
54
|
+
)
|
55
|
+
|
56
|
+
::RSpec::Core::RakeTask.new
|
57
|
+
|
58
|
+
standard_checks = ["standard", "query_registry:validate_queries", "spec"]
|
59
|
+
|
60
|
+
desc "Rebuild everything. Intended to be run locally as you iterate on the schema"
|
61
|
+
task build: ["schema_artifacts:dump", *standard_checks]
|
62
|
+
|
63
|
+
desc "Check everything. Intended to be run on CI to check your project."
|
64
|
+
task check: ["schema_artifacts:check", *standard_checks]
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# TODO: remove or replace this query when you replace the artist schema.
|
2
|
+
query FindArtist {
|
3
|
+
byName: artists(filter: {
|
4
|
+
name: {equalToAnyOf: ["U2"]}
|
5
|
+
}) {
|
6
|
+
nodes {
|
7
|
+
name
|
8
|
+
bio {
|
9
|
+
yearFormed
|
10
|
+
}
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
byBioYearFounded: artists(filter: {
|
15
|
+
bio: {yearFormed: {gt: 2000}}
|
16
|
+
}) {
|
17
|
+
nodes {
|
18
|
+
name
|
19
|
+
bio {
|
20
|
+
yearFormed
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# TODO: replace this file with one that defines the schema for your own dataset.
|
2
|
+
ElasticGraph.define_schema do |schema|
|
3
|
+
schema.object_type "Artist" do |t|
|
4
|
+
t.field "id", "ID"
|
5
|
+
t.field "name", "String"
|
6
|
+
t.field "lifetimeSales", "JsonSafeLong"
|
7
|
+
t.field "bio", "ArtistBio"
|
8
|
+
|
9
|
+
t.field "albums", "[Album!]!" do |f|
|
10
|
+
f.mapping type: "nested"
|
11
|
+
end
|
12
|
+
|
13
|
+
t.field "tours", "[Tour!]!" do |f|
|
14
|
+
f.mapping type: "nested"
|
15
|
+
end
|
16
|
+
|
17
|
+
t.index "artists"
|
18
|
+
end
|
19
|
+
|
20
|
+
schema.object_type "ArtistBio" do |t|
|
21
|
+
t.field "yearFormed", "Int"
|
22
|
+
t.field "homeCountry", "String"
|
23
|
+
t.field "description", "String" do |f|
|
24
|
+
f.mapping type: "text"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
schema.object_type "Album" do |t|
|
29
|
+
t.field "name", "String"
|
30
|
+
t.field "releasedOn", "Date"
|
31
|
+
t.field "soldUnits", "Int"
|
32
|
+
t.field "tracks", "[AlbumTrack!]!" do |f|
|
33
|
+
f.mapping type: "nested"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
schema.object_type "AlbumTrack" do |t|
|
38
|
+
t.field "name", "String"
|
39
|
+
t.field "trackNumber", "Int"
|
40
|
+
t.field "lengthInSeconds", "Int"
|
41
|
+
end
|
42
|
+
|
43
|
+
schema.object_type "Tour" do |t|
|
44
|
+
t.field "name", "String"
|
45
|
+
t.field "shows", "[Show!]!" do |f|
|
46
|
+
f.mapping type: "nested"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
schema.object_type "Show" do |t|
|
51
|
+
t.relates_to_one "venue", "Venue", via: "venueId", dir: :out
|
52
|
+
t.field "attendance", "Int"
|
53
|
+
t.field "startedAt", "DateTime"
|
54
|
+
end
|
55
|
+
|
56
|
+
schema.object_type "Venue" do |t|
|
57
|
+
t.field "id", "ID"
|
58
|
+
t.field "name", "String"
|
59
|
+
t.field "location", "GeoLocation"
|
60
|
+
t.field "capacity", "Int"
|
61
|
+
t.relates_to_many "featuredArtists", "Artist", via: "tours.shows.venueId", dir: :in, singular: "featuredArtist"
|
62
|
+
|
63
|
+
t.index "venues"
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
ElasticGraph.define_schema do |schema|
|
4
|
+
# ElasticGraph will tell you when you need to bump this.
|
5
|
+
schema.json_schema_version 1
|
6
|
+
|
7
|
+
# This registers the elasticgraph-query_registry extension, which can be used to reject queries that
|
8
|
+
# clients have not registered (and to reject queries that differ from what a client has registered).
|
9
|
+
# In addition, every registered query is validated against the schema in the CI build, giving you
|
10
|
+
# confidence as you evolve your schema that you're not breaking client queries.
|
11
|
+
#
|
12
|
+
# If you don't want to use this extension, you can remove these lines.
|
13
|
+
require(query_registry_path = "elastic_graph/query_registry/graphql_extension")
|
14
|
+
schema.register_graphql_extension ElasticGraph::QueryRegistry::GraphQLExtension, defined_at: query_registry_path
|
15
|
+
end
|
16
|
+
|
17
|
+
# Load the rest of the schema from files at config/schema/**/*.rb.
|
18
|
+
Dir["#{__dir__}/schema/**/*.rb"].each do |schema_def_file|
|
19
|
+
# Must use `load`, not `require` so that if the schema is evaluated multiple times it works.
|
20
|
+
load Pathname(schema_def_file).expand_path
|
21
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
datastore:
|
2
|
+
client_faraday_adapter:
|
3
|
+
name: httpx
|
4
|
+
require: httpx/adapters/faraday
|
5
|
+
clusters:
|
6
|
+
main:
|
7
|
+
backend: <%= ElasticGraph.setup_env.datastore %>
|
8
|
+
url: http://localhost:9293
|
9
|
+
settings: {}
|
10
|
+
index_definitions:
|
11
|
+
# TODO: replace the `artists:` and `venues:` keys with the indices from your dataset
|
12
|
+
artists: &main_index_settings
|
13
|
+
# elasticgraph-local relies on the cluster being named "main".
|
14
|
+
query_cluster: "main"
|
15
|
+
index_into_clusters: ["main"]
|
16
|
+
ignore_routing_values: []
|
17
|
+
custom_timestamp_ranges: []
|
18
|
+
setting_overrides:
|
19
|
+
number_of_shards: 10
|
20
|
+
setting_overrides_by_timestamp: {}
|
21
|
+
venues: *main_index_settings
|
22
|
+
max_client_retries: 3
|
23
|
+
graphql:
|
24
|
+
default_page_size: 50
|
25
|
+
max_page_size: 500
|
26
|
+
logger:
|
27
|
+
device: stderr
|
28
|
+
indexer:
|
29
|
+
latency_slo_thresholds_by_timestamp_in_ms: {}
|
30
|
+
schema_artifacts:
|
31
|
+
directory: config/schema/artifacts
|
32
|
+
query_registry:
|
33
|
+
# Allow any query by any client since this is for local use.
|
34
|
+
allow_unregistered_clients: true
|
35
|
+
allow_any_query_for_clients: []
|
36
|
+
path_to_registry: config/queries
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require "factory_bot"
|
2
|
+
require "faker"
|
3
|
+
require_relative "shared_factories"
|
4
|
+
|
5
|
+
# TODO: replace the artist/album/tour/venue factories with your own.
|
6
|
+
FactoryBot.define do
|
7
|
+
factory :artist, parent: :indexed_type_base do
|
8
|
+
__typename { "Artist" }
|
9
|
+
name { Faker::Music.band }
|
10
|
+
|
11
|
+
lifetimeSales do
|
12
|
+
albums.map { |a| a.fetch(:soldUnits) }.sum
|
13
|
+
end
|
14
|
+
|
15
|
+
bio { build(:artist_bio) }
|
16
|
+
|
17
|
+
albums do
|
18
|
+
Faker::Number.between(from: 1, to: 10).times.map { build(:album) }
|
19
|
+
end
|
20
|
+
|
21
|
+
tours do
|
22
|
+
Faker::Number.between(from: 0, to: 8).times.map { build(:tour, venueIds: venueIds) }
|
23
|
+
end
|
24
|
+
|
25
|
+
transient do
|
26
|
+
venueIds { [] }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
factory :artist_bio, parent: :hash_base do
|
31
|
+
__typename { "ArtistBio" }
|
32
|
+
yearFormed { Faker::Number.between(from: 1900, to: 2025) }
|
33
|
+
homeCountry { Faker::Address.country }
|
34
|
+
description { Faker::Lorem.paragraphs(number: 3).join("\n\n") }
|
35
|
+
end
|
36
|
+
|
37
|
+
factory :album, parent: :hash_base do
|
38
|
+
__typename { "Album" }
|
39
|
+
name { Faker::Music.album }
|
40
|
+
releasedOn { Faker::Date.between(from: "1900-01-01", to: "2025-12-31").iso8601 }
|
41
|
+
soldUnits { Faker::Number.between(from: 10000, to: 100_000_000) }
|
42
|
+
tracks do
|
43
|
+
Faker::Number.between(from: 1, to: 20).times.map do |index|
|
44
|
+
build(:album_track, trackNumber: index + 1)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
factory :album_track, parent: :hash_base do
|
50
|
+
__typename { "AlbumTrack" }
|
51
|
+
name { Faker::Music::RockBand.song }
|
52
|
+
trackNumber { Faker::Number.between(from: 1, to: 20) }
|
53
|
+
lengthInSeconds { Faker::Number.between(from: 30, to: 1200) }
|
54
|
+
end
|
55
|
+
|
56
|
+
factory :tour, parent: :hash_base do
|
57
|
+
__typename { "Tour" }
|
58
|
+
name { "#{Faker::Music::RockBand.song} Tour" }
|
59
|
+
shows do
|
60
|
+
start_date = Faker::Date.between(from: "1900-01-01", to: "2025-12-31")
|
61
|
+
|
62
|
+
Faker::Number.between(from: 3, to: 200).times.map do |index|
|
63
|
+
venue_id = Faker::Base.sample(venueIds)
|
64
|
+
build(:show, date: start_date + index, venueId: venue_id)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
transient do
|
69
|
+
venueIds { [] }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
factory :show, parent: :hash_base do
|
74
|
+
__typename { "Show" }
|
75
|
+
attendance { Faker::Number.between(from: 200, to: 100_000) }
|
76
|
+
startedAt { "#{date.iso8601}T#{startTime}" }
|
77
|
+
venueId { nil }
|
78
|
+
|
79
|
+
transient do
|
80
|
+
date { Faker::Date.between(from: "1900-01-01", to: "2025-12-31") }
|
81
|
+
startTime { Faker::Base.sample(%w[19:00:00Z 19:30:00Z 20:00:00Z 20:30:00Z]) }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
factory :venue, parent: :indexed_type_base do
|
86
|
+
__typename { "Venue" }
|
87
|
+
|
88
|
+
name do
|
89
|
+
# Some common music venue types
|
90
|
+
venue_types = ["Theater", "Arena", "Music Hall", "Stadium", "Opera House", "Amphitheater"]
|
91
|
+
|
92
|
+
city_name = Faker::Address.city
|
93
|
+
venue_type = Faker::Base.sample(venue_types)
|
94
|
+
|
95
|
+
"#{city_name} #{venue_type}"
|
96
|
+
end
|
97
|
+
|
98
|
+
location { build(:geo_location) }
|
99
|
+
capacity { Faker::Number.between(from: 200, to: 100_000) }
|
100
|
+
end
|
101
|
+
|
102
|
+
factory :geo_location, parent: :hash_base do
|
103
|
+
__typename { "GeoLocation" }
|
104
|
+
latitude { Faker::Number.between(from: -90.0, to: 90.0) }
|
105
|
+
longitude { Faker::Number.between(from: -180.0, to: 180.0) }
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative "factories"
|
2
|
+
|
3
|
+
module <%= ElasticGraph.setup_env.app_module %>
|
4
|
+
module FakeDataBatchGenerator
|
5
|
+
def self.generate(artists:, venues:)
|
6
|
+
venue_list = FactoryBot.build_list(:venue, venues)
|
7
|
+
venue_ids = venue_list.map { |v| v.fetch(:id) }
|
8
|
+
|
9
|
+
artist_list = FactoryBot.build_list(:artist, artists, venueIds: venue_ids)
|
10
|
+
|
11
|
+
venue_list + artist_list
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "date"
|
2
|
+
require "factory_bot"
|
3
|
+
require "faker"
|
4
|
+
|
5
|
+
FactoryBot.define do
|
6
|
+
factory :hash_base, class: Hash do
|
7
|
+
initialize_with { attributes }
|
8
|
+
end
|
9
|
+
|
10
|
+
trait :uuid_id do
|
11
|
+
id { Faker::Internet.uuid }
|
12
|
+
end
|
13
|
+
|
14
|
+
trait :versioned do
|
15
|
+
__version { Faker::Number.between(from: 1, to: 10) }
|
16
|
+
end
|
17
|
+
|
18
|
+
current_json_schema_version = nil
|
19
|
+
|
20
|
+
factory :indexed_type_base, parent: :hash_base, traits: [:uuid_id, :versioned] do
|
21
|
+
__typename { raise NotImplementedError, "You must supply __typename" }
|
22
|
+
__json_schema_version do
|
23
|
+
current_json_schema_version ||= begin
|
24
|
+
json_schema_file = File.expand_path("../../config/schema/artifacts/json_schemas.yaml", __dir__)
|
25
|
+
YAML.safe_load_file(json_schema_file).fetch("json_schema_version")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "elastic_graph/local/spec_support/common_project_specs"
|
2
|
+
require "<%= ElasticGraph.setup_env.app_name %>/factories"
|
3
|
+
require "<%= ElasticGraph.setup_env.app_name %>/fake_data_batch_generator"
|
4
|
+
|
5
|
+
RSpec.describe "ElasticGraph project" do
|
6
|
+
ignored_factories = [
|
7
|
+
# List any factories to ignore
|
8
|
+
]
|
9
|
+
|
10
|
+
include_examples "an ElasticGraph project",
|
11
|
+
use_settings_yaml: "local.yaml",
|
12
|
+
ignored_factories: ignored_factories
|
13
|
+
|
14
|
+
# TODO: update this spec as needed to generate example fake data for your dataset.
|
15
|
+
it "generates a batch of valid records from `FakeDataBatchGenerator`" do
|
16
|
+
batch = <%= ElasticGraph.setup_env.app_module %>::FakeDataBatchGenerator.generate(artists: 20, venues: 5)
|
17
|
+
expect(batch.size).to eq(25)
|
18
|
+
end
|
19
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elasticgraph
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.19.
|
4
|
+
version: 0.19.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Myron Marston
|
@@ -10,139 +10,71 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2025-02-06 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
17
|
-
requirement: !ruby/object:Gem::Requirement
|
18
|
-
requirements:
|
19
|
-
- - "~>"
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '2.26'
|
22
|
-
type: :development
|
23
|
-
prerelease: false
|
24
|
-
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
requirements:
|
26
|
-
- - "~>"
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
version: '2.26'
|
29
|
-
- !ruby/object:Gem::Dependency
|
30
|
-
name: rubocop-rake
|
31
|
-
requirement: !ruby/object:Gem::Requirement
|
32
|
-
requirements:
|
33
|
-
- - "~>"
|
34
|
-
- !ruby/object:Gem::Version
|
35
|
-
version: '0.6'
|
36
|
-
type: :development
|
37
|
-
prerelease: false
|
38
|
-
version_requirements: !ruby/object:Gem::Requirement
|
39
|
-
requirements:
|
40
|
-
- - "~>"
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
version: '0.6'
|
43
|
-
- !ruby/object:Gem::Dependency
|
44
|
-
name: rubocop-rspec
|
45
|
-
requirement: !ruby/object:Gem::Requirement
|
46
|
-
requirements:
|
47
|
-
- - "~>"
|
48
|
-
- !ruby/object:Gem::Version
|
49
|
-
version: '3.1'
|
50
|
-
type: :development
|
51
|
-
prerelease: false
|
52
|
-
version_requirements: !ruby/object:Gem::Requirement
|
53
|
-
requirements:
|
54
|
-
- - "~>"
|
55
|
-
- !ruby/object:Gem::Version
|
56
|
-
version: '3.1'
|
57
|
-
- !ruby/object:Gem::Dependency
|
58
|
-
name: standard
|
59
|
-
requirement: !ruby/object:Gem::Requirement
|
60
|
-
requirements:
|
61
|
-
- - "~>"
|
62
|
-
- !ruby/object:Gem::Version
|
63
|
-
version: 1.41.0
|
64
|
-
type: :development
|
65
|
-
prerelease: false
|
66
|
-
version_requirements: !ruby/object:Gem::Requirement
|
67
|
-
requirements:
|
68
|
-
- - "~>"
|
69
|
-
- !ruby/object:Gem::Version
|
70
|
-
version: 1.41.0
|
71
|
-
- !ruby/object:Gem::Dependency
|
72
|
-
name: elasticgraph-admin
|
73
|
-
requirement: !ruby/object:Gem::Requirement
|
74
|
-
requirements:
|
75
|
-
- - '='
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
version: 0.19.0.0
|
78
|
-
type: :runtime
|
79
|
-
prerelease: false
|
80
|
-
version_requirements: !ruby/object:Gem::Requirement
|
81
|
-
requirements:
|
82
|
-
- - '='
|
83
|
-
- !ruby/object:Gem::Version
|
84
|
-
version: 0.19.0.0
|
85
|
-
- !ruby/object:Gem::Dependency
|
86
|
-
name: elasticgraph-graphql
|
16
|
+
name: elasticgraph-support
|
87
17
|
requirement: !ruby/object:Gem::Requirement
|
88
18
|
requirements:
|
89
19
|
- - '='
|
90
20
|
- !ruby/object:Gem::Version
|
91
|
-
version: 0.19.
|
21
|
+
version: 0.19.1.0
|
92
22
|
type: :runtime
|
93
23
|
prerelease: false
|
94
24
|
version_requirements: !ruby/object:Gem::Requirement
|
95
25
|
requirements:
|
96
26
|
- - '='
|
97
27
|
- !ruby/object:Gem::Version
|
98
|
-
version: 0.19.
|
28
|
+
version: 0.19.1.0
|
99
29
|
- !ruby/object:Gem::Dependency
|
100
|
-
name:
|
30
|
+
name: thor
|
101
31
|
requirement: !ruby/object:Gem::Requirement
|
102
32
|
requirements:
|
103
|
-
- -
|
104
|
-
- !ruby/object:Gem::Version
|
105
|
-
version: 0.19.0.0
|
106
|
-
type: :runtime
|
107
|
-
prerelease: false
|
108
|
-
version_requirements: !ruby/object:Gem::Requirement
|
109
|
-
requirements:
|
110
|
-
- - '='
|
111
|
-
- !ruby/object:Gem::Version
|
112
|
-
version: 0.19.0.0
|
113
|
-
- !ruby/object:Gem::Dependency
|
114
|
-
name: elasticgraph-local
|
115
|
-
requirement: !ruby/object:Gem::Requirement
|
116
|
-
requirements:
|
117
|
-
- - '='
|
33
|
+
- - "~>"
|
118
34
|
- !ruby/object:Gem::Version
|
119
|
-
version:
|
35
|
+
version: '1.3'
|
120
36
|
type: :runtime
|
121
37
|
prerelease: false
|
122
38
|
version_requirements: !ruby/object:Gem::Requirement
|
123
39
|
requirements:
|
124
|
-
- -
|
40
|
+
- - "~>"
|
125
41
|
- !ruby/object:Gem::Version
|
126
|
-
version:
|
42
|
+
version: '1.3'
|
127
43
|
description:
|
128
44
|
email:
|
129
45
|
- myron@squareup.com
|
130
|
-
executables:
|
46
|
+
executables:
|
47
|
+
- elasticgraph
|
131
48
|
extensions: []
|
132
49
|
extra_rdoc_files: []
|
133
50
|
files:
|
134
51
|
- LICENSE.txt
|
135
52
|
- README.md
|
136
|
-
- elasticgraph
|
53
|
+
- exe/elasticgraph
|
54
|
+
- lib/elastic_graph/cli.rb
|
55
|
+
- lib/elastic_graph/project_template/.gitignore
|
56
|
+
- lib/elastic_graph/project_template/.standard.yml.tt
|
57
|
+
- lib/elastic_graph/project_template/Gemfile.tt
|
58
|
+
- lib/elastic_graph/project_template/README.md.tt
|
59
|
+
- lib/elastic_graph/project_template/Rakefile.tt
|
60
|
+
- lib/elastic_graph/project_template/config/queries/example_client/FindArtist.graphql
|
61
|
+
- lib/elastic_graph/project_template/config/queries/example_client/ListArtistAlbums.graphql
|
62
|
+
- lib/elastic_graph/project_template/config/schema.rb.tt
|
63
|
+
- lib/elastic_graph/project_template/config/schema/artists.rb.tt
|
64
|
+
- lib/elastic_graph/project_template/config/settings/local.yaml.tt
|
65
|
+
- lib/elastic_graph/project_template/lib/app_name/factories.rb
|
66
|
+
- lib/elastic_graph/project_template/lib/app_name/fake_data_batch_generator.rb.tt
|
67
|
+
- lib/elastic_graph/project_template/lib/app_name/shared_factories.rb
|
68
|
+
- lib/elastic_graph/project_template/spec/project_spec.rb.tt
|
137
69
|
homepage: https://block.github.io/elasticgraph/
|
138
70
|
licenses:
|
139
71
|
- MIT
|
140
72
|
metadata:
|
141
73
|
bug_tracker_uri: https://github.com/block/elasticgraph/issues
|
142
|
-
changelog_uri: https://github.com/block/elasticgraph/releases/tag/v0.19.
|
74
|
+
changelog_uri: https://github.com/block/elasticgraph/releases/tag/v0.19.1.0
|
143
75
|
documentation_uri: https://block.github.io/elasticgraph/docs/main/
|
144
76
|
homepage_uri: https://block.github.io/elasticgraph/
|
145
|
-
source_code_uri: https://github.com/block/elasticgraph/tree/v0.19.
|
77
|
+
source_code_uri: https://github.com/block/elasticgraph/tree/v0.19.1.0/elasticgraph
|
146
78
|
gem_category: core
|
147
79
|
post_install_message:
|
148
80
|
rdoc_options: []
|
@@ -150,9 +82,12 @@ require_paths:
|
|
150
82
|
- lib
|
151
83
|
required_ruby_version: !ruby/object:Gem::Requirement
|
152
84
|
requirements:
|
153
|
-
- - "
|
85
|
+
- - ">="
|
154
86
|
- !ruby/object:Gem::Version
|
155
87
|
version: '3.2'
|
88
|
+
- - "<"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '3.5'
|
156
91
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
92
|
requirements:
|
158
93
|
- - ">="
|
@@ -162,5 +97,5 @@ requirements: []
|
|
162
97
|
rubygems_version: 3.5.22
|
163
98
|
signing_key:
|
164
99
|
specification_version: 4
|
165
|
-
summary:
|
100
|
+
summary: Bootstraps ElasticGraph projects.
|
166
101
|
test_files: []
|
data/elasticgraph.gemspec
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# Copyright 2024 Block, Inc.
|
2
|
-
#
|
3
|
-
# Use of this source code is governed by an MIT-style
|
4
|
-
# license that can be found in the LICENSE file or at
|
5
|
-
# https://opensource.org/licenses/MIT.
|
6
|
-
#
|
7
|
-
# frozen_string_literal: true
|
8
|
-
|
9
|
-
require_relative "../gemspec_helper"
|
10
|
-
|
11
|
-
ElasticGraphGemspecHelper.define_elasticgraph_gem(gemspec_file: __FILE__, category: :core) do |spec, eg_version|
|
12
|
-
spec.summary = "ElasticGraph meta-gem that pulls in all the core ElasticGraph gems."
|
13
|
-
|
14
|
-
spec.add_dependency "elasticgraph-admin", eg_version
|
15
|
-
spec.add_dependency "elasticgraph-graphql", eg_version
|
16
|
-
spec.add_dependency "elasticgraph-indexer", eg_version
|
17
|
-
spec.add_dependency "elasticgraph-local", eg_version
|
18
|
-
end
|