Skip to content

[WIP] Adding documentation for @polybase/client #152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ dist
node
web
.log
.npmrc
.npmrc
**/doc
16 changes: 16 additions & 0 deletions packages/client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,19 @@ To run E2E tests, ensure that [Polybase](https://github.com/polybase/polybase) i
```
yarn test:e2e
```

# Doc

To generate the documentation for the project, run the following command:

```
$ npm run doc
```

or

```
$ yarn run doc
```

This will generate the documentation in the `doc` directory.
5 changes: 4 additions & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"release": "npx np",
"test": "jest ./src",
"test:e2e": "jest ./e2e --verbose",
"fix": "yarn eslint \"./src/**/*.{ts,tsx}\" --fix"
"fix": "yarn eslint \"./src/**/*.{ts,tsx}\" --fix",
"doc": "npx typedoc --plugin typedoc-plugin-missing-exports"
},
"jest": {
"preset": "ts-jest",
Expand Down Expand Up @@ -46,6 +47,8 @@
"terser-webpack-plugin": "^5.3.6",
"ts-jest": "^29.1.0",
"ts-loader": "^9.4.2",
"typedoc": "^0.24.8",
"typedoc-plugin-missing-exports": "^2.0.1",
"typescript": "^4.9.4",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1"
Expand Down
32 changes: 31 additions & 1 deletion packages/client/src/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,31 @@ import { AxiosError, AxiosRequestConfig } from 'axios'
import { createError, createErrorFromAxiosError } from './errors'
import { QueryValue, Request, RequestParams, Sender, SenderResponse, Signer, SignerResponse } from './types'

/**
* The Client configuration.
*/
export interface ClientConfig {
/** The unique identifier for this client.
* @example
* ```
* polybase@ts/client:v0
* ```
*/
clientId: string
/** The base URL of the Polybase service.
* @example
* ```
* https://testnet.polybase.xyz/v0
* ```
*/
baseURL: string
}

type SignatureCache = Record<string, { timeMs: number, sig: SignerResponse }>

/**
* The Client used by the Polybase Client for interacting with the Polybase service.
*/
export class Client {
private sender: Sender
signer?: Signer
Expand All @@ -23,6 +41,9 @@ export class Client {
this.signatureCache = {}
}

/**
* Returns a new {@link ClientRequest} instance.
*/
request = (req: Request): ClientRequest => {
return new ClientRequest(this.sender, {
url: req.url,
Expand Down Expand Up @@ -54,7 +75,12 @@ export class ClientRequest {
this.aborter.abort()
}

/* Sending a request to the server. */
/**
* Send a request to the server.
*
* @param withAuth - The authentication mode.
* @param sigExtraTimeMs - Extra time to sign the request.
*/
send = async <T = any>(withAuth: 'none' | 'optional' | 'required', sigExtraTimeMs?: number): Promise<SenderResponse<T>> => {
try {
const req = this.req as AxiosRequestConfig
Expand Down Expand Up @@ -99,6 +125,7 @@ export class ClientRequest {
}
}

/** @private */
private getSignature = async (extraTimeMs: number) => {
if (!this.signer) return ''

Expand Down Expand Up @@ -138,6 +165,9 @@ export class ClientRequest {
}
}

/**
* Parse the given request parameters into a {@link Record} object.
*/
export function parseParams(params?: RequestParams): Record<string, QueryValue | undefined> {
if (!params) return {}
return {
Expand Down
41 changes: 41 additions & 0 deletions packages/client/src/Collection.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* @see [Collections](https://polybase.xyz/docs/collections)
* @module
*/

import { CollectionRecord, CollectionRecordResponse } from './Record'
import { Query, QueryResponse } from './Query'
import { Subscription, SubscriptionFn, SubscriptionErrorFn, UnsubscribeFn } from './Subscription'
Expand Down Expand Up @@ -29,6 +34,9 @@ export class Collection<T> {
load = async () => {
}

/**
* returns The collection metadata.
*/
getMeta = async (): Promise<CollectionMeta> => {
if (this.meta) return this.meta
// Manually get Collection meta, otherwise we would recursively call this function
Expand All @@ -44,6 +52,9 @@ export class Collection<T> {
return this.meta
}

/**
* @returns The prepared AST for this collection.
*/
getAST = async (): Promise<ASTCollection> => {
// Return cached value if it exists
if (this.astCache) return this.astCache
Expand All @@ -55,10 +66,19 @@ export class Collection<T> {
return collectionAST
}

/**
* @returns The short name for this collection.
*/
name(): string {
return getCollectionShortNameFromId(this.id)
}

/**
* Validate the given collection ast.
*
* @param data - the data to be validated
* @returns Whether validation succeeded (`true`) or not (`false`).
*/
validate = async (data: Partial<T>) => {
const ast = await this.getAST()
try {
Expand All @@ -69,13 +89,22 @@ export class Collection<T> {
}
}

/**
* @returns Whether this collection can be read pubclicly (`true) or not (`false`)
* @see [Permissions](https://polybase.xyz/docs/permissions)
*/
isReadPubliclyAccessible = async (): Promise<boolean> => {
// Without this, we would recursively call this function
if (this.id === 'Collection') return true

return this.isCollectionPubliclyAccessible('read')
}

/**
* @param methodName - the method (as defined in the collection schema).
* @returns Whether the method can be called (`true`) on this collection or not (`false`).
* @see [Permissions](https://polybase.xyz/docs/permissions)
*/
isCallPubliclyAccessible = async (methodName: string) => {
// Without this, we would recursively call this function
if (this.id === 'Collection') return true
Expand Down Expand Up @@ -104,6 +133,12 @@ export class Collection<T> {
return hasPublicDirective || hasTypeDirective
}

/**
* Create a collection record.
*
* @param args - the data for the new collection.
* @returns The newly created collection record.
*/
create = async (args: CallArgs = []): Promise<CollectionRecordResponse<T>> => {
if (!Array.isArray(args)) {
throw new TypeError('invalid argument: `args` must be an array')
Expand All @@ -127,6 +162,12 @@ export class Collection<T> {
return this.createQuery().get()
}

/**
* Retrieves the record, for this collection, with the given id.
*
* @param id - the id of the collection record.:w
* @returns The collection record.
*/
record = (id: string): CollectionRecord<T> => {
return new CollectionRecord<T>(id, this, this.client, this.onRecordSnapshotRegister)
}
Expand Down
51 changes: 50 additions & 1 deletion packages/client/src/Polybase.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,47 @@
/**
* <p>The Polybase Client SDK.</p>
*
* <p>The Polybase module is how we communicate with the Polybase service.
* @see [Getting Started](https://polybase.xyz/docs/get-started)
*</p>
*
* @module
*/

import { parse } from '@polybase/polylang'
import axios from 'axios'
import { Client } from './Client'
import { Collection } from './Collection'
import { PolybaseError, createError } from './errors'
import { CollectionMeta, Sender, Signer } from './types'

/**
* Configuration for the Polybase Client.
*/
export interface PolybaseConfig {
/**
* The baseURL of the Polybase service.
* @example
* ```
* https://testnet.polybase.xyz/v0
* ```
*/
baseURL: string
/**
* The unique identifier of the Client.
* @example
* ```
* polybase@ts/client:v0
* ```
*/
clientId: string
/**
* The default namespace for the Client.
* @example
* ```
* "pk/0x1fda4bead8bc2e85d4de75694b893de5dfb0fbe69e8ed1d2531c805db483ba350ea28d4b1c7acf6171d902586e439a04f23cb0827b08a29cbdf3dd0e5c994ec0/MyClient"
* ```
*/
defaultNamespace?: string
sender: Sender
signer?: Signer
Expand All @@ -19,6 +53,9 @@ const defaultConfig = {
sender: axios,
}

/**
* The Polybase Client.
*/
export class Polybase {
private config: PolybaseConfig
private client: Client
Expand All @@ -34,6 +71,12 @@ export class Polybase {
)
}

/**
* Retrieves the collection with the given path.
*
* @param path - the fully-qualified path to the collection.
* @returns The given {@link Collection} instance.
*/
collection<T = any>(path: string): Collection<T> {
const rp = this.getResolvedPath(path)
if (this.collections[rp]) return this.collections[rp]
Expand Down Expand Up @@ -71,7 +114,13 @@ export class Polybase {
return this.collection<T>(data.id)
}

/* Applies the given schema to the database, creating new collections and adding existing collections */
/**
* Applies the given schema to the database, creating new collections and adding existing collections.
*
* @param schema: The schema to apply.
* @param namespace: The namespace for the collection.
* @returns An array of {@link Collection} instances.
*/
applySchema = async (schema: string, namespace?: string): Promise<Collection<any>[]> => {
const collections = []
const ns = (namespace ?? this.config.defaultNamespace)
Expand Down
6 changes: 6 additions & 0 deletions packages/client/src/Query.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* @module
* @see [Filter records](https://polybase.xyz/docs/read#filter-records)
* @see [Pagination](https://polybase.xyz/docs/read#pagination)
*/

import { Client } from './Client'
import { Collection, QuerySnapshotRegister } from './Collection'
import { CollectionRecord, CollectionRecordResponse } from './Record'
Expand Down
35 changes: 34 additions & 1 deletion packages/client/src/Record.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* This module contains types and functions for the actual instances of collections.
*
* @module
*/

import { Collection } from './Collection'
import { SubscriptionErrorFn, SubscriptionFn } from './Subscription'
import { CollectionRecordSnapshotRegister, Request, CallArgs, SenderRawRecordResponse, Block } from './types'
Expand All @@ -11,6 +17,9 @@ export type CollectionRecordReference = {
id: string
}

/**
* This represents an instance of a collection.
*/
export class CollectionRecord<T> {
id: string
private collection: Collection<T>
Expand All @@ -24,6 +33,13 @@ export class CollectionRecord<T> {
this.onSnapshotRegister = onSnapshotRegister
}

/**
* Calls a function on this collection record.
* The function must be a custom function defined in the collection schema.
*
* @see [Write Data](https://polybase.xyz/docs/write-data)
* @see [Delete Data](https://polybase.xyz/docs/delete-data)
*/
call = async (functionName: string, args: CallArgs = []): Promise<CollectionRecordResponse<T, T | null>> => {
const ast = await this.collection.getAST()
const isCallPubliclyAccessible = await this.collection.isCallPubliclyAccessible(functionName)
Expand All @@ -39,6 +55,12 @@ export class CollectionRecord<T> {
return new CollectionRecordResponse(this.id, res.data, ast, this.collection, this.client, this.onSnapshotRegister)
}

/**
* Retrieves the collection record.
*
* @returns The collection recod.
* @see [Read Data](https://polybase.xyz/docs/read)
*/
get = async (): Promise<CollectionRecordResponse<T, T | null>> => {
const ast = await this.collection.getAST()
const isReadPubliclyAccessible = await this.collection.isReadPubliclyAccessible()
Expand All @@ -65,16 +87,27 @@ export class CollectionRecord<T> {
return `record:${this.collection.id}/${this.id}`
}

/**
* Listener for updates to this record (after the write is confirmed).
*
* @see [Listen for updates on a record](https://polybase.xyz/docs/read#listen-for-updates-on-a-record)
*/
onSnapshot = (fn: SubscriptionFn<CollectionRecordResponse<T>>, errFn?: SubscriptionErrorFn) => {
return this.onSnapshotRegister(this, fn, errFn)
}

/**
* The {@link Request} object for this collection record.
*/
request = (): Request => ({
url: `/collections/${encodeURIComponent(this.collection.id)}/records/${encodeURIComponent(this.id)}`,
method: 'GET',
})
}

/**
* The collection record data, as returned by the Polybase service.
*/
export class CollectionRecordResponse<T, NT extends T | null = T> extends CollectionRecord<T> {
data: NT
block: Block
Expand All @@ -100,6 +133,6 @@ export class CollectionRecordResponse<T, NT extends T | null = T> extends Collec
}

/**
* @deprecated use CollectionRecord
* @deprecated use CollectionRecord instead
*/
export const Doc = CollectionRecord
Loading