From a05f8af604f80cf4ed33eaaaa78ede21f2bf5849 Mon Sep 17 00:00:00 2001 From: Chad Miller Date: Wed, 12 Nov 2025 13:13:42 -0800 Subject: [PATCH] move registry to unstable_registry since its not ready yet --- CHANGELOG.md | 6 + examples/03-unstable-cache/README.md | 24 -- examples/03-unstable-cache/gleam.toml | 27 -- examples/03-unstable-cache/index.html | 15 - examples/03-unstable-cache/manifest.toml | 61 ---- .../03-unstable-cache/src/cache_example.gleam | 316 ------------------ .../src/components/character_detail.gleam | 100 ------ .../src/components/character_list.gleam | 91 ----- .../src/components/episode_list.gleam | 84 ----- .../src/components/location_list.gleam | 80 ----- .../src/generated/queries.gleam | 32 -- .../src/generated/queries/get_character.gleam | 83 ----- .../generated/queries/get_characters.gleam | 93 ------ .../src/generated/queries/get_episodes.gleam | 89 ----- .../src/generated/queries/get_locations.gleam | 93 ------ .../src/graphql/get_character.gleam | 79 ----- .../src/graphql/get_character.gql | 11 - .../src/graphql/get_characters.gleam | 82 ----- .../src/graphql/get_characters.gql | 10 - .../src/graphql/get_episodes.gleam | 83 ----- .../src/graphql/get_episodes.gql | 10 - .../src/graphql/get_locations.gleam | 87 ----- .../src/graphql/get_locations.gql | 10 - .../test/cache_example_test.gleam | 13 - gleam.toml | 2 +- src/squall/internal/registry_codegen.gleam | 8 +- ...registry.gleam => unstable_registry.gleam} | 0 27 files changed, 11 insertions(+), 1578 deletions(-) delete mode 100644 examples/03-unstable-cache/README.md delete mode 100644 examples/03-unstable-cache/gleam.toml delete mode 100644 examples/03-unstable-cache/index.html delete mode 100644 examples/03-unstable-cache/manifest.toml delete mode 100644 examples/03-unstable-cache/src/cache_example.gleam delete mode 100644 examples/03-unstable-cache/src/components/character_detail.gleam delete mode 100644 examples/03-unstable-cache/src/components/character_list.gleam delete mode 100644 examples/03-unstable-cache/src/components/episode_list.gleam delete mode 100644 examples/03-unstable-cache/src/components/location_list.gleam delete mode 100644 examples/03-unstable-cache/src/generated/queries.gleam delete mode 100644 examples/03-unstable-cache/src/generated/queries/get_character.gleam delete mode 100644 examples/03-unstable-cache/src/generated/queries/get_characters.gleam delete mode 100644 examples/03-unstable-cache/src/generated/queries/get_episodes.gleam delete mode 100644 examples/03-unstable-cache/src/generated/queries/get_locations.gleam delete mode 100644 examples/03-unstable-cache/src/graphql/get_character.gleam delete mode 100644 examples/03-unstable-cache/src/graphql/get_character.gql delete mode 100644 examples/03-unstable-cache/src/graphql/get_characters.gleam delete mode 100644 examples/03-unstable-cache/src/graphql/get_characters.gql delete mode 100644 examples/03-unstable-cache/src/graphql/get_episodes.gleam delete mode 100644 examples/03-unstable-cache/src/graphql/get_episodes.gql delete mode 100644 examples/03-unstable-cache/src/graphql/get_locations.gleam delete mode 100644 examples/03-unstable-cache/src/graphql/get_locations.gql delete mode 100644 examples/03-unstable-cache/test/cache_example_test.gleam rename src/squall/{registry.gleam => unstable_registry.gleam} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f636c0..d52f093 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.1.1] - 2025-11-12 + +### Changed + +- **Renamed `registry` module to `unstable_registry`** - The cache registry module is experimental + ## [1.1.0] - 2025-11-12 ### Added diff --git a/examples/03-unstable-cache/README.md b/examples/03-unstable-cache/README.md deleted file mode 100644 index 0b38aca..0000000 --- a/examples/03-unstable-cache/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# cache_example - -[![Package Version](https://img.shields.io/hexpm/v/cache_example)](https://hex.pm/packages/cache_example) -[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/cache_example/) - -```sh -gleam add cache_example@1 -``` -```gleam -import cache_example - -pub fn main() -> Nil { - // TODO: An example of the project in use -} -``` - -Further documentation can be found at . - -## Development - -```sh -gleam run # Run the project -gleam test # Run the tests -``` diff --git a/examples/03-unstable-cache/gleam.toml b/examples/03-unstable-cache/gleam.toml deleted file mode 100644 index 7a924f1..0000000 --- a/examples/03-unstable-cache/gleam.toml +++ /dev/null @@ -1,27 +0,0 @@ -name = "cache_example" -version = "1.0.0" -target = "javascript" - -# Fill out these fields if you intend to generate HTML documentation or publish -# your project to the Hex package manager. -# -# description = "" -# licences = ["Apache-2.0"] -# repository = { type = "github", user = "", repo = "" } -# links = [{ title = "Website", href = "" }] -# -# For a full reference of all the available options, you can have a look at -# https://gleam.run/writing-gleam/gleam-toml/. - -[dependencies] -gleam_stdlib = ">= 0.44.0 and < 2.0.0" -lustre = ">= 5.0.0 and < 6.0.0" -gleam_json = ">= 3.0.0 and < 4.0.0" -squall = { path = "../../" } -squall_cache = { path = "/Users/chadmiller/code/squall_cache" } -modem = ">= 2.0.0 and < 3.0.0" -gleam_http = ">= 4.3.0 and < 5.0.0" - -[dev-dependencies] -gleeunit = ">= 1.0.0 and < 2.0.0" -lustre_dev_tools = ">= 2.2.2 and < 3.0.0" diff --git a/examples/03-unstable-cache/index.html b/examples/03-unstable-cache/index.html deleted file mode 100644 index 0032152..0000000 --- a/examples/03-unstable-cache/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - Squall Cache Example - Rick and Morty Characters - - -
- - - diff --git a/examples/03-unstable-cache/manifest.toml b/examples/03-unstable-cache/manifest.toml deleted file mode 100644 index d6dcdf4..0000000 --- a/examples/03-unstable-cache/manifest.toml +++ /dev/null @@ -1,61 +0,0 @@ -# This file was generated by Gleam -# You typically do not need to edit this file - -packages = [ - { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, - { name = "booklet", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "booklet", source = "hex", outer_checksum = "08E0FDB78DC4D8A5D3C80295B021505C7D2A2E7B6C6D5EAB7286C36F4A53C851" }, - { name = "directories", version = "1.2.0", build_tools = ["gleam"], requirements = ["envoy", "gleam_stdlib", "platform", "simplifile"], otp_app = "directories", source = "hex", outer_checksum = "D13090CFCDF6759B87217E8DDD73A75903A700148A82C1D33799F333E249BF9E" }, - { name = "envoy", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "95FD059345AA982E89A0B6E2A3BF1CF43E17A7048DCD85B5B65D3B9E4E39D359" }, - { name = "exception", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "329D269D5C2A314F7364BD2711372B6F2C58FA6F39981572E5CA68624D291F8C" }, - { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" }, - { name = "glam", version = "2.0.3", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glam", source = "hex", outer_checksum = "237C2CE218A2A0A5D46D625F8EF5B78F964BC91018B78D692B17E1AB84295229" }, - { name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" }, - { name = "gleam_community_colour", version = "2.0.2", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "E34DD2C896AC3792151EDA939DA435FF3B69922F33415ED3C4406C932FBE9634" }, - { name = "gleam_crypto", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "50774BAFFF1144E7872814C566C5D653D83A3EBF23ACC3156B757A1B6819086E" }, - { name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" }, - { name = "gleam_fetch", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_javascript", "gleam_stdlib"], otp_app = "gleam_fetch", source = "hex", outer_checksum = "2CBF9F2E1C71AEBBFB13A9D5720CD8DB4263EB02FE60C5A7A1C6E17B0151C20C" }, - { name = "gleam_http", version = "4.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "82EA6A717C842456188C190AFB372665EA56CE13D8559BF3B1DD9E40F619EE0C" }, - { name = "gleam_httpc", version = "5.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "C545172618D07811494E97AAA4A0FB34DA6F6D0061FDC8041C2F8E3BE2B2E48F" }, - { name = "gleam_javascript", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_javascript", source = "hex", outer_checksum = "EF6C77A506F026C6FB37941889477CD5E4234FCD4337FF0E9384E297CB8F97EB" }, - { name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" }, - { name = "gleam_otp", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "BA6A294E295E428EC1562DC1C11EA7530DCB981E8359134BEABC8493B7B2258E" }, - { name = "gleam_regexp", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "9C215C6CA84A5B35BB934A9B61A9A306EC743153BE2B0425A0D032E477B062A9" }, - { name = "gleam_stdlib", version = "0.65.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "7C69C71D8C493AE11A5184828A77110EB05A7786EBF8B25B36A72F879C3EE107" }, - { name = "gleam_time", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "D560E672C7279C89908981E068DF07FD16D0C859DCA266F908B18F04DF0EB8E6" }, - { name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" }, - { name = "gleeunit", version = "1.9.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "DA9553CE58B67924B3C631F96FE3370C49EB6D6DC6B384EC4862CC4AAA718F3C" }, - { name = "glint", version = "1.2.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "2214C7CEFDE457CEE62140C3D4899B964E05236DA74E4243DFADF4AF29C382BB" }, - { name = "glisten", version = "8.0.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging", "telemetry"], otp_app = "glisten", source = "hex", outer_checksum = "534BB27C71FB9E506345A767C0D76B17A9E9199934340C975DC003C710E3692D" }, - { name = "gramps", version = "6.0.0", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "8B7195978FBFD30B43DF791A8A272041B81E45D245314D7A41FC57237AA882A0" }, - { name = "group_registry", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "group_registry", source = "hex", outer_checksum = "BC798A53D6F2406DB94E27CB45C57052CB56B32ACF7CC16EA20F6BAEC7E36B90" }, - { name = "houdini", version = "1.2.0", build_tools = ["gleam"], requirements = [], otp_app = "houdini", source = "hex", outer_checksum = "5DB1053F1AF828049C2B206D4403C18970ABEF5C18671CA3C2D2ED0DD64F6385" }, - { name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" }, - { name = "justin", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "7FA0C6DB78640C6DC5FBFD59BF3456009F3F8B485BF6825E97E1EB44E9A1E2CD" }, - { name = "logging", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "1098FBF10B54B44C2C7FDF0B01C1253CAFACDACABEFB4B0D027803246753E06D" }, - { name = "lustre", version = "5.4.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib", "houdini"], otp_app = "lustre", source = "hex", outer_checksum = "40E097BABCE65FB7C460C073078611F7F5802EB07E1A9BFB5C229F71B60F8E50" }, - { name = "lustre_dev_tools", version = "2.2.2", build_tools = ["gleam"], requirements = ["argv", "booklet", "filepath", "gleam_community_ansi", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_httpc", "gleam_json", "gleam_otp", "gleam_regexp", "gleam_stdlib", "glint", "group_registry", "justin", "lustre", "mist", "polly", "simplifile", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "C66A09B0B268B596F021971E4E4111E4B2B4A1DF5BDFE6C28A1E1FE4CA371F1A" }, - { name = "marceau", version = "1.3.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "2D1C27504BEF45005F5DFB18591F8610FB4BFA91744878210BDC464412EC44E9" }, - { name = "mist", version = "5.0.3", build_tools = ["gleam"], requirements = ["exception", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "gleam_yielder", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "7C4BE717A81305323C47C8A591E6B9BA4AC7F56354BF70B4D3DF08CC01192668" }, - { name = "modem", version = "2.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib", "lustre"], otp_app = "modem", source = "hex", outer_checksum = "3F9682EBCBF4D26045F1038A7507E8C7967E49D43F9CA6BA68EF0C971B195A7F" }, - { name = "platform", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "platform", source = "hex", outer_checksum = "8339420A95AD89AAC0F82F4C3DB8DD401041742D6C3F46132A8739F6AEB75391" }, - { name = "polly", version = "2.1.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib", "simplifile"], otp_app = "polly", source = "hex", outer_checksum = "1BA4D0ACE9BCF52AEA6AD9DE020FD8220CCA399A379E50A1775FC5C1204FCF56" }, - { name = "simplifile", version = "2.3.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "957E0E5B75927659F1D2A1B7B75D7B9BA96FAA8D0C53EA71C4AD9CD0C6B848F6" }, - { name = "snag", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "274F41D6C3ECF99F7686FDCE54183333E41D2C1CA5A3A673F9A8B2C7A4401077" }, - { name = "squall", version = "1.0.1", build_tools = ["gleam"], requirements = ["argv", "filepath", "glam", "gleam_http", "gleam_httpc", "gleam_json", "gleam_stdlib", "simplifile", "swell"], source = "local", path = "../.." }, - { name = "squall_cache", version = "0.1.0", build_tools = ["gleam"], requirements = ["gleam_fetch", "gleam_http", "gleam_javascript", "gleam_json", "gleam_stdlib", "lustre", "squall"], source = "local", path = "../../../squall_cache" }, - { name = "swell", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "swell", source = "hex", outer_checksum = "CA28A95AB9A01E51D1FCFC0FC4F7102C7F47D04B9711138248D08C2A9F1FE6A3" }, - { name = "telemetry", version = "1.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "telemetry", source = "hex", outer_checksum = "7015FC8919DBE63764F4B4B87A95B7C0996BD539E0D499BE6EC9D7F3875B79E6" }, - { name = "tom", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_time"], otp_app = "tom", source = "hex", outer_checksum = "74D0C5A3761F7A7D06994755D4D5AD854122EF8E9F9F76A3E7547606D8C77091" }, - { name = "wisp", version = "2.1.0", build_tools = ["gleam"], requirements = ["directories", "exception", "filepath", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "houdini", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "362BDDD11BF48EB38CDE51A73BC7D1B89581B395CA998E3F23F11EC026151C54" }, -] - -[requirements] -gleam_json = { version = ">= 3.0.0 and < 4.0.0" } -gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } -gleeunit = { version = ">= 1.0.0 and < 2.0.0" } -lustre = { version = ">= 5.0.0 and < 6.0.0" } -lustre_dev_tools = { version = ">= 2.2.2 and < 3.0.0" } -modem = { version = ">= 2.0.0 and < 3.0.0" } -squall = { path = "../../" } -squall_cache = { path = "../../../squall_cache" } -gleam_http = { version = ">= 4.3.0 and < 5.0.0" } diff --git a/examples/03-unstable-cache/src/cache_example.gleam b/examples/03-unstable-cache/src/cache_example.gleam deleted file mode 100644 index a21b4bd..0000000 --- a/examples/03-unstable-cache/src/cache_example.gleam +++ /dev/null @@ -1,316 +0,0 @@ -import components/character_detail -import components/character_list -import components/episode_list -import components/location_list -import generated/queries -import generated/queries/get_character -import generated/queries/get_characters -import generated/queries/get_episodes -import generated/queries/get_locations -import gleam/json.{type Json} -import gleam/string -import gleam/uri -import lustre -import lustre/attribute -import lustre/effect.{type Effect} -import lustre/element.{type Element} -import lustre/element/html -import modem -import squall/registry -import squall_cache - -pub fn main() { - let app = lustre.application(init, update, view) - let assert Ok(_) = lustre.start(app, "#app", Nil) -} - -// MODEL - -pub type Route { - Home - Characters - CharacterDetail(id: String) - Episodes - Locations -} - -pub type Model { - Model(cache: squall_cache.Cache, registry: registry.Registry, route: Route) -} - -fn init(_flags) -> #(Model, Effect(Msg)) { - // Create cache - optionally with headers for authentication - let cache = squall_cache.new("https://rickandmortyapi.com/graphql") - // To add headers (e.g., for authentication): - // let cache = squall_cache.new_with_headers(fn() { - // [#("Authorization", "Bearer " <> get_auth_token())] - // }) - - let reg = queries.init_registry() - - // Parse the initial route from the current URL - let initial_route = case modem.initial_uri() { - Ok(uri) -> parse_route(uri) - Error(_) -> Home - } - - // Determine what data needs to be fetched based on initial route - let #(initial_cache, data_effects) = case initial_route { - Characters -> { - let #(new_cache, _) = - squall_cache.lookup( - cache, - "GetCharacters", - json.object([]), - get_characters.parse_get_characters_response, - ) - let #(final_cache, fx) = - squall_cache.process_pending(new_cache, reg, HandleQueryResponse, fn() { - 0 - }) - #(final_cache, fx) - } - CharacterDetail(id) -> { - let variables = json.object([#("id", json.string(id))]) - let #(new_cache, _) = - squall_cache.lookup( - cache, - "GetCharacter", - variables, - get_character.parse_get_character_response, - ) - let #(final_cache, fx) = - squall_cache.process_pending(new_cache, reg, HandleQueryResponse, fn() { - 0 - }) - #(final_cache, fx) - } - Episodes -> { - let #(new_cache, _) = - squall_cache.lookup( - cache, - "GetEpisodes", - json.object([]), - get_episodes.parse_get_episodes_response, - ) - let #(final_cache, fx) = - squall_cache.process_pending(new_cache, reg, HandleQueryResponse, fn() { - 0 - }) - #(final_cache, fx) - } - Locations -> { - let #(new_cache, _) = - squall_cache.lookup( - cache, - "GetLocations", - json.object([]), - get_locations.parse_get_locations_response, - ) - let #(final_cache, fx) = - squall_cache.process_pending(new_cache, reg, HandleQueryResponse, fn() { - 0 - }) - #(final_cache, fx) - } - Home -> #(cache, []) - } - - // Combine modem effect with data fetching effects - let modem_effect = modem.init(on_url_change) - let combined_effects = effect.batch([modem_effect, ..data_effects]) - - #( - Model(cache: initial_cache, registry: reg, route: initial_route), - combined_effects, - ) -} - -// UPDATE - -pub type Msg { - HandleQueryResponse(String, Json, Result(String, String)) - OnRouteChange(Route) -} - -fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) { - case msg { - HandleQueryResponse(query_name, variables, Ok(response_body)) -> { - // Store response in cache as raw string with the correct variables - let cache_with_data = - squall_cache.store_query( - model.cache, - query_name, - variables, - response_body, - 0, - ) - - // Process any new pending fetches - let #(final_cache, effects) = - squall_cache.process_pending( - cache_with_data, - model.registry, - HandleQueryResponse, - fn() { 0 }, - ) - - #(Model(..model, cache: final_cache), effect.batch(effects)) - } - - HandleQueryResponse(_query_name, _variables, Error(_err)) -> { - #(model, effect.none()) - } - - OnRouteChange(route) -> { - // When route changes, trigger lookups for that route's data - let effects = case route { - Characters -> { - let #(new_cache, _result) = - squall_cache.lookup( - model.cache, - "GetCharacters", - json.object([]), - get_characters.parse_get_characters_response, - ) - let #(final_cache, fx) = - squall_cache.process_pending( - new_cache, - model.registry, - HandleQueryResponse, - fn() { 0 }, - ) - [#(final_cache, fx)] - } - CharacterDetail(id) -> { - let variables = json.object([#("id", json.string(id))]) - let #(new_cache, _result) = - squall_cache.lookup( - model.cache, - "GetCharacter", - variables, - get_character.parse_get_character_response, - ) - let #(final_cache, fx) = - squall_cache.process_pending( - new_cache, - model.registry, - HandleQueryResponse, - fn() { 0 }, - ) - [#(final_cache, fx)] - } - Episodes -> { - let #(new_cache, _result) = - squall_cache.lookup( - model.cache, - "GetEpisodes", - json.object([]), - get_episodes.parse_get_episodes_response, - ) - let #(final_cache, fx) = - squall_cache.process_pending( - new_cache, - model.registry, - HandleQueryResponse, - fn() { 0 }, - ) - [#(final_cache, fx)] - } - Locations -> { - let #(new_cache, _result) = - squall_cache.lookup( - model.cache, - "GetLocations", - json.object([]), - get_locations.parse_get_locations_response, - ) - let #(final_cache, fx) = - squall_cache.process_pending( - new_cache, - model.registry, - HandleQueryResponse, - fn() { 0 }, - ) - [#(final_cache, fx)] - } - Home -> [] - } - - case effects { - [#(final_cache, fx)] -> #( - Model(..model, cache: final_cache, route: route), - effect.batch(fx), - ) - _ -> #(Model(..model, route: route), effect.none()) - } - } - } -} - -// VIEW - -fn view(model: Model) -> Element(Msg) { - html.div([attribute.style("padding", "20px")], [ - html.h1([], [html.text("Rick and Morty API - Cached")]), - html.p([], [ - html.text( - "Navigate between pages - watch how cached data loads instantly!", - ), - ]), - // Navigation - html.nav([attribute.style("margin", "20px 0")], [ - html.a([attribute.href("/"), attribute.style("margin-right", "10px")], [ - html.text("Home"), - ]), - html.a( - [attribute.href("/characters"), attribute.style("margin-right", "10px")], - [html.text("Characters")], - ), - html.a( - [attribute.href("/episodes"), attribute.style("margin-right", "10px")], - [html.text("Episodes")], - ), - html.a([attribute.href("/locations")], [html.text("Locations")]), - ]), - html.hr([]), - // Route content - case model.route { - Home -> - html.div([], [ - html.h2([], [html.text("Welcome!")]), - html.p([], [ - html.text( - "Click the links above to explore. Notice how data loads instantly on revisit!", - ), - ]), - ]) - Characters -> character_list.view(model.cache) - CharacterDetail(id) -> character_detail.view(model.cache, id) - Episodes -> episode_list.view(model.cache) - Locations -> location_list.view(model.cache) - }, - ]) -} - -// ROUTING - -fn on_url_change(uri: uri.Uri) -> Msg { - OnRouteChange(parse_route(uri)) -} - -fn parse_route(uri: uri.Uri) -> Route { - case uri.path { - "/" -> Home - "/characters" -> Characters - "/episodes" -> Episodes - "/locations" -> Locations - _ -> { - // Try to parse /character/:id - case string.split(uri.path, "/") { - ["", "character", id] -> CharacterDetail(id) - _ -> Home - } - } - } -} diff --git a/examples/03-unstable-cache/src/components/character_detail.gleam b/examples/03-unstable-cache/src/components/character_detail.gleam deleted file mode 100644 index 6510bb4..0000000 --- a/examples/03-unstable-cache/src/components/character_detail.gleam +++ /dev/null @@ -1,100 +0,0 @@ -import generated/queries/get_character -import gleam/json -import gleam/option -import lustre/attribute -import lustre/element.{type Element} -import lustre/element/html -import squall_cache.{type Cache} - -/// Fetch a single character by ID from Rick and Morty API -/// -/// ```graphql -/// query GetCharacter($id: ID!) { -/// character(id: $id) { -/// id -/// name -/// status -/// species -/// type -/// gender -/// image -/// } -/// } -/// ``` -pub fn view(cache: Cache, id: String) -> Element(msg) { - let variables = json.object([#("id", json.string(id))]) - - let #(_cache, result) = - squall_cache.lookup( - cache, - "GetCharacter", - variables, - get_character.parse_get_character_response, - ) - - html.div([], [ - html.h2([], [html.text("Character Detail")]), - case result { - squall_cache.Loading -> html.p([], [html.text("Loading character...")]) - - squall_cache.Failed(message) -> - html.p([attribute.style("color", "red")], [ - html.text("Error: " <> message), - ]) - - squall_cache.Data(data) -> render_character(data) - }, - ]) -} - -fn render_character(data: get_character.GetCharacterResponse) -> Element(msg) { - case data.character { - option.None -> html.p([], [html.text("Character not found")]) - option.Some(char) -> { - html.div([attribute.style("max-width", "600px")], [ - html.div( - [ - attribute.style("display", "flex"), - attribute.style("gap", "20px"), - ], - [ - case char.image { - option.Some(img) -> - html.img([ - attribute.src(img), - attribute.style("width", "300px"), - attribute.style("border-radius", "8px"), - ]) - option.None -> html.div([], []) - }, - html.div([], [ - html.h3([], [ - html.text(char.name |> option.unwrap("Unknown")), - ]), - html.p([], [ - html.strong([], [html.text("Status: ")]), - html.text(char.status |> option.unwrap("Unknown")), - ]), - html.p([], [ - html.strong([], [html.text("Species: ")]), - html.text(char.species |> option.unwrap("Unknown")), - ]), - html.p([], [ - html.strong([], [html.text("Gender: ")]), - html.text(char.gender |> option.unwrap("Unknown")), - ]), - case char.type_ { - option.Some("") | option.None -> html.div([], []) - option.Some(type_) -> - html.p([], [ - html.strong([], [html.text("Type: ")]), - html.text(type_), - ]) - }, - ]), - ], - ), - ]) - } - } -} diff --git a/examples/03-unstable-cache/src/components/character_list.gleam b/examples/03-unstable-cache/src/components/character_list.gleam deleted file mode 100644 index 7ee66ea..0000000 --- a/examples/03-unstable-cache/src/components/character_list.gleam +++ /dev/null @@ -1,91 +0,0 @@ -import generated/queries/get_characters -import gleam/json -import gleam/list -import gleam/option -import lustre/attribute -import lustre/element.{type Element} -import lustre/element/html -import squall_cache.{type Cache} - -/// Fetch all characters from Rick and Morty API -/// -/// ```graphql -/// query GetCharacters { -/// characters { -/// results { -/// id -/// name -/// status -/// species -/// } -/// } -/// } -/// ``` -pub fn view(cache: Cache) -> Element(msg) { - // Just read from cache - fetching already happened in init - // Pass generated parser directly! - let #(_cache, result) = - squall_cache.lookup( - cache, - "GetCharacters", - json.object([]), - get_characters.parse_get_characters_response, - ) - - html.div([], [ - html.h2([], [html.text("Characters")]), - case result { - squall_cache.Loading -> html.p([], [html.text("Loading characters...")]) - - squall_cache.Failed(message) -> - html.p([attribute.style("color", "red")], [ - html.text("Error: " <> message), - ]) - - squall_cache.Data(data) -> render_characters(data) - }, - ]) -} - -fn render_characters(data: get_characters.GetCharactersResponse) -> Element(msg) { - case data.characters { - option.None -> html.p([], [html.text("No characters data")]) - option.Some(characters) -> - case characters.results { - option.None -> html.p([], [html.text("No results")]) - option.Some(results) -> { - html.ul( - [], - results - |> list.map(fn(char) { - html.li([attribute.style("margin", "10px 0")], [ - html.div([], [ - html.a( - [ - attribute.href( - "/character/" <> option.unwrap(char.id, ""), - ), - ], - [ - html.strong([], [ - html.text( - char.name - |> option.unwrap("Unknown"), - ), - ]), - ], - ), - html.text( - " - Status: " <> option.unwrap(char.status, "Unknown"), - ), - html.text( - ", Species: " <> option.unwrap(char.species, "Unknown"), - ), - ]), - ]) - }), - ) - } - } - } -} diff --git a/examples/03-unstable-cache/src/components/episode_list.gleam b/examples/03-unstable-cache/src/components/episode_list.gleam deleted file mode 100644 index a77d44a..0000000 --- a/examples/03-unstable-cache/src/components/episode_list.gleam +++ /dev/null @@ -1,84 +0,0 @@ -import generated/queries/get_episodes -import gleam/json -import gleam/list -import gleam/option -import lustre/attribute -import lustre/element.{type Element} -import lustre/element/html -import squall_cache.{type Cache} - -/// Fetch all episodes from Rick and Morty API -/// -/// ```graphql -/// query GetEpisodes { -/// episodes { -/// results { -/// id -/// name -/// air_date -/// episode -/// } -/// } -/// } -/// ``` -pub fn view(cache: Cache) -> Element(msg) { - let #(_cache, result) = - squall_cache.lookup( - cache, - "GetEpisodes", - json.object([]), - get_episodes.parse_get_episodes_response, - ) - - html.div([], [ - html.h2([], [html.text("Episodes")]), - case result { - squall_cache.Loading -> html.p([], [html.text("Loading episodes...")]) - - squall_cache.Failed(message) -> - html.p([attribute.style("color", "red")], [ - html.text("Error: " <> message), - ]) - - squall_cache.Data(data) -> render_episodes(data) - }, - ]) -} - -fn render_episodes(data: get_episodes.GetEpisodesResponse) -> Element(msg) { - case data.episodes { - option.None -> html.p([], [html.text("No episodes data")]) - option.Some(episodes) -> - case episodes.results { - option.None -> html.p([], [html.text("No results")]) - option.Some(results) -> { - html.ul( - [], - results - |> list.map(fn(ep) { - html.li([attribute.style("margin", "10px 0")], [ - html.div([], [ - html.strong([], [ - html.text( - ep.episode - |> option.unwrap(""), - ), - html.text(" - "), - html.text( - ep.name - |> option.unwrap("Unknown"), - ), - ]), - html.text( - " (Aired: " - <> option.unwrap(ep.air_date, "Unknown") - <> ")", - ), - ]), - ]) - }), - ) - } - } - } -} diff --git a/examples/03-unstable-cache/src/components/location_list.gleam b/examples/03-unstable-cache/src/components/location_list.gleam deleted file mode 100644 index 7c55a95..0000000 --- a/examples/03-unstable-cache/src/components/location_list.gleam +++ /dev/null @@ -1,80 +0,0 @@ -import generated/queries/get_locations -import gleam/json -import gleam/list -import gleam/option -import lustre/attribute -import lustre/element.{type Element} -import lustre/element/html -import squall_cache.{type Cache} - -/// Fetch all locations from Rick and Morty API -/// -/// ```graphql -/// query GetLocations { -/// locations { -/// results { -/// id -/// name -/// type -/// dimension -/// } -/// } -/// } -/// ``` -pub fn view(cache: Cache) -> Element(msg) { - let #(_cache, result) = - squall_cache.lookup( - cache, - "GetLocations", - json.object([]), - get_locations.parse_get_locations_response, - ) - - html.div([], [ - html.h2([], [html.text("Locations")]), - case result { - squall_cache.Loading -> html.p([], [html.text("Loading locations...")]) - - squall_cache.Failed(message) -> - html.p([attribute.style("color", "red")], [ - html.text("Error: " <> message), - ]) - - squall_cache.Data(data) -> render_locations(data) - }, - ]) -} - -fn render_locations(data: get_locations.GetLocationsResponse) -> Element(msg) { - case data.locations { - option.None -> html.p([], [html.text("No locations data")]) - option.Some(locations) -> - case locations.results { - option.None -> html.p([], [html.text("No results")]) - option.Some(results) -> { - html.ul( - [], - results - |> list.map(fn(loc) { - html.li([attribute.style("margin", "10px 0")], [ - html.div([], [ - html.strong([], [ - html.text( - loc.name - |> option.unwrap("Unknown"), - ), - ]), - html.text( - " - Type: " <> option.unwrap(loc.type_, "Unknown"), - ), - html.text( - ", Dimension: " <> option.unwrap(loc.dimension, "Unknown"), - ), - ]), - ]) - }), - ) - } - } - } -} diff --git a/examples/03-unstable-cache/src/generated/queries.gleam b/examples/03-unstable-cache/src/generated/queries.gleam deleted file mode 100644 index b52d104..0000000 --- a/examples/03-unstable-cache/src/generated/queries.gleam +++ /dev/null @@ -1,32 +0,0 @@ -import squall/registry - -/// Initialize the query registry with all extracted queries -/// This function is auto-generated by Squall -pub fn init_registry() -> registry.Registry { - let reg = registry.new() - let reg = registry.register( - reg, - "GetCharacter", - "query GetCharacter($id: ID!) {\n character(id: $id) {\n __typename\n id\n name\n status\n species\n type\n gender\n image\n }\n}", - "generated/queries/get_character", - ) - let reg = registry.register( - reg, - "GetCharacters", - "query GetCharacters {\n characters {\n __typename\n results {\n __typename\n id\n name\n status\n species\n }\n }\n}", - "generated/queries/get_characters", - ) - let reg = registry.register( - reg, - "GetLocations", - "query GetLocations {\n locations {\n __typename\n results {\n __typename\n id\n name\n type\n dimension\n }\n }\n}", - "generated/queries/get_locations", - ) - let reg = registry.register( - reg, - "GetEpisodes", - "query GetEpisodes {\n episodes {\n __typename\n results {\n __typename\n id\n name\n air_date\n episode\n }\n }\n}", - "generated/queries/get_episodes", - ) - reg -} \ No newline at end of file diff --git a/examples/03-unstable-cache/src/generated/queries/get_character.gleam b/examples/03-unstable-cache/src/generated/queries/get_character.gleam deleted file mode 100644 index 64521d0..0000000 --- a/examples/03-unstable-cache/src/generated/queries/get_character.gleam +++ /dev/null @@ -1,83 +0,0 @@ -import gleam/dynamic/decode -import gleam/http/request.{type Request} -import gleam/json -import squall -import gleam/option.{type Option} - -pub type Character { - Character( - typename: Option(String), - id: Option(String), - name: Option(String), - status: Option(String), - species: Option(String), - type_: Option(String), - gender: Option(String), - image: Option(String), - ) -} - -pub fn character_decoder() -> decode.Decoder(Character) { - use typename <- decode.field("__typename", decode.optional(decode.string)) - use id <- decode.field("id", decode.optional(decode.string)) - use name <- decode.field("name", decode.optional(decode.string)) - use status <- decode.field("status", decode.optional(decode.string)) - use species <- decode.field("species", decode.optional(decode.string)) - use type_ <- decode.field("type", decode.optional(decode.string)) - use gender <- decode.field("gender", decode.optional(decode.string)) - use image <- decode.field("image", decode.optional(decode.string)) - decode.success(Character( - typename: typename, - id: id, - name: name, - status: status, - species: species, - type_: type_, - gender: gender, - image: image, - )) -} - -pub fn character_to_json(input: Character) -> json.Json { - json.object( - [ - #("__typename", json.nullable(input.typename, json.string)), - #("id", json.nullable(input.id, json.string)), - #("name", json.nullable(input.name, json.string)), - #("status", json.nullable(input.status, json.string)), - #("species", json.nullable(input.species, json.string)), - #("type", json.nullable(input.type_, json.string)), - #("gender", json.nullable(input.gender, json.string)), - #("image", json.nullable(input.image, json.string)), - ], - ) -} - -pub type GetCharacterResponse { - GetCharacterResponse(character: Option(Character)) -} - -pub fn get_character_response_decoder() -> decode.Decoder(GetCharacterResponse) { - use character <- decode.field("character", decode.optional(character_decoder())) - decode.success(GetCharacterResponse(character: character)) -} - -pub fn get_character_response_to_json(input: GetCharacterResponse) -> json.Json { - json.object( - [ - #("character", json.nullable(input.character, character_to_json)), - ], - ) -} - -pub fn get_character(client: squall.Client, id: String) -> Result(Request(String), String) { - squall.prepare_request( - client, - "query GetCharacter($id: ID!) {\n character(id: $id) {\n __typename\n id\n name\n status\n species\n type\n gender\n image\n }\n}", - json.object([#("id", json.string(id))]), - ) -} - -pub fn parse_get_character_response(body: String) -> Result(GetCharacterResponse, String) { - squall.parse_response(body, get_character_response_decoder()) -} diff --git a/examples/03-unstable-cache/src/generated/queries/get_characters.gleam b/examples/03-unstable-cache/src/generated/queries/get_characters.gleam deleted file mode 100644 index aab5329..0000000 --- a/examples/03-unstable-cache/src/generated/queries/get_characters.gleam +++ /dev/null @@ -1,93 +0,0 @@ -import gleam/dynamic/decode -import gleam/http/request.{type Request} -import gleam/json -import squall -import gleam/option.{type Option} - -pub type Characters { - Characters(typename: Option(String), results: Option(List(Character))) -} - -pub fn characters_decoder() -> decode.Decoder(Characters) { - use typename <- decode.field("__typename", decode.optional(decode.string)) - use results <- decode.field("results", decode.optional(decode.list(character_decoder()))) - decode.success(Characters(typename: typename, results: results)) -} - -pub type Character { - Character( - typename: Option(String), - id: Option(String), - name: Option(String), - status: Option(String), - species: Option(String), - ) -} - -pub fn character_decoder() -> decode.Decoder(Character) { - use typename <- decode.field("__typename", decode.optional(decode.string)) - use id <- decode.field("id", decode.optional(decode.string)) - use name <- decode.field("name", decode.optional(decode.string)) - use status <- decode.field("status", decode.optional(decode.string)) - use species <- decode.field("species", decode.optional(decode.string)) - decode.success(Character( - typename: typename, - id: id, - name: name, - status: status, - species: species, - )) -} - -pub fn characters_to_json(input: Characters) -> json.Json { - json.object( - [ - #("__typename", json.nullable(input.typename, json.string)), - #("results", json.nullable( - input.results, - fn(list) { json.array(from: list, of: character_to_json) }, - )), - ], - ) -} - -pub fn character_to_json(input: Character) -> json.Json { - json.object( - [ - #("__typename", json.nullable(input.typename, json.string)), - #("id", json.nullable(input.id, json.string)), - #("name", json.nullable(input.name, json.string)), - #("status", json.nullable(input.status, json.string)), - #("species", json.nullable(input.species, json.string)), - ], - ) -} - -pub type GetCharactersResponse { - GetCharactersResponse(characters: Option(Characters)) -} - -pub fn get_characters_response_decoder() -> decode.Decoder(GetCharactersResponse) { - use characters <- decode.field("characters", decode.optional(characters_decoder())) - decode.success(GetCharactersResponse(characters: characters)) -} - -pub fn get_characters_response_to_json(input: GetCharactersResponse) -> json.Json { - json.object( - [ - #("characters", json.nullable(input.characters, characters_to_json)), - ], - ) -} - -pub fn get_characters(client: squall.Client) -> Result(Request(String), String) { - squall.prepare_request( - client, - "query GetCharacters {\n characters {\n __typename\n results {\n __typename\n id\n name\n status\n species\n }\n }\n}", - json.object([]), - ) -} - -pub fn parse_get_characters_response(body: String) -> Result(GetCharactersResponse, String) { - squall.parse_response(body, get_characters_response_decoder()) -} diff --git a/examples/03-unstable-cache/src/generated/queries/get_episodes.gleam b/examples/03-unstable-cache/src/generated/queries/get_episodes.gleam deleted file mode 100644 index 97d5cfa..0000000 --- a/examples/03-unstable-cache/src/generated/queries/get_episodes.gleam +++ /dev/null @@ -1,89 +0,0 @@ -import gleam/dynamic/decode -import gleam/http/request.{type Request} -import gleam/json -import squall -import gleam/option.{type Option} - -pub type Episodes { - Episodes(typename: Option(String), results: Option(List(Episode))) -} - -pub fn episodes_decoder() -> decode.Decoder(Episodes) { - use typename <- decode.field("__typename", decode.optional(decode.string)) - use results <- decode.field("results", decode.optional(decode.list(episode_decoder()))) - decode.success(Episodes(typename: typename, results: results)) -} - -pub type Episode { - Episode( - typename: Option(String), - id: Option(String), - name: Option(String), - air_date: Option(String), - episode: Option(String), - ) -} - -pub fn episode_decoder() -> decode.Decoder(Episode) { - use typename <- decode.field("__typename", decode.optional(decode.string)) - use id <- decode.field("id", decode.optional(decode.string)) - use name <- decode.field("name", decode.optional(decode.string)) - use air_date <- decode.field("air_date", decode.optional(decode.string)) - use episode <- decode.field("episode", decode.optional(decode.string)) - decode.success(Episode( - typename: typename, - id: id, - name: name, - air_date: air_date, - episode: episode, - )) -} - -pub fn episodes_to_json(input: Episodes) -> json.Json { - json.object( - [ - #("__typename", json.nullable(input.typename, json.string)), - #("results", json.nullable( - input.results, - fn(list) { json.array(from: list, of: episode_to_json) }, - )), - ], - ) -} - -pub fn episode_to_json(input: Episode) -> json.Json { - json.object( - [ - #("__typename", json.nullable(input.typename, json.string)), - #("id", json.nullable(input.id, json.string)), - #("name", json.nullable(input.name, json.string)), - #("air_date", json.nullable(input.air_date, json.string)), - #("episode", json.nullable(input.episode, json.string)), - ], - ) -} - -pub type GetEpisodesResponse { - GetEpisodesResponse(episodes: Option(Episodes)) -} - -pub fn get_episodes_response_decoder() -> decode.Decoder(GetEpisodesResponse) { - use episodes <- decode.field("episodes", decode.optional(episodes_decoder())) - decode.success(GetEpisodesResponse(episodes: episodes)) -} - -pub fn get_episodes_response_to_json(input: GetEpisodesResponse) -> json.Json { - json.object([#("episodes", json.nullable(input.episodes, episodes_to_json))]) -} - -pub fn get_episodes(client: squall.Client) -> Result(Request(String), String) { - squall.prepare_request( - client, - "query GetEpisodes {\n episodes {\n __typename\n results {\n __typename\n id\n name\n air_date\n episode\n }\n }\n}", - json.object([]), - ) -} - -pub fn parse_get_episodes_response(body: String) -> Result(GetEpisodesResponse, String) { - squall.parse_response(body, get_episodes_response_decoder()) -} diff --git a/examples/03-unstable-cache/src/generated/queries/get_locations.gleam b/examples/03-unstable-cache/src/generated/queries/get_locations.gleam deleted file mode 100644 index dd811a7..0000000 --- a/examples/03-unstable-cache/src/generated/queries/get_locations.gleam +++ /dev/null @@ -1,93 +0,0 @@ -import gleam/dynamic/decode -import gleam/http/request.{type Request} -import gleam/json -import squall -import gleam/option.{type Option} - -pub type Locations { - Locations(typename: Option(String), results: Option(List(Location))) -} - -pub fn locations_decoder() -> decode.Decoder(Locations) { - use typename <- decode.field("__typename", decode.optional(decode.string)) - use results <- decode.field("results", decode.optional(decode.list(location_decoder()))) - decode.success(Locations(typename: typename, results: results)) -} - -pub type Location { - Location( - typename: Option(String), - id: Option(String), - name: Option(String), - type_: Option(String), - dimension: Option(String), - ) -} - -pub fn location_decoder() -> decode.Decoder(Location) { - use typename <- decode.field("__typename", decode.optional(decode.string)) - use id <- decode.field("id", decode.optional(decode.string)) - use name <- decode.field("name", decode.optional(decode.string)) - use type_ <- decode.field("type", decode.optional(decode.string)) - use dimension <- decode.field("dimension", decode.optional(decode.string)) - decode.success(Location( - typename: typename, - id: id, - name: name, - type_: type_, - dimension: dimension, - )) -} - -pub fn locations_to_json(input: Locations) -> json.Json { - json.object( - [ - #("__typename", json.nullable(input.typename, json.string)), - #("results", json.nullable( - input.results, - fn(list) { json.array(from: list, of: location_to_json) }, - )), - ], - ) -} - -pub fn location_to_json(input: Location) -> json.Json { - json.object( - [ - #("__typename", json.nullable(input.typename, json.string)), - #("id", json.nullable(input.id, json.string)), - #("name", json.nullable(input.name, json.string)), - #("type", json.nullable(input.type_, json.string)), - #("dimension", json.nullable(input.dimension, json.string)), - ], - ) -} - -pub type GetLocationsResponse { - GetLocationsResponse(locations: Option(Locations)) -} - -pub fn get_locations_response_decoder() -> decode.Decoder(GetLocationsResponse) { - use locations <- decode.field("locations", decode.optional(locations_decoder())) - decode.success(GetLocationsResponse(locations: locations)) -} - -pub fn get_locations_response_to_json(input: GetLocationsResponse) -> json.Json { - json.object( - [ - #("locations", json.nullable(input.locations, locations_to_json)), - ], - ) -} - -pub fn get_locations(client: squall.Client) -> Result(Request(String), String) { - squall.prepare_request( - client, - "query GetLocations {\n locations {\n __typename\n results {\n __typename\n id\n name\n type\n dimension\n }\n }\n}", - json.object([]), - ) -} - -pub fn parse_get_locations_response(body: String) -> Result(GetLocationsResponse, String) { - squall.parse_response(body, get_locations_response_decoder()) -} diff --git a/examples/03-unstable-cache/src/graphql/get_character.gleam b/examples/03-unstable-cache/src/graphql/get_character.gleam deleted file mode 100644 index 8d99394..0000000 --- a/examples/03-unstable-cache/src/graphql/get_character.gleam +++ /dev/null @@ -1,79 +0,0 @@ -import gleam/dynamic/decode -import gleam/http/request.{type Request} -import gleam/json -import squall -import gleam/option.{type Option} - -pub type Character { - Character( - id: Option(String), - name: Option(String), - status: Option(String), - species: Option(String), - type_: Option(String), - gender: Option(String), - image: Option(String), - ) -} - -pub fn character_decoder() -> decode.Decoder(Character) { - use id <- decode.field("id", decode.optional(decode.string)) - use name <- decode.field("name", decode.optional(decode.string)) - use status <- decode.field("status", decode.optional(decode.string)) - use species <- decode.field("species", decode.optional(decode.string)) - use type_ <- decode.field("type", decode.optional(decode.string)) - use gender <- decode.field("gender", decode.optional(decode.string)) - use image <- decode.field("image", decode.optional(decode.string)) - decode.success(Character( - id: id, - name: name, - status: status, - species: species, - type_: type_, - gender: gender, - image: image, - )) -} - -pub fn character_to_json(input: Character) -> json.Json { - json.object( - [ - #("id", json.nullable(input.id, json.string)), - #("name", json.nullable(input.name, json.string)), - #("status", json.nullable(input.status, json.string)), - #("species", json.nullable(input.species, json.string)), - #("type", json.nullable(input.type_, json.string)), - #("gender", json.nullable(input.gender, json.string)), - #("image", json.nullable(input.image, json.string)), - ], - ) -} - -pub type GetCharacterResponse { - GetCharacterResponse(character: Option(Character)) -} - -pub fn get_character_response_decoder() -> decode.Decoder(GetCharacterResponse) { - use character <- decode.field("character", decode.optional(character_decoder())) - decode.success(GetCharacterResponse(character: character)) -} - -pub fn get_character_response_to_json(input: GetCharacterResponse) -> json.Json { - json.object( - [ - #("character", json.nullable(input.character, character_to_json)), - ], - ) -} - -pub fn get_character(client: squall.Client, id: String) -> Result(Request(String), String) { - squall.prepare_request( - client, - "query GetCharacter($id: ID!) {\n character(id: $id) {\n id\n name\n status\n species\n type\n gender\n image\n }\n}\n", - json.object([#("id", json.string(id))]), - ) -} - -pub fn parse_get_character_response(body: String) -> Result(GetCharacterResponse, String) { - squall.parse_response(body, get_character_response_decoder()) -} diff --git a/examples/03-unstable-cache/src/graphql/get_character.gql b/examples/03-unstable-cache/src/graphql/get_character.gql deleted file mode 100644 index 4676e00..0000000 --- a/examples/03-unstable-cache/src/graphql/get_character.gql +++ /dev/null @@ -1,11 +0,0 @@ -query GetCharacter($id: ID!) { - character(id: $id) { - id - name - status - species - type - gender - image - } -} diff --git a/examples/03-unstable-cache/src/graphql/get_characters.gleam b/examples/03-unstable-cache/src/graphql/get_characters.gleam deleted file mode 100644 index 925cf72..0000000 --- a/examples/03-unstable-cache/src/graphql/get_characters.gleam +++ /dev/null @@ -1,82 +0,0 @@ -import gleam/dynamic/decode -import gleam/http/request.{type Request} -import gleam/json -import squall -import gleam/option.{type Option} - -pub type Characters { - Characters(results: Option(List(Character))) -} - -pub fn characters_decoder() -> decode.Decoder(Characters) { - use results <- decode.field("results", decode.optional(decode.list(character_decoder()))) - decode.success(Characters(results: results)) -} - -pub type Character { - Character( - id: Option(String), - name: Option(String), - status: Option(String), - species: Option(String), - ) -} - -pub fn character_decoder() -> decode.Decoder(Character) { - use id <- decode.field("id", decode.optional(decode.string)) - use name <- decode.field("name", decode.optional(decode.string)) - use status <- decode.field("status", decode.optional(decode.string)) - use species <- decode.field("species", decode.optional(decode.string)) - decode.success(Character(id: id, name: name, status: status, species: species)) -} - -pub fn characters_to_json(input: Characters) -> json.Json { - json.object( - [ - #("results", json.nullable( - input.results, - fn(list) { json.array(from: list, of: character_to_json) }, - )), - ], - ) -} - -pub fn character_to_json(input: Character) -> json.Json { - json.object( - [ - #("id", json.nullable(input.id, json.string)), - #("name", json.nullable(input.name, json.string)), - #("status", json.nullable(input.status, json.string)), - #("species", json.nullable(input.species, json.string)), - ], - ) -} - -pub type GetCharactersResponse { - GetCharactersResponse(characters: Option(Characters)) -} - -pub fn get_characters_response_decoder() -> decode.Decoder(GetCharactersResponse) { - use characters <- decode.field("characters", decode.optional(characters_decoder())) - decode.success(GetCharactersResponse(characters: characters)) -} - -pub fn get_characters_response_to_json(input: GetCharactersResponse) -> json.Json { - json.object( - [ - #("characters", json.nullable(input.characters, characters_to_json)), - ], - ) -} - -pub fn get_characters(client: squall.Client) -> Result(Request(String), String) { - squall.prepare_request( - client, - "query GetCharacters {\n characters {\n results {\n id\n name\n status\n species\n }\n }\n}\n", - json.object([]), - ) -} - -pub fn parse_get_characters_response(body: String) -> Result(GetCharactersResponse, String) { - squall.parse_response(body, get_characters_response_decoder()) -} diff --git a/examples/03-unstable-cache/src/graphql/get_characters.gql b/examples/03-unstable-cache/src/graphql/get_characters.gql deleted file mode 100644 index 4269012..0000000 --- a/examples/03-unstable-cache/src/graphql/get_characters.gql +++ /dev/null @@ -1,10 +0,0 @@ -query GetCharacters { - characters { - results { - id - name - status - species - } - } -} diff --git a/examples/03-unstable-cache/src/graphql/get_episodes.gleam b/examples/03-unstable-cache/src/graphql/get_episodes.gleam deleted file mode 100644 index 268d978..0000000 --- a/examples/03-unstable-cache/src/graphql/get_episodes.gleam +++ /dev/null @@ -1,83 +0,0 @@ -import gleam/dynamic/decode -import gleam/http/request.{type Request} -import gleam/json -import squall -import gleam/option.{type Option} - -pub type Episodes { - Episodes(results: Option(List(Episode))) -} - -pub fn episodes_decoder() -> decode.Decoder(Episodes) { - use results <- decode.field("results", decode.optional(decode.list(episode_decoder()))) - decode.success(Episodes(results: results)) -} - -pub type Episode { - Episode( - id: Option(String), - name: Option(String), - air_date: Option(String), - episode: Option(String), - ) -} - -pub fn episode_decoder() -> decode.Decoder(Episode) { - use id <- decode.field("id", decode.optional(decode.string)) - use name <- decode.field("name", decode.optional(decode.string)) - use air_date <- decode.field("air_date", decode.optional(decode.string)) - use episode <- decode.field("episode", decode.optional(decode.string)) - decode.success(Episode( - id: id, - name: name, - air_date: air_date, - episode: episode, - )) -} - -pub fn episodes_to_json(input: Episodes) -> json.Json { - json.object( - [ - #("results", json.nullable( - input.results, - fn(list) { json.array(from: list, of: episode_to_json) }, - )), - ], - ) -} - -pub fn episode_to_json(input: Episode) -> json.Json { - json.object( - [ - #("id", json.nullable(input.id, json.string)), - #("name", json.nullable(input.name, json.string)), - #("air_date", json.nullable(input.air_date, json.string)), - #("episode", json.nullable(input.episode, json.string)), - ], - ) -} - -pub type GetEpisodesResponse { - GetEpisodesResponse(episodes: Option(Episodes)) -} - -pub fn get_episodes_response_decoder() -> decode.Decoder(GetEpisodesResponse) { - use episodes <- decode.field("episodes", decode.optional(episodes_decoder())) - decode.success(GetEpisodesResponse(episodes: episodes)) -} - -pub fn get_episodes_response_to_json(input: GetEpisodesResponse) -> json.Json { - json.object([#("episodes", json.nullable(input.episodes, episodes_to_json))]) -} - -pub fn get_episodes(client: squall.Client) -> Result(Request(String), String) { - squall.prepare_request( - client, - "query GetEpisodes {\n episodes {\n results {\n id\n name\n air_date\n episode\n }\n }\n}\n", - json.object([]), - ) -} - -pub fn parse_get_episodes_response(body: String) -> Result(GetEpisodesResponse, String) { - squall.parse_response(body, get_episodes_response_decoder()) -} diff --git a/examples/03-unstable-cache/src/graphql/get_episodes.gql b/examples/03-unstable-cache/src/graphql/get_episodes.gql deleted file mode 100644 index 9d7db29..0000000 --- a/examples/03-unstable-cache/src/graphql/get_episodes.gql +++ /dev/null @@ -1,10 +0,0 @@ -query GetEpisodes { - episodes { - results { - id - name - air_date - episode - } - } -} diff --git a/examples/03-unstable-cache/src/graphql/get_locations.gleam b/examples/03-unstable-cache/src/graphql/get_locations.gleam deleted file mode 100644 index e9fd807..0000000 --- a/examples/03-unstable-cache/src/graphql/get_locations.gleam +++ /dev/null @@ -1,87 +0,0 @@ -import gleam/dynamic/decode -import gleam/http/request.{type Request} -import gleam/json -import squall -import gleam/option.{type Option} - -pub type Locations { - Locations(results: Option(List(Location))) -} - -pub fn locations_decoder() -> decode.Decoder(Locations) { - use results <- decode.field("results", decode.optional(decode.list(location_decoder()))) - decode.success(Locations(results: results)) -} - -pub type Location { - Location( - id: Option(String), - name: Option(String), - type_: Option(String), - dimension: Option(String), - ) -} - -pub fn location_decoder() -> decode.Decoder(Location) { - use id <- decode.field("id", decode.optional(decode.string)) - use name <- decode.field("name", decode.optional(decode.string)) - use type_ <- decode.field("type", decode.optional(decode.string)) - use dimension <- decode.field("dimension", decode.optional(decode.string)) - decode.success(Location( - id: id, - name: name, - type_: type_, - dimension: dimension, - )) -} - -pub fn locations_to_json(input: Locations) -> json.Json { - json.object( - [ - #("results", json.nullable( - input.results, - fn(list) { json.array(from: list, of: location_to_json) }, - )), - ], - ) -} - -pub fn location_to_json(input: Location) -> json.Json { - json.object( - [ - #("id", json.nullable(input.id, json.string)), - #("name", json.nullable(input.name, json.string)), - #("type", json.nullable(input.type_, json.string)), - #("dimension", json.nullable(input.dimension, json.string)), - ], - ) -} - -pub type GetLocationsResponse { - GetLocationsResponse(locations: Option(Locations)) -} - -pub fn get_locations_response_decoder() -> decode.Decoder(GetLocationsResponse) { - use locations <- decode.field("locations", decode.optional(locations_decoder())) - decode.success(GetLocationsResponse(locations: locations)) -} - -pub fn get_locations_response_to_json(input: GetLocationsResponse) -> json.Json { - json.object( - [ - #("locations", json.nullable(input.locations, locations_to_json)), - ], - ) -} - -pub fn get_locations(client: squall.Client) -> Result(Request(String), String) { - squall.prepare_request( - client, - "query GetLocations {\n locations {\n results {\n id\n name\n type\n dimension\n }\n }\n}\n", - json.object([]), - ) -} - -pub fn parse_get_locations_response(body: String) -> Result(GetLocationsResponse, String) { - squall.parse_response(body, get_locations_response_decoder()) -} diff --git a/examples/03-unstable-cache/src/graphql/get_locations.gql b/examples/03-unstable-cache/src/graphql/get_locations.gql deleted file mode 100644 index 48e7f63..0000000 --- a/examples/03-unstable-cache/src/graphql/get_locations.gql +++ /dev/null @@ -1,10 +0,0 @@ -query GetLocations { - locations { - results { - id - name - type - dimension - } - } -} diff --git a/examples/03-unstable-cache/test/cache_example_test.gleam b/examples/03-unstable-cache/test/cache_example_test.gleam deleted file mode 100644 index fba3c88..0000000 --- a/examples/03-unstable-cache/test/cache_example_test.gleam +++ /dev/null @@ -1,13 +0,0 @@ -import gleeunit - -pub fn main() -> Nil { - gleeunit.main() -} - -// gleeunit test functions end in `_test` -pub fn hello_world_test() { - let name = "Joe" - let greeting = "Hello, " <> name <> "!" - - assert greeting == "Hello, Joe!" -} diff --git a/gleam.toml b/gleam.toml index ac5d02d..6d9a1de 100644 --- a/gleam.toml +++ b/gleam.toml @@ -1,5 +1,5 @@ name = "squall" -version = "1.1.0" +version = "1.1.1" description = "☁️ Type-safe GraphQL client generator for Gleam" licences = ["Apache-2.0"] repository = { type = "github", user = "bigmoves", repo = "squall" } diff --git a/src/squall/internal/registry_codegen.gleam b/src/squall/internal/registry_codegen.gleam index 980cf85..0d1cc59 100644 --- a/src/squall/internal/registry_codegen.gleam +++ b/src/squall/internal/registry_codegen.gleam @@ -11,7 +11,7 @@ pub fn generate_registry_module(queries: List(QueryDefinition)) -> String { } fn generate_imports() -> String { - "import squall/registry" + "import squall/unstable_registry" } fn generate_init_function(queries: List(QueryDefinition)) -> String { @@ -20,8 +20,8 @@ fn generate_init_function(queries: List(QueryDefinition)) -> String { "/// Initialize the query registry with all extracted queries /// This function is auto-generated by Squall -pub fn init_registry() -> registry.Registry { - let reg = registry.new() +pub fn init_registry() -> unstable_registry.Registry { + let reg = unstable_registry.new() " <> registrations_code <> " reg }" @@ -31,7 +31,7 @@ fn generate_registration(query: QueryDefinition) -> String { let module_path = "generated/queries/" <> to_snake_case(query.name) let escaped_query = escape_string(query.query) - "let reg = registry.register( + "let reg = unstable_registry.register( reg, \"" <> query.name <> "\", \"" <> escaped_query <> "\", diff --git a/src/squall/registry.gleam b/src/squall/unstable_registry.gleam similarity index 100% rename from src/squall/registry.gleam rename to src/squall/unstable_registry.gleam -- 2.51.2