Skip to content

Commit

Permalink
Support default datasources (#691)
Browse files Browse the repository at this point in the history
* Default datasources

* fix

* update qp
  • Loading branch information
Janpot authored Aug 11, 2022
1 parent e9f966c commit 1bb41ae
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 115 deletions.
21 changes: 15 additions & 6 deletions packages/toolpad-app/src/appDom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import invariant from 'invariant';
import { ConnectionStatus, AppTheme } from './types';
import { omit, update, updateOrCreate } from './utils/immutability';
import { camelCase, generateUniqueString, removeDiacritics } from './utils/strings';
import { ExactEntriesOf } from './utils/types';
import { ExactEntriesOf, Maybe } from './utils/types';
import { filterValues } from './utils/collections';

export const RESERVED_NODE_PROPERTIES = [
Expand Down Expand Up @@ -107,7 +107,7 @@ export interface QueryNode<Q = any, P = any> extends AppDomNodeBase {
readonly params?: BindableAttrValues<P>;
readonly attributes: {
readonly dataSource?: ConstantAttrValue<string>;
readonly connectionId: ConstantAttrValue<NodeReference>;
readonly connectionId: ConstantAttrValue<NodeReference | null>;
readonly query: ConstantAttrValue<Q>;
readonly transform?: ConstantAttrValue<string>;
readonly transformEnabled?: ConstantAttrValue<boolean>;
Expand Down Expand Up @@ -811,12 +811,21 @@ export function createRenderTree(dom: AppDom): RenderTree {
};
}

export function ref(nodeId: NodeId): NodeReference {
return { $$ref: nodeId };
export function ref(nodeId: NodeId): NodeReference;
export function ref(nodeId: null | undefined): null;
export function ref(nodeId: Maybe<NodeId>): NodeReference | null;
export function ref(nodeId: Maybe<NodeId>): NodeReference | null {
return nodeId ? { $$ref: nodeId } : null;
}

export function deref(nodeRef: NodeReference): NodeId {
return nodeRef.$$ref;
export function deref(nodeRef: NodeReference): NodeId;
export function deref(nodeRef: null | undefined): null;
export function deref(nodeRef: Maybe<NodeReference>): NodeId | null;
export function deref(nodeRef: Maybe<NodeReference>): NodeId | null {
if (nodeRef) {
return nodeRef.$$ref;
}
return null;
}

export function fromLegacyQueryNode(node: QueryNode<any>): QueryNode<any> {
Expand Down
66 changes: 15 additions & 51 deletions packages/toolpad-app/src/server/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,42 +161,10 @@ export async function getApp(id: string) {
return prisma.app.findUnique({ where: { id } });
}

function createDefaultConnections(dom: appDom.AppDom): appDom.ConnectionNode[] {
if (process.env.TOOLPAD_DEMO) {
return [
appDom.createNode(dom, 'connection', {
name: 'movies',
attributes: {
dataSource: appDom.createConst('movies'),
params: appDom.createSecret({ apiKey: '12345' }),
status: appDom.createConst(null),
},
}),
];
}

return [
appDom.createNode(dom, 'connection', {
name: 'rest',
attributes: {
dataSource: appDom.createConst('rest'),
params: appDom.createSecret({}),
status: appDom.createConst(null),
},
}),
];
}

function createDefaultDom(): appDom.AppDom {
let dom = appDom.createDom();
const appNode = appDom.getApp(dom);

// Create default connections
const defaultConnections = createDefaultConnections(dom);
for (const connection of defaultConnections) {
dom = appDom.addNode(dom, connection, appNode, 'connections');
}

// Create default page
const newPageNode = appDom.createNode(dom, 'page', {
name: 'Page 1',
Expand Down Expand Up @@ -335,20 +303,16 @@ export async function loadReleaseDom(appId: string, version: number): Promise<ap
return JSON.parse(release.snapshot.toString('utf-8')) as appDom.AppDom;
}

async function getConnection<P = unknown>(
appId: string,
id: string,
): Promise<appDom.ConnectionNode<P>> {
const dom = await loadPreviewDom(appId);
return appDom.getNode(dom, id as NodeId, 'connection') as appDom.ConnectionNode<P>;
}

export async function getConnectionParams<P = unknown>(
appId: string,
id: string,
connectionId: string | null,
): Promise<P | null> {
const dom = await loadPreviewDom(appId);
const node = appDom.getNode(dom, id as NodeId, 'connection') as appDom.ConnectionNode<P>;
const node = appDom.getNode(
dom,
connectionId as NodeId,
'connection',
) as appDom.ConnectionNode<P>;
return node.attributes.params.value;
}

Expand Down Expand Up @@ -386,10 +350,9 @@ export async function execQuery<P, Q>(
);
}

const connectionParams = await getConnectionParams<P>(
appId,
appDom.deref(query.attributes.connectionId.value),
);
const connectionParams = query.attributes.connectionId.value
? await getConnectionParams<P>(appId, appDom.deref(query.attributes.connectionId.value))
: null;

const transformEnabled = query.attributes.transformEnabled?.value;
const transform = query.attributes.transform?.value;
Expand All @@ -406,22 +369,23 @@ export async function execQuery<P, Q>(

export async function dataSourceFetchPrivate<P, Q>(
appId: string,
connectionId: NodeId,
dataSourceId: string,
connectionId: NodeId | null,
query: Q,
): Promise<any> {
const connection: appDom.ConnectionNode<P> = await getConnection<P>(appId, connectionId);
const dataSourceId = connection.attributes.dataSource.value;
const dataSource: ServerDataSource<P, Q, any> | undefined = serverDataSources[dataSourceId];

if (!dataSource) {
throw new Error(`Unknown dataSource "${dataSourceId}" for connection "${connection.id}"`);
throw new Error(`Unknown dataSource "${dataSourceId}"`);
}

if (!dataSource.execPrivate) {
throw new Error(`No execPrivate available on datasource "${dataSourceId}"`);
}

const connectionParams = connection.attributes.params.value;
const connectionParams: P | null = connectionId
? await getConnectionParams<P>(appId, connectionId)
: null;

return dataSource.execPrivate(connectionParams, query);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ function ConnectionEditorContent<P>({
[connectionNode, domApi],
);

const dataSourceType = connectionNode.attributes.dataSource.value;
const dataSource = dataSources[dataSourceType];
const dataSourceId = connectionNode.attributes.dataSource.value;
const dataSource = dataSources[dataSourceId];
const connectionEditorContext = React.useMemo(
() => ({ appId, connectionId: connectionNode.id }),
[appId, connectionNode.id],
() => ({ appId, dataSourceId, connectionId: connectionNode.id }),
[appId, dataSourceId, connectionNode.id],
);

return (
Expand All @@ -77,7 +77,7 @@ function ConnectionEditorContent<P>({
dataSource={dataSource}
value={connectionNode.attributes.params.value}
onChange={handleConnectionChange}
handlerBasePath={`/api/dataSources/${dataSourceType}`}
handlerBasePath={`/api/dataSources/${dataSourceId}`}
appId={appId}
connectionId={connectionNode.id}
/>
Expand Down
Loading

0 comments on commit 1bb41ae

Please sign in to comment.