Skip to content
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

JSDoc comments for JS #51

Merged
merged 11 commits into from
Feb 9, 2024
2 changes: 1 addition & 1 deletion packages/powersync-react/src/hooks/usePowerSyncQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { usePowerSync } from './PowerSyncContext';

/**
* A hook to access a single static query.
* For an updated result, use usePowerSyncWatchedQuery instead
* For an updated result, use {@link usePowerSyncWatchedQuery} instead
*/
export const usePowerSyncQuery = <T = any>(sqlStatement: string, parameters: any[] = []): T[] => {
const powerSync = usePowerSync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ import { EventIterator } from 'event-iterator';
import { quoteIdentifier } from '../utils/strings';

export interface DisconnectAndClearOptions {
/** When set to false, data in local-only tables is preserved. */
clearLocal?: boolean;
}

export interface PowerSyncDatabaseOptions {
/** Schema used for the local database. */
schema: Schema;
database: DBAdapter;
/**
Expand Down Expand Up @@ -114,14 +116,25 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
this._isReadyPromise = this.initialize();
}

/**
* Schema used for the local database.
*/
get schema() {
return this._schema;
}

/**
* The underlying database.
*
* For the most part, behavior is the same whether querying on the underlying database, or on {@link AbstractPowerSyncDatabase}. The main difference is in update notifications: the underlying database reports updates to the underlying tables, while AbstractPowerSyncDatabase reports updates to the higher-level views.
benitav marked this conversation as resolved.
Show resolved Hide resolved
*/
protected get database() {
return this.options.database;
}

/**
* Whether a connection to the PowerSync service is currently open.
*/
get connected() {
return this.currentStatus?.connected || false;
}
Expand Down Expand Up @@ -163,6 +176,11 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
this.iterateListeners((cb) => cb.initialized?.());
}

/**
* Replace the schema with a new version. This is for advanced use cases - typically the schema should just be specified once in the constructor.
*
* Cannot be used while connected - this should only be called before {@link AbstractPowerSyncDatabase.connect}.
*/
async updateSchema(schema: Schema) {
if (this.abortController) {
throw new Error('Cannot update schema while connected');
Expand Down Expand Up @@ -226,6 +244,11 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
this.watchCrudUploads();
}

/**
* Close the sync connection.
*
* Use {@link connect} to connect again.
*/
async disconnect() {
this.abortController?.abort();
this.syncStatusListenerDisposer?.();
Expand All @@ -237,6 +260,8 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
* Use this when logging out.
* The database can still be queried after this is called, but the tables
* would be empty.
*
* To preserve data in local-only tables, set clearLocal to false.
*/
async disconnectAndClear(options = DEFAULT_DISCONNECT_CLEAR_OPTIONS) {
await this.disconnect();
Expand Down Expand Up @@ -270,7 +295,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
/*
* Close the database, releasing resources.
*
* Also [disconnect]s any active connection.
* Also disconnects any active connection.
*
* Once close is called, this connection cannot be used again - a new one
* must be constructed.
Expand Down Expand Up @@ -307,12 +332,12 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
*
* Returns null if there is no data to upload.
*
* Use this from the [PowerSyncBackendConnector.uploadData]` callback.
* Use this from the {@link PowerSyncBackendConnector.uploadData} callback.
*
* Once the data have been successfully uploaded, call [CrudBatch.complete] before
* Once the data have been successfully uploaded, call {@link CrudBatch.complete} before
* requesting the next batch.
*
* Use [limit] to specify the maximum number of updates to return in a single
* Use {@link limit} to specify the maximum number of updates to return in a single
* batch.
*
* This method does include transaction ids in the result, but does not group
Expand Down Expand Up @@ -358,12 +383,12 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
*
* Returns null if there is no data to upload.
*
* Use this from the [PowerSyncBackendConnector.uploadData]` callback.
* Use this from the {@link PowerSyncBackendConnector.uploadData} callback.
*
* Once the data have been successfully uploaded, call [CrudTransaction.complete] before
* Once the data have been successfully uploaded, call {@link CrudTransaction.complete} before
* requesting the next transaction.
*
* Unlike [getCrudBatch], this only returns data from a single transaction at a time.
* Unlike {@link getCrudBatch}, this only returns data from a single transaction at a time.
* All data for the transaction is loaded into memory.
*/
async getNextCrudTransaction(): Promise<CrudTransaction> {
Expand Down Expand Up @@ -413,15 +438,15 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
}

/**
* Execute a statement and optionally return results
* Execute a statement and optionally return results.
*/
async execute(sql: string, parameters?: any[]) {
await this.waitForReady();
return this.database.execute(sql, parameters);
}

/**
* Execute a read-only query and return results
* Execute a read-only query and return results.
*/
async getAll<T>(sql: string, parameters?: any[]): Promise<T[]> {
await this.waitForReady();
Expand All @@ -446,8 +471,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB

/**
* Takes a read lock, without starting a transaction.
*
* In most cases, [readTransaction] should be used instead.
* In most cases, {@link readTransaction} should be used instead.
*/
async readLock<T>(callback: (db: DBAdapter) => Promise<T>) {
await this.waitForReady();
Expand All @@ -456,7 +480,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB

/**
* Takes a global lock, without starting a transaction.
* In most cases, [writeTransaction] should be used instead.
* In most cases, {@link writeTransaction} should be used instead.
*/
async writeLock<T>(callback: (db: DBAdapter) => Promise<T>) {
await this.waitForReady();
Expand All @@ -466,6 +490,12 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
});
}

/**
* Open a read-only transaction.
* TODO: Up to maxReaders read transactions can run concurrently. After that, read transactions are queued.
benitav marked this conversation as resolved.
Show resolved Hide resolved
benitav marked this conversation as resolved.
Show resolved Hide resolved
* Read transactions can run concurrently to a write transaction.
* Changes from any write transaction are not visible to read transactions started before it.
*/
async readTransaction<T>(
callback: (tx: Transaction) => Promise<T>,
lockTimeout: number = DEFAULT_LOCK_TIMEOUT_MS
Expand All @@ -481,6 +511,11 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
);
}

/**
* Open a read-write transaction.
* This takes a global lock - only one write transaction can execute against the database at a time.
* TODO: Statements within the transaction must be done on the provided SqliteWriteContext - attempting statements on the SqliteConnection instance will error.
benitav marked this conversation as resolved.
Show resolved Hide resolved
*/
async writeTransaction<T>(
callback: (tx: Transaction) => Promise<T>,
lockTimeout: number = DEFAULT_LOCK_TIMEOUT_MS
Expand All @@ -496,6 +531,11 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
);
}

/**
* Execute a read query every time the source tables are modified.
* TODO: Use throttle to specify the minimum interval between queries.
benitav marked this conversation as resolved.
Show resolved Hide resolved
* TODO: Source tables are automatically detected using `EXPLAIN QUERY PLAN`.
benitav marked this conversation as resolved.
Show resolved Hide resolved
*/
async *watch(sql: string, parameters?: any[], options?: SQLWatchOptions): AsyncIterable<QueryResult> {
//Fetch initial data
yield await this.executeReadOnly(sql, parameters);
Expand Down Expand Up @@ -524,7 +564,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
/**
* Create a Stream of changes to any of the specified tables.
*
* This is preferred over [watch] when multiple queries need to be performed
* This is preferred over {@link watch} when multiple queries need to be performed
* together when data is changed.
*
* Note, do not declare this as `async *onChange` as it will not work in React Native
Expand Down Expand Up @@ -582,6 +622,9 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
});
}

/**
* TODO
benitav marked this conversation as resolved.
Show resolved Hide resolved
*/
private async executeReadOnly(sql: string, params: any[]) {
await this.waitForReady();
return this.database.readLock((tx) => tx.execute(sql, params));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Schema } from '../db/schema/Schema';
import { AbstractPowerSyncDatabase, PowerSyncDatabaseOptions } from './AbstractPowerSyncDatabase';

export interface PowerSyncOpenFactoryOptions extends Partial<PowerSyncDatabaseOptions> {
/** Schema used for the local database. */
schema: Schema;
/**
* Filename for the database.
Expand All @@ -20,6 +21,9 @@ export abstract class AbstractPowerSyncDatabaseOpenFactory {
options.logger = options.logger ?? Logger.get(`PowerSync ${this.options.dbFilename}`);
}

/**
* Schema used for the local database.
*/
get schema() {
return this.options.schema;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface PowerSyncBackendConnector {

/** Upload local changes to the app backend.
*
* Use [PowerSyncDatabase.getCrudBatch] to get a batch of changes to upload. See [DevConnector] for an example implementation.
* Use {@link AbstractPowerSyncDatabase.getCrudBatch} to get a batch of changes to upload.
*
* Any thrown errors will result in a retry after the configured wait period (default: 5 seconds).
*/
Expand Down
12 changes: 12 additions & 0 deletions packages/powersync-sdk-common/src/client/sync/bucket/CrudBatch.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import { CrudEntry } from './CrudEntry';

/**
* TODO
benitav marked this conversation as resolved.
Show resolved Hide resolved
*/
export class CrudBatch {
constructor(
/**
* List of client-side changes.
*/
public crud: CrudEntry[],
/**
* true if there are more changes in the local queue.
*/
public haveMore: boolean,
/**
* Call to remove the changes from the local queue, once successfully uploaded.
*/
public complete: (writeCheckpoint?: string) => Promise<void>
) {}
}
27 changes: 27 additions & 0 deletions packages/powersync-sdk-common/src/client/sync/bucket/CrudEntry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,33 @@ export type CrudEntryOutputJSON = {
data: Record<string, any>;
};

/**
* A single client-side change.
*/
export class CrudEntry {
/**
* Auto-incrementing client-side id.
*/
clientId: number;
/**
* ID of the changed row.
*/
id: string;
/**
* Type of change.
*/
op: UpdateType;
/**
* Data associated with the change.
*/
opData?: Record<string, any>;
/**
* Table that contained the change.
*/
table: string;
/**
* Auto-incrementing transaction id. This is the same for all operations within the same transaction.
*/
transactionId?: number;

static fromRow(dbRow: CrudEntryJSON) {
Expand All @@ -67,6 +88,9 @@ export class CrudEntry {
this.transactionId = transactionId;
}

/**
* Converts the change to JSON format.
*/
toJSON(): CrudEntryOutputJSON {
return {
op_id: this.clientId,
Expand All @@ -78,6 +102,9 @@ export class CrudEntry {
};
}

/**
* The hash code for this object.
*/
hashCode() {
return hash([this.transactionId, this.clientId, this.op, this.table, this.id, this.opData]);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import { CrudBatch } from './CrudBatch';
import { CrudEntry } from './CrudEntry';

/**
* TODO
benitav marked this conversation as resolved.
Show resolved Hide resolved
*/
export class CrudTransaction extends CrudBatch {
constructor(
/**
* List of client-side changes.
*/
public crud: CrudEntry[],
/**
* Call to remove the changes from the local queue, once successfully uploaded.
*/
public complete: (checkpoint?: string) => Promise<void>,
/**
* Unique transaction id.
benitav marked this conversation as resolved.
Show resolved Hide resolved
*/
public transactionId?: number
) {
super(crud, false, complete);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,6 @@ export class SqliteBucketStorage implements BucketStorageAdapter {

/**
* Mark a bucket for deletion.
*
* @param bucket
*/
private async deleteBucket(bucket: string) {
// Delete a bucket, but allow it to be re-created.
Expand Down
Loading
Loading