|
| 1 | +Change log |
| 2 | +========== |
| 3 | + |
| 4 | +## 0.6.0 – Unreleased |
| 5 | + |
| 6 | +TL;DR: Many big changes in how context types work and how they |
| 7 | +interact with the executor. Not too much to worry about if you're only |
| 8 | +using the macros and not deriving `GraphQLType` directly. |
| 9 | + |
| 10 | +### Breaking changes |
| 11 | + |
| 12 | +* The `executor` argument in all resolver methods is now |
| 13 | + immutable. The executor instead uses interior mutability to store |
| 14 | + errors in a thread-safe manner. |
| 15 | + |
| 16 | + This change could open up for asynchronous or multi-threaded |
| 17 | + execution: you can today use something like rayon in your resolve |
| 18 | + methods to let child nodes be concurrently resolved. |
| 19 | + |
| 20 | + **How to fix:** All field resolvers that looked like `field |
| 21 | + name(&mut executor` now should say `field name(&executor`. |
| 22 | + |
| 23 | +* The context type of `GraphQLType` is moved to an associated type; |
| 24 | + meaning it's no longer generic. This only affects people who |
| 25 | + implement the trait manually, _not_ macro users. |
| 26 | + |
| 27 | + This greatly simplifies a lot of code by ensuring that there only |
| 28 | + can be one `GraphQLType` implementation for any given Rust |
| 29 | + type. However, it has the downside that support for generic contexts |
| 30 | + previously used in scalars, has been removed. Instead, use the new |
| 31 | + context conversion features to accomplish the same task. |
| 32 | + |
| 33 | + **How to fix:** Instead of `impl GraphQLType<MyContext> for ...`, |
| 34 | + you use `impl GraphQLType for ... { type Context = MyContext;`. |
| 35 | + |
| 36 | +* All context types must derive the `Context` marker trait. This is |
| 37 | + part of an overarching change to allow different types to use |
| 38 | + different contexts. |
| 39 | + |
| 40 | + **How to fix:** If you have written e.g. `graphql_object!(MyType: |
| 41 | + MyContext ...)` you will need to add `impl Context for MyContext |
| 42 | + {}`. Simple as that. |
| 43 | + |
| 44 | + |
| 45 | +### Added |
| 46 | + |
| 47 | +* Support for different contexts for different types. As GraphQL |
| 48 | + schemas tend to get large, narrowing down the context type to |
| 49 | + exactly what a given type needs is great for |
| 50 | + encapsulation. Similarly, letting different subsystems use different |
| 51 | + resources thorugh the context is also useful for the same reasons. |
| 52 | + |
| 53 | + Juniper supports two different methods of doing this, depending on |
| 54 | + your needs: if you have two contexts where one can be converted into |
| 55 | + the other _without any extra knowledge_, you can implement the new |
| 56 | + `FromContext` trait. This is useful if you have multiple crates or |
| 57 | + modules that all belong to the same GraphQL schema: |
| 58 | + |
| 59 | + ```rust |
| 60 | + |
| 61 | + struct TopContext { |
| 62 | + db: DatabaseConnection, |
| 63 | + session: WebSession, |
| 64 | + current_user: User, |
| 65 | + } |
| 66 | + |
| 67 | + struct ModuleOneContext { |
| 68 | + db: DatabaseConnection, // This module only requires a database connection |
| 69 | + } |
| 70 | + |
| 71 | + impl Context for TopContext {} |
| 72 | + impl Context for ModuleOneContext {} |
| 73 | + |
| 74 | + impl FromContext<TopContext> for ModuleOneContext { |
| 75 | + fn from(ctx: &TopContext) -> ModuleOneContext { |
| 76 | + ModuleOneContext { |
| 77 | + db: ctx.db.clone() |
| 78 | + } |
| 79 | + } |
| 80 | + } |
| 81 | + |
| 82 | + graphql_object!(Query: TopContext |&self| { |
| 83 | + field item(&executor) -> Item { |
| 84 | + executor.context().db.get_item() |
| 85 | + } |
| 86 | + }); |
| 87 | + |
| 88 | + // The `Item` type uses another context type - conversion is automatic |
| 89 | + graphql_object!(Item: ModuleOneContext |&self| { |
| 90 | + // ... |
| 91 | + }); |
| 92 | + |
| 93 | + ``` |
| 94 | + |
| 95 | + The other way is to manually perform the conversion in a field |
| 96 | + resolver. This method is preferred when the child context needs |
| 97 | + extra knowledge than what exists in the parent context: |
| 98 | + |
| 99 | + ```rust |
| 100 | + |
| 101 | + // Each entity has its own context |
| 102 | + struct TopContext { |
| 103 | + entities: HashMap<i64, EntityContext>, |
| 104 | + db: DatabaseConnection, |
| 105 | + } |
| 106 | + |
| 107 | + struct EntityContext { |
| 108 | + // fields |
| 109 | + } |
| 110 | + |
| 111 | + impl Context for TopContext {} |
| 112 | + impl Context for EntityContext {} |
| 113 | + |
| 114 | + graphql_object!(Query: TopContext |&self| { |
| 115 | + // By returning a tuple (&Context, GraphQLType), you can tell the executor |
| 116 | + // to switch out the context for the returned value. You can wrap the |
| 117 | + // tuple in Option<>, FieldResult<>, FieldResult<Option<>>, or just return |
| 118 | + // the tuple without wrapping it. |
| 119 | + field entity(&executor, key: i64) -> Option<(&EntityContext, Entity)> { |
| 120 | + executor.context().entities.get(&key) |
| 121 | + .map(|ctx| (ctx, executor.context().db.get_entity(key))) |
| 122 | + } |
| 123 | + }); |
| 124 | + |
| 125 | + graphql_object!(Entity: EntityContext |&self| { |
| 126 | + // ... |
| 127 | + }); |
| 128 | + |
| 129 | + ``` |
| 130 | + |
| 131 | +## [0.5.3] – 2016-12-05 |
| 132 | + |
| 133 | +### Added |
| 134 | + |
| 135 | +* `jtry!`: Helper macro to produce `FieldResult`s from regular |
| 136 | + `Result`s. Wherever you would be using `try!` in a regular function |
| 137 | + or method, you can use `jtry!` in a field resolver: |
| 138 | + |
| 139 | + ```rust |
| 140 | + graphql_object(MyType: Database |&self| { |
| 141 | + field count(&executor) -> FieldResult<i64> { |
| 142 | + let txn = jtry!(executor.context().transaction()); |
| 143 | + |
| 144 | + let count = jtry!(txn.execute("SELECT COUNT(*) FROM user")); |
| 145 | + |
| 146 | + Ok(count[0][0]) |
| 147 | + } |
| 148 | + }); |
| 149 | + ``` |
| 150 | + |
| 151 | +### Changes |
| 152 | + |
| 153 | +* Relax context type trait requirements for the iron handler: your |
| 154 | + contexts no longer have to be `Send + Sync`. |
| 155 | + |
| 156 | +* `RootNode` is now `Send` and `Sync` if both the mutation and query |
| 157 | + types implement `Send` and `Sync`. |
| 158 | + |
| 159 | +### Bugfixes |
| 160 | + |
| 161 | +* `return` statements inside field resolvers no longer cause syntax |
| 162 | + errors. |
| 163 | + |
| 164 | + |
| 165 | + |
| 166 | +## 0.5.2 – 2016-11-13 |
| 167 | + |
| 168 | +### Added |
| 169 | + |
| 170 | +* Support for marking fields and enum values deprecated. |
| 171 | +* `input_object!` helper macro |
| 172 | + |
| 173 | +### Changes |
| 174 | + |
| 175 | +* The included example server now uses the simple Star Wars schema |
| 176 | + used in query/introspection tests. |
| 177 | + |
| 178 | +### Bugfixes |
| 179 | + |
| 180 | +* The query validators - particularly ones concerned with validation |
| 181 | + of input data and variables - have been improved significantly. A |
| 182 | + large number of test cases have been added. |
| 183 | + |
| 184 | +* Macro syntax stability has also been improved. All syntactical edge |
| 185 | + cases of the macros have gotten tests to verify their correctness. |
| 186 | + |
| 187 | + |
| 188 | +[0.5.3]: https://github.com/mhallin/juniper/compare/0.5.2...0.5.3 |
0 commit comments