Skip to content

Commit

Permalink
Support composite indices in schema literal types
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvdrum committed Jan 10, 2022
1 parent 6fc22ec commit 69af9db
Show file tree
Hide file tree
Showing 9 changed files with 35 additions and 19 deletions.
6 changes: 3 additions & 3 deletions src/plugins/dev-mode/check-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type {
TopLevelProperty
} from '../../types';
import {
flattenObject,
flattenObject, isMaybeReadonlyArray,
trimDots
} from '../../util';
import { rxDocumentProperties } from './entity-properties';
Expand Down Expand Up @@ -320,7 +320,7 @@ export function checkSchema(jsonSchema: RxJsonSchema<any>) {
// check format of jsonSchema.indexes
if (jsonSchema.indexes) {
// should be an array
if (!Array.isArray(jsonSchema.indexes)) {
if (!isMaybeReadonlyArray(jsonSchema.indexes)) {
throw newRxError('SC18', {
indexes: jsonSchema.indexes,
schema: jsonSchema
Expand Down Expand Up @@ -378,7 +378,7 @@ export function checkSchema(jsonSchema: RxJsonSchema<any>) {
/* check types of the indexes */
(jsonSchema.indexes || [])
.reduce((indexPaths: string[], currentIndex) => {
if (Array.isArray(currentIndex)) {
if (isMaybeReadonlyArray(currentIndex)) {
indexPaths.concat(currentIndex);
} else {
indexPaths.push(currentIndex);
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/key-compression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import type {
RxCollection,
CompositePrimaryKey
} from '../types';
import { flatClone } from '../util';
import {flatClone, isMaybeReadonlyArray} from '../util';

declare type CompressionState = {
table: CompressionTable;
Expand Down Expand Up @@ -87,7 +87,7 @@ export function createCompressionState(
*/
if (schema.indexes) {
const newIndexes = schema.indexes.map(idx => {
if (Array.isArray(idx)) {
if (isMaybeReadonlyArray(idx)) {
return idx.map(subIdx => compressedPath(table, subIdx));
} else {
return compressedPath(table, idx);
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/lokijs/rx-storage-instance-loki.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
flatClone,
now,
ensureNotFalsy,
randomCouchString
randomCouchString, isMaybeReadonlyArray
} from '../../util';
import { newRxError } from '../../rx-error';
import { getPrimaryFieldOfPrimaryKey } from '../../rx-schema';
Expand Down Expand Up @@ -547,7 +547,7 @@ export async function createLokiLocalState<RxDocType>(
const indices: string[] = [];
if (params.schema.indexes) {
params.schema.indexes.forEach(idx => {
if (!Array.isArray(idx)) {
if (!isMaybeReadonlyArray(idx)) {
indices.push(idx);
}
});
Expand Down
6 changes: 3 additions & 3 deletions src/plugins/pouchdb/rx-storage-pouchdb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import type {
RxJsonSchema,
RxStorageInstanceCreationParams,
RxStorage,
RxKeyObjectStorageInstanceCreationParams
RxKeyObjectStorageInstanceCreationParams, MaybeReadonly
} from '../../types';

import {
flatClone,
adapterObject
adapterObject, isMaybeReadonlyArray
} from '../../util';
import {
isLevelDown,
Expand Down Expand Up @@ -167,7 +167,7 @@ export async function createIndexesOnPouch(

await Promise.all(
schema.indexes.map(async (indexMaybeArray) => {
let indexArray: string[] = Array.isArray(indexMaybeArray) ? indexMaybeArray : [indexMaybeArray];
let indexArray: MaybeReadonly<string[]> = isMaybeReadonlyArray(indexMaybeArray) ? indexMaybeArray : [indexMaybeArray];

/**
* replace primary key with _id
Expand Down
10 changes: 5 additions & 5 deletions src/rx-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
hash,
sortObject,
overwriteGetterForCaching,
flatClone
flatClone, isMaybeReadonlyArray
} from './util';
import {
newRxError,
Expand All @@ -21,13 +21,13 @@ import {
import type {
CompositePrimaryKey,
DeepMutable,
DeepReadonly,
DeepReadonly, MaybeReadonly,
PrimaryKey,
RxJsonSchema
} from './types';

export class RxSchema<T = any> {
public indexes: string[][];
public indexes: MaybeReadonly<string[]>[];
public primaryPath: keyof T;
public finalFields: string[];

Expand Down Expand Up @@ -213,8 +213,8 @@ export class RxSchema<T = any> {

export function getIndexes<T = any>(
jsonSchema: RxJsonSchema<T>
): string[][] {
return (jsonSchema.indexes || []).map(index => Array.isArray(index) ? index : [index]);
): MaybeReadonly<string[]>[] {
return (jsonSchema.indexes || []).map(index => isMaybeReadonlyArray(index) ? index : [index]);
}

export function getPrimaryFieldOfPrimaryKey<RxDocType>(
Expand Down
2 changes: 1 addition & 1 deletion src/types/rx-error.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export interface RxErrorParameters {
readonly collection?: any;
readonly database?: any;
readonly indexes?: Array<string | string[]> | Readonly<Array<string | string[]>>;
readonly index?: string | string[];
readonly index?: string | string[] | readonly string[];
readonly plugin?: RxPlugin | any;
readonly plugins?: Set<RxPlugin | any>;
}
Expand Down
4 changes: 2 additions & 2 deletions src/types/rx-schema.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AsTyped } from 'as-typed';
import { StringKeys } from './util';
import {MaybeReadonly, StringKeys} from './util';

/**
* @link https://github.com/types/lib-json-schema/blob/master/v4/index.d.ts
Expand Down Expand Up @@ -115,7 +115,7 @@ export declare class RxJsonSchema<
required?: StringKeys<RxDocType>[] | readonly StringKeys<RxDocType>[];


indexes?: (string | string[])[] | readonly (string | string[])[];
indexes?: MaybeReadonly<string | MaybeReadonly<string[]>>[];
encrypted?: string[];
keyCompression?: boolean;
/**
Expand Down
2 changes: 2 additions & 0 deletions src/types/util.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type DeepReadonlyObject<T> = {
readonly [P in keyof T]: DeepReadonly<T[P]>;
};

export type MaybeReadonly<T> = T | Readonly<T>;


/**
* Opposite of DeepReadonly,
Expand Down
16 changes: 15 additions & 1 deletion src/util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { BlobBuffer, DeepReadonlyObject } from './types';
import type {BlobBuffer, DeepReadonlyObject, MaybeReadonly} from './types';
import {
default as deepClone
} from 'clone';
Expand Down Expand Up @@ -465,6 +465,20 @@ export function getFromObjectOrThrow<V>(
return val;
}

/**
* returns true if the supplied argument is either an Array<T> or a Readonly<Array<T>>
*/
export function isMaybeReadonlyArray(x: any): x is MaybeReadonly<any[]> {
// While this looks strange, it's a workaround for an issue in TypeScript:
// https://github.com/microsoft/TypeScript/issues/17002
//
// The problem is that `Array.isArray` as a type guard returns `false` for a readonly array,
// but at runtime the object is an array and the runtime call to `Array.isArray` would return `true`.
// The type predicate here allows for both `Array<T>` and `Readonly<Array<T>>` to pass a type check while
// still performing runtime type inspection.
return Array.isArray(x);
}

export const blobBufferUtil = {
/**
* depending if we are on node or browser,
Expand Down

0 comments on commit 69af9db

Please # to comment.