Skip to content

Commit

Permalink
Strict null checks.
Browse files Browse the repository at this point in the history
  • Loading branch information
rkistner committed Feb 29, 2024
1 parent 6a94dbb commit 9b2fc64
Show file tree
Hide file tree
Showing 17 changed files with 51 additions and 45 deletions.
13 changes: 6 additions & 7 deletions packages/kysely-driver/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@
"declaration": true /* Generates corresponding '.d.ts' file. */,
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
"lib": [
"DOM",
"ES2020",
"WebWorker"
] /* Specify library files to be included in the compilation. */,
"lib": ["DOM", "ES2020", "WebWorker"] /* Specify library files to be included in the compilation. */,
"module": "es2020" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
"outDir": "./lib" /* Redirect output structure to the directory. */,
Expand All @@ -18,7 +14,10 @@
"strict": true /* Enable all strict type-checking options. */,
"target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
},
"include": [
"src/**/*",
"include": ["src/**/*"],
"references": [
{
"path": "../powersync-sdk-common"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
super();
this.bucketStorageAdapter = this.generateBucketStorageAdapter();
this.closed = true;
this.currentStatus = null;
this.currentStatus = undefined;
this.options = { ...DEFAULT_POWERSYNC_DB_OPTIONS, ...options };
this._schema = options.schema;
this.ready = false;
Expand Down Expand Up @@ -201,7 +201,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
try {
schema.validate();
} catch (ex) {
this.options.logger.warn('Schema validation failed. Unexpected behaviour could occur', ex);
this.options.logger?.warn('Schema validation failed. Unexpected behaviour could occur', ex);
}
this._schema = schema;
await this.database.execute('SELECT powersync_replace_schema(?)', [JSON.stringify(this.schema.toJSON())]);
Expand Down Expand Up @@ -291,7 +291,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
[tableGlob]
);

if (!existingTableRows.rows.length) {
if (!existingTableRows.rows?.length) {
return;
}
for (const row of existingTableRows.rows._array) {
Expand Down Expand Up @@ -325,11 +325,11 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
`SELECT SUM(cast(data as blob) + 20) as size, count(*) as count FROM ${PSInternalTable.CRUD}`
);

const row = result.rows.item(0);
const row = result.rows!.item(0);
return new UploadQueueStats(row?.count ?? 0, row?.size ?? 0);
} else {
const result = await tx.execute(`SELECT count(*) as count FROM ${PSInternalTable.CRUD}`);
const row = result.rows.item(0);
const row = result.rows!.item(0);
return new UploadQueueStats(row?.count ?? 0);
}
});
Expand Down Expand Up @@ -388,7 +388,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
* 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> {
async getNextCrudTransaction(): Promise<CrudTransaction | null> {
return await this.readTransaction(async (tx) => {
const first = await tx.getOptional<CrudEntryJSON>(
`SELECT id, tx_id, data FROM ${PSInternalTable.CRUD} ORDER BY id ASC LIMIT 1`
Expand Down Expand Up @@ -543,7 +543,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB

const resolvedTables = options?.tables ?? [];
if (!options?.tables) {
const explained = await this.getAll(`EXPLAIN ${sql}`, parameters);
const explained = await this.getAll<{ opcode: string; p3: number; p2: number }>(`EXPLAIN ${sql}`, parameters);
const rootPages = _.chain(explained)
.filter((row) => row['opcode'] == 'OpenRead' && row['p3'] == 0 && _.isNumber(row['p2']))
.map((row) => row['p2'])
Expand Down Expand Up @@ -571,10 +571,11 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
* Note, do not declare this as `async *onChange` as it will not work in React Native
*/
onChange(options?: SQLWatchOptions): AsyncIterable<WatchOnChangeEvent> {
const watchedTables = options.tables ?? [];
const resolvedOptions = options ?? {};
const watchedTables = resolvedOptions.tables ?? [];

let throttledTableUpdates: string[] = [];
const throttleMs = options.throttleMs ?? DEFAULT_WATCH_THROTTLE_MS;
const throttleMs = resolvedOptions.throttleMs ?? DEFAULT_WATCH_THROTTLE_MS;

return new EventIterator<WatchOnChangeEvent>((eventOptions) => {
const flushTableUpdates = _.throttle(
Expand All @@ -593,7 +594,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB

const dispose = this.database.registerListener({
tablesUpdated: async (update) => {
const { rawTableNames } = options;
const { rawTableNames } = resolvedOptions;

const tables = isBatchedUpdateNotification(update) ? update.tables : [update.table];

Expand All @@ -613,7 +614,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
}
});

options.signal?.addEventListener('abort', () => {
resolvedOptions.signal?.addEventListener('abort', () => {
dispose();
eventOptions.stop();
// Maybe fail?
Expand All @@ -626,7 +627,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
/**
* @ignore
*/
private async executeReadOnly(sql: string, params: any[]) {
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 @@ -33,7 +33,6 @@ export abstract class AbstractPowerSyncDatabaseOpenFactory {
generateOptions(): PowerSyncDatabaseOptions {
return {
database: this.openDB(),
schema: this.schema,
...this.options
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ export type CrudEntryDataJSON = {
};

/**
* The output JSOn seems to be a third type of JSON, not the same as the input JSON.
* The output JSON seems to be a third type of JSON, not the same as the input JSON.
*/
export type CrudEntryOutputJSON = {
op_id: number;
op: UpdateType;
type: string;
id: string;
tx_id?: number;
data: Record<string, any>;
data?: Record<string, any>;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class SyncDataBucket {
return new SyncDataBucket(
row.bucket,
row.data.map((entry) => OplogEntry.fromRow(entry)),
row.has_more,
row.has_more ?? false,
row.after,
row.next_after
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export interface AbstractStreamingSyncImplementationOptions {
}

export interface StreamingSyncImplementationListener extends BaseListener {
statusChanged?: (status: SyncStatus) => void;
statusChanged?: ((status: SyncStatus) => void) | undefined;
}

export const DEFAULT_CRUD_UPLOAD_THROTTLE_MS = 1000;
Expand All @@ -69,7 +69,7 @@ export abstract class AbstractStreamingSyncImplementation extends BaseObserver<S
this.options = { ...DEFAULT_STREAMING_SYNC_OPTIONS, ...options };
this.syncStatus = new SyncStatus({
connected: false,
lastSyncedAt: null,
lastSyncedAt: undefined,
dataFlow: {
uploading: false,
downloading: false
Expand Down Expand Up @@ -245,7 +245,7 @@ export abstract class AbstractStreamingSyncImplementation extends BaseObserver<S
await this.options.adapter.setTargetCheckpoint(targetCheckpoint);
} else if (isStreamingSyncCheckpointComplete(line)) {
this.logger.debug('Checkpoint complete', targetCheckpoint);
const result = await this.options.adapter.syncLocalDatabase(targetCheckpoint);
const result = await this.options.adapter.syncLocalDatabase(targetCheckpoint!);
if (!result.checkpointValid) {
// This means checksums failed. Start again with a new checkpoint.
// TODO: better back-off
Expand Down Expand Up @@ -325,7 +325,7 @@ export abstract class AbstractStreamingSyncImplementation extends BaseObserver<S
lastSyncedAt: new Date()
});
} else if (_.isEqual(validatedCheckpoint, targetCheckpoint)) {
const result = await this.options.adapter.syncLocalDatabase(targetCheckpoint);
const result = await this.options.adapter.syncLocalDatabase(targetCheckpoint!);
if (!result.checkpointValid) {
// This means checksums failed. Start again with a new checkpoint.
// TODO: better back-off
Expand Down Expand Up @@ -355,7 +355,7 @@ export abstract class AbstractStreamingSyncImplementation extends BaseObserver<S
});
}

async *streamingSyncRequest(req: StreamingSyncRequest, signal: AbortSignal): AsyncGenerator<StreamingSyncLine> {
async *streamingSyncRequest(req: StreamingSyncRequest, signal?: AbortSignal): AsyncGenerator<StreamingSyncLine> {
const body = await this.options.remote.postStreaming('/sync/stream', req, {}, signal);
const stream = ndjsonStream(body);
const reader = stream.getReader();
Expand Down
2 changes: 1 addition & 1 deletion packages/powersync-sdk-common/src/db/crud/SyncStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export class SyncStatus {
}

getMessage() {
const { dataFlow } = this.options;
const dataFlow = this.dataFlowStatus;
return `SyncStatus<connected: ${this.connected} lastSyncedAt: ${this.lastSyncedAt}. Downloading: ${dataFlow.downloading}. Uploading: ${dataFlow.uploading}`;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class UploadQueueStats {
/**
* Size of the upload queue in bytes.
*/
public size: number = null
public size: number | null = null
) {}

toString() {
Expand Down
2 changes: 1 addition & 1 deletion packages/powersync-sdk-common/src/db/schema/Index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class Index {
}

get columns() {
return this.options.columns;
return this.options.columns ?? [];
}

toJSON(table: Table) {
Expand Down
8 changes: 4 additions & 4 deletions packages/powersync-sdk-common/src/db/schema/Table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,23 @@ export class Table {
}

get viewName() {
return this.viewNameOverride || this.name;
return this.viewNameOverride ?? this.name;
}

get columns() {
return this.options.columns;
}

get indexes() {
return this.options.indexes;
return this.options.indexes ?? [];
}

get localOnly() {
return this.options.localOnly;
return this.options.localOnly ?? false;
}

get insertOnly() {
return this.options.insertOnly;
return this.options.insertOnly ?? false;
}

get internalName() {
Expand Down
2 changes: 1 addition & 1 deletion packages/powersync-sdk-common/src/utils/BaseObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export interface BaseObserverInterface<T extends BaseListener> {
}

export type BaseListener = {
[key: string]: (...event: any) => any;
[key: string]: ((...event: any) => any) | undefined;
};

export class BaseObserver<T extends BaseListener = BaseListener> implements BaseObserverInterface<T> {
Expand Down
6 changes: 4 additions & 2 deletions packages/powersync-sdk-common/src/utils/mutex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ export async function mutexRunExclusive<T>(
timedOut = true;
reject(new Error('Timeout waiting for lock'));
}, timeout)
: null;
: undefined;

mutex.runExclusive(async () => {
clearTimeout(timeoutId);
if (timeoutId) {
clearTimeout(timeoutId);
}
if (timedOut) return;

try {
Expand Down
3 changes: 2 additions & 1 deletion packages/powersync-sdk-common/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"noStrictGenericChecks": false,
"resolveJsonModule": true,
"skipLibCheck": true,
"target": "esnext"
"target": "esnext",
"strictNullChecks": true
},
"include": ["src/**/*"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ export class ReactNativeRemote extends AbstractRemote {
throw ex;
});

clearTimeout(timeout);
if (timeout != null) {
clearTimeout(timeout);
}

if (!res.ok) {
const text = await res.text();
Expand All @@ -108,7 +110,7 @@ export class ReactNativeRemote extends AbstractRemote {
* The common SDK is a bit oblivious to `ReadableStream` classes.
* This should be improved when moving to Websockets
*/
const reader = res.body.getReader();
const reader = res.body!.getReader();
const outputStream = new ReadableStream({
start(controller) {
return processStream();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class ReactNativeStreamingSyncImplementation extends AbstractStreamingSyn
initLocks() {
const { identifier } = this.options;
if (identifier && LOCKS.has(identifier)) {
this.locks = LOCKS.get(identifier);
this.locks = LOCKS.get(identifier)!;
return;
}

Expand All @@ -46,7 +46,7 @@ export class ReactNativeStreamingSyncImplementation extends AbstractStreamingSyn
}
return lock.acquire(lockOptions.type, async () => {
if (lockOptions.signal?.aborted) {
return null;
throw new Error('Aborted');
}

return lockOptions.callback();
Expand Down
3 changes: 2 additions & 1 deletion packages/powersync-sdk-react-native/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"noStrictGenericChecks": false,
"resolveJsonModule": true,
"skipLibCheck": true,
"target": "esnext"
"target": "esnext",
"strictNullChecks": true
},
"references": [
{
Expand Down
3 changes: 2 additions & 1 deletion packages/powersync-sdk-web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"skipLibCheck": true /* Skip type checking of declaration files. */,
"sourceMap": true /* Generates corresponding '.map' file. */,
"strict": true /* Enable all strict type-checking options. */,
"target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
"strictNullChecks": true
},
"include": ["src/**/*", "tests/**/*"]
}

0 comments on commit 9b2fc64

Please sign in to comment.