Skip to content

Commit

Permalink
Update Documentation to FluidObject (#9817)
Browse files Browse the repository at this point in the history
Update IFluidObject documentation to references to FluidObject, and fix some doc bugs.

related #8253
  • Loading branch information
anthony-murphy authored Apr 11, 2022
1 parent b7eadee commit 1f73218
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 152 deletions.
49 changes: 0 additions & 49 deletions docs/content/docs/deep/dataobject-aqueduct.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,55 +198,6 @@ export fluidExport = new ContainerRuntimeFactoryWithDefaultDataStore(
);
```

## Provider entries development

The container developer can optionally provide a registry of `ProviderEntry` objects into the container. A ProviderEntry
is defined as follows:

```typescript
interface ProviderEntry<T extends keyof IFluidObject> {
type: T;
provider: FluidProvider<T>
}
```

The `type` must be a keyof `IFluidObject`. This basically means that it needs to be the name of an interfaces that
extends off of `IFluidObject`. The `provider` must be something that provides the interface defined in `type`. The
`DependencyContainer` we use in the `@fluidframework/synthesize` package defines the following `FluidObjectProvider`
types:

```typescript
type FluidObjectProvider<T extends keyof IFluidObject> =
IFluidObject[T]
| Promise<IFluidObject[T]>
| ((dependencyContainer: DependencyContainer) => IFluidObject[T])
| ((dependencyContainer: DependencyContainer) => Promise<IFluidObject[T]>);
```

```typescript
IFluidObject[T]
```

An object that implements the interface.

```typescript
Promise<IFluidObject[T]>
```

A Promise to an object that implements the interface

```typescript
(dependencyContainer: DependencyContainer) => IFluidObject[T]
```

A factory that will return the object.

```typescript
(dependencyContainer: DependencyContainer) => Promise<IFluidObject[T]>
```

A factory that will return a Promise to the object.

## Container-level request handlers

You can provide custom request handlers to the container. These request handlers are injected after system handlers but
Expand Down
15 changes: 7 additions & 8 deletions docs/content/docs/deep/feature-detection-iprovide.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Feature detection via IFluidObject
title: Feature detection via FluidObject
draft: true
status: outdated
aliases:
Expand All @@ -13,21 +13,20 @@ data included.
Fluid can be a very dynamic system. There are scenarios in which your code will call certain members of an object, *if
and only if*, the object has certain capabilities; that is, it implements certain interfaces. So, your code needs a way
of detecting whether the object implements specific interfaces. To make this easier, Fluid has a feature detection
mechanism, which centers around a special interface called `IFluidObject`. Feature detection is a technique by which one
mechanism, which centers around a special type called `FluidObject`. Feature detection is a technique by which one
Data Object can dynamically determine the capabilities of another Data Object.

In order to detect features supported by an unknown object, you cast it to an `IFluidObject` and then query the object
for a specific interface that it may support. The interfaces exposed via `IFluidObject` include many core Fluid
interfaces, such as `IFluidHandle` or `IFluidLoadable`, and this list can be augmented using [TypeScript's interface
merging capabilities](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces). This
In order to detect features supported by an unknown object, you cast it to an `FluidObject` and then query the object
for a specific interface that it may support. The interfaces available via `FluidObject` include many core Fluid
interfaces, such as `IFluidHandle` or `IFluidLoadable`. This
discovery system (see example below) enables any Data Object to record what interfaces it implements and make it
possible for other Data Objects to discover them. The specifics of how these interfaces are declared is not relevant
until you want to define your own interfaces, which we'll cover in a later section.

The following is an example of feature detection using `IFluidObject`:
The following is an example of feature detection using `FluidObject`:

```typescript
const anUnknownObject = anyObject as IFluidObject;
const anUnknownObject = anyObject as FluidObject<IFluidLoadable>;

// Query the object to see if it supports IFluidLoadable
const loadable = anUnknownObject.IFluidLoadable; // loadable: IFluidLoadable | undefined
Expand Down
49 changes: 0 additions & 49 deletions packages/framework/aqueduct/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,55 +185,6 @@ export fluidExport = new ContainerRuntimeFactoryWithDefaultDataStore(
);
```

## Provider entries development

The container developer can optionally provide a registry of `ProviderEntry` objects into the container. A ProviderEntry
is defined as follows:

```typescript
interface ProviderEntry<T extends keyof IFluidObject> {
type: T;
provider: FluidProvider<T>
}
```

The `type` must be a keyof `IFluidObject`. This basically means that it needs to be the name of an interfaces that
extends off of `IFluidObject`. The `provider` must be something that provides the interface defined in `type`. The
`DependencyContainer` we use in the `@fluidframework/synthesize` package defines the following `FluidObjectProvider`
types:

```typescript
type FluidObjectProvider<T extends keyof IFluidObject> =
IFluidObject[T]
| Promise<IFluidObject[T]>
| ((dependencyContainer: DependencyContainer) => IFluidObject[T])
| ((dependencyContainer: DependencyContainer) => Promise<IFluidObject[T]>);
```

```typescript
IFluidObject[T]
```

An object that implements the interface.

```typescript
Promise<IFluidObject[T]>
```

A Promise to an object that implements the interface

```typescript
(dependencyContainer: DependencyContainer) => IFluidObject[T]
```

A factory that will return the object.

```typescript
(dependencyContainer: DependencyContainer) => Promise<IFluidObject[T]>
```

A factory that will return a Promise to the object.

## Container-level request handlers

You can provide custom request handlers to the container. These request handlers are injected after system handlers but
Expand Down
73 changes: 27 additions & 46 deletions packages/framework/synthesize/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# @fluidframework/synthesize

An Ioc type library for synthesizing a IFluidObject based on registered IFluidObject providers.
An Ioc type library for synthesizing a FluidObject based on FluidObject providers.

It allows for the creation of a `DependencyContainer` that can have IFluidObjects registered with it
It allows for the creation of a `DependencyContainer` that can have FluidObjects registered with it
based on their interface Symbol. So for example if I wanted to register something as `IFoo` I would
need to provide and object that implements `IFoo` along side it.

Expand All @@ -21,7 +21,7 @@ So if I wanted an object with an optional `IFoo` and a required `IBar` I would g
## Simple Example

```typescript
const dc = new DependencyContainer();
const dc = new DependencyContainer<FluidObject<IFoo & IBar>>();
dc.register(IFoo, new Foo());

const s = dc.synthesize({IFoo}, {});
Expand All @@ -44,7 +44,7 @@ console.log(s.IFoo?.foo;)

## Fluid object Providers

Fluid object Providers are the the different ways you can return a IFluidObject when registering.
Fluid object Providers are the the different ways you can return a FluidObject when registering.

There are four types of providers:

Expand All @@ -54,86 +54,68 @@ There are four types of providers:
4. [`Async Factory Provider`](###Async-Factory-Provider)

```typescript
type FluidObjectProvider<T extends keyof IFluidObject> =
IFluidObject[T]
| Promise<IFluidObject[T]>
| ((dependencyContainer: DependencyContainer) => IFluidObject[T])
| ((dependencyContainer: DependencyContainer) => Promise<IFluidObject[T]>);
type FluidObjectProvider<T> =
NonNullable<T>
| Promise<NonNullable<T>>
| ((dependencyContainer: IFluidDependencySynthesizer) => NonNullable<T>)
| ((dependencyContainer: IFluidDependencySynthesizer) => Promise<NonNullable<T>>);
```

### Value Provider

Provide an IFluidObject of a given type.
Provide an FluidObject of a given type.

#### Usage

```typescript
const dc = new DependencyContainer();
const dc = new DependencyContainer<FluidObject<IFoo>>();

// Singleton
const foo = new Foo();
dc.register(IFoo, Foo);

// Instance
dc.register(IFoo, new Foo())
dc.register(IFoo, new Foo());
```

### Async Value Provider

Provide a Promise to an IFluidObject of a given type.
Provide a Promise to an FluidObject of a given type.

#### Usage

```typescript
const dc = new DependencyContainer();
const dc = new DependencyContainer<FluidObject<IFoo>>();

const generateFoo: Promise<IFoo> = await() => {
const foo = new Foo();
await foo.initialize();
return foo;
}

// Singleton
const foo = generateFoo();
dc.register(IFoo, foo);

// Instance
dc.register(IFoo, generateFoo());
```

### Factory Provider

```typescript
(dependencyContainer: DependencyContainer) => IFluidObject[T]
```

Provide a function that will resolve an IFluidObject of a given type.
Provide a function that will resolve an FluidObject of a given type.

#### Usage

```typescript
const dc = new DependencyContainer();
const dc = new DependencyContainer<FluidObject<IFoo & IBar>>();
const fooFactory = () => new Foo();
dc.register(IFoo, fooFactory);

// Factories can utilize the DependencyContainer if the IFluidObject depends
// Factories can utilize the DependencyContainer if the FluidObject depends
// on other providers
const barFactory = (dc) => new Bar(dc);
dc.register(IFoo, barFactory);
```

### Async Factory Provider

```typescript
(dependencyContainer: DependencyContainer) => Promise<IFluidObject[T]>
```

Provide a function that will resolve a Promise to an IFluidObject of a given type.
Provide a function that will resolve a Promise to an FluidObject of a given type.

#### Usage

```typescript
const dc = new DependencyContainer();
const dc = new DependencyContainer<FluidObject<IFoo & IBar>>();

const generateFoo: Promise<IFoo> = await() => {
const foo = new Foo();
Expand All @@ -154,7 +136,7 @@ dc.register(IBar, generateBar);

## Synthesize

Once you have a `DependencyContainer` with registered providers you can synthesize/generate a new IFluidObject
Once you have a `DependencyContainer` with registered providers you can synthesize/generate a new FluidObject
from it. The object that is returned will have the correct typing of optional and required types.

An Example:
Expand All @@ -173,11 +155,11 @@ is a TypeScript `type` that ensures the types being passed match the ones in the

### Optional Types

Optional types will return a Promise to it's corresponding IFluidObject or undefined. Because of this we need to do
Optional types will return a Promise to it's corresponding FluidObject or undefined. Because of this we need to do
an if check to validate the object or use the `?` like in the example below.

```typescript
const dc = new DependencyContainer();
const dc = new DependencyContainer<FluidObject<IFoo>>();

const s = dc.synthesize<IFoo>({IFoo}, {});
const foo = await s.IFoo;
Expand All @@ -189,12 +171,12 @@ need to provide the type.*

### Required Types

Required types will return a Promise to it's corresponding IFluidObject or it will throw.
Required types will return a Promise to it's corresponding FluidObject or it will throw.

You can see below that we don't need to add the `?` to check our requested type.

```typescript
const dc = new DependencyContainer();
const dc = new DependencyContainer<FluidObject<IFoo>>();

const scope = dc.synthesize<{}, IFoo>({}, {IFoo});
const foo = await s.IFoo;
Expand All @@ -206,7 +188,7 @@ console.log(foo.foo);
You can declare multiple types for both Optional and Required using the `&` or creating a separate type.

```typescript
const dc = new DependencyContainer();
const dc = new DependencyContainer<FluidObject<IFoo & IBar>>();

const scope = dc.synthesize<IFoo & IBar>({IFoo, IBar}, {});
const fooP = s.IFoo;
Expand All @@ -217,7 +199,7 @@ console.log(bar?.bar);
```

```typescript
const dc = new DependencyContainer();
const dc = new DependencyContainer<FluidObject<IFoo & IBar>>();

const scope = dc.synthesize<{}, IFoo & IBar>({}, {IFoo, IBar});
const fooP = s.IFoo;
Expand All @@ -228,7 +210,7 @@ console.log(bar.bar);
```

```typescript
const dc = new DependencyContainer();
const dc = new DependencyContainer<FluidObject<IFoo & IBar>>();

const scope = dc.synthesize<IFoo, IBar>({IFoo}, {IBar});
const fooP = s.IFoo;
Expand All @@ -243,4 +225,3 @@ console.log(bar.bar);
The `DependencyContainer` takes one optional parameter which is the `parent`. When resolving providers the `DependencyContainer` will first
check the current container then look in the parent.

The `parent` can also be set after `DependencyContainer` creation.

0 comments on commit 1f73218

Please sign in to comment.