Generating APIs
TinyBase can take a TablesSchema
and/or ValuesSchema
(which have either been explicitly set, or inferred) and generate the code for type definitions and ORM-like implementations to wrap the Store
.
This is most likely to be used as part of a build script which takes a TablesSchema
or ValuesSchema
as input (or imported data) to generate TypeScript definition (.d.ts
) files and .ts
and .tsx
implementations. These can then be linked into the development and compilation of an application as a whole.
Using The getStoreApi Method
This is performed from the Tools
object - which is returned from the createTools
function - and via the getStoreApi
method.
The method takes a parameter which serves as the 'name' for your wrapped, typed, Store
:
import {createStore} from 'tinybase';
import {createTools} from 'tinybase/tools';
const store = createStore().setTable('pets', {
fido: {species: 'dog'},
felix: {species: 'cat'},
cujo: {species: 'dog'},
});
const tools = createTools(store);
const [dTs, ts, uiReactDTs, uiReactTsx] = tools.getStoreApi('shop');
In this case, the resulting four strings will need to be written to shop.d.ts
, shop.ts
, shop-ui-react.d.ts
, and shop-ui-react.tsx
files respectively. TinyBase does not perform that step for you, so you'll need to do it explicitly:
fs.writeFileSync('shop.d.ts', dTs, 'utf-8');
fs.writeFileSync('shop.ts', ts, 'utf-8');
fs.writeFileSync('shop-ui-react.d.ts', uiReactDTs, 'utf-8');
fs.writeFileSync('shop-ui-react.tsx', uiReactTsx, 'utf-8');
Prettified Code
The getPrettyStoreApi
method is an asynchronous method that attempts to run a locally installed prettier
module to ensure the file is reasonably formatted:
const [prettyDTs, prettyTs, prettyUiReactDTs, prettyUiReactTsx] =
await tools.getPrettyStoreApi('shop');
fs.writeFileSync('shop.d.ts', prettyDTs, 'utf-8');
fs.writeFileSync('shop.ts', prettyTs, 'utf-8');
fs.writeFileSync('shop-ui-react.d.ts', prettyUiReactDTs, 'utf-8');
fs.writeFileSync('shop-ui-react.tsx', prettyUiReactTsx, 'utf-8');
This will produce a file containing the types for your wrapped Store
, for example:
//...
/**
* Represents the 'pets' Table.
*/
export type PetsTable = {[rowId: Id]: PetsRow};
/**
* Represents a Row when getting the content of the 'pets' Table.
*/
export type PetsRow = {species: string};
//...
The .ts
implementation will contain the createShop
entry point, and will look something like this:
//...
export const createShop: typeof createShopDecl = () => {
// ...
const store = createStore().setTablesSchema({
pets: {
species: {type: 'string', default: 'dog'},
},
});
return {
hasPetsTable: (): boolean => store.hasTable('pets'),
getPetsTable: (): PetsTable => store.getTable('pets') as PetsTable,
// ...
};
};
Examples
For the full set of methods and types generated by these code generation methods, inspect the output directly. Suffice to say that the generated APIs above will allow you to write domain-specific code like this:
import {createShop} from './shop';
const shop = createShop()
.setPetsTable({fido: {species: 'dog'}})
.setPetsRow('felix', {species: 'cat'});
console.log(shop.getPetsSpeciesCell('felix'));
// -> 'cat'
And so on. There is complete equivalence between the generated methods in your domain-specific API and the underlying Store
interface. Similarly, every React hook and component has a domain-specific equivalent:
import React from 'react';
import {createRoot} from 'react-dom/client';
const App = () => {
shop = useCreateShop(() =>
createShop()
.setPetsTable({fido: {species: 'dog'}})
.setPetsRow('felix', {species: 'cat'}),
);
return (
<Provider shop={shop}>
<PetsRowView rowId="fido" />
<PetsSpeciesCellView rowId="felix" />
</Provider>
);
};
createRoot(document.body).render(<App />);
Other Notes
Whether pretty or not, the resulting files can easily be included in your main application. Note that the implementations (eg shop.ts
) import types from the definitions (eg shop.d.ts
) and so it's required that the four files are next to each other in the file system.
If the Store
has neither an explicit schema, nor can one be inferred, the four strings will be empty, since no type information can be usefully generated for the Store
.
If you do not wish to handle the programmatic steps described above, and simply want to take schemas stored in a file and generate these definitions directly, see the Command Line guide in this section.
You can also read the brief Gathering Statistics guide.