Skip to content
Draft
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
2 changes: 1 addition & 1 deletion config-root.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@
"type": "boolean",
"description": "Attempt fail-over to different node when unreachable. Default: true"
},
"shard": { "type": "integer", "description": "Shard id for this instance." },
"shard": { "type": ["integer", "null"], "description": "Shard id for this instance." },
"logging": { "$ref": "#/definitions/loggerConfig" }
}
},
Expand Down
11 changes: 8 additions & 3 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,19 @@ export type {
SubscriptionRequest,
RequestTargetOrId,
} from './resources/ResourceInterface.ts';
export { ResourceInterface } from './resources/ResourceInterface.ts';
export type { ResourceInterface, ResourceStaticInterface } from './resources/ResourceInterface.ts';
export type {
TableInterface,
TableInterface as Table,
TableStaticInterface,
Attribute,
} from './resources/TableInterface.ts';
export type { User } from './security/user.ts';
export type { RecordObject } from './resources/RecordEncoder.ts';
export type { IterableEventQueue } from './resources/IterableEventQueue.ts';
export { RequestTarget } from './resources/RequestTarget.ts';
export { server } from './server/Server';
export { tables, databases, type Table } from './resources/databases.ts';
export type { Attribute } from './resources/Table.ts';
export { tables, databases } from './resources/databases.ts';

export { Scope } from './components/Scope.ts';
export type { FilesOption, FilesOptionObject } from './components/deriveGlobOptions.ts';
Expand Down
3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ exports.RequestTarget = undefined;
exports.RequestTargetOrId = undefined;
exports.Resource = undefined;
exports.ResourceInterface = undefined;
exports.ResourceStaticInterface = undefined;
exports.Scope = undefined;
exports.Session = undefined;
exports.SourceContext = undefined;
exports.SubscriptionRequest = undefined;
exports.Table = undefined;
exports.TableInterface = undefined;
exports.TableStaticInterface = undefined;
exports.User = undefined;

// these are all overwritten by the globals, but need to be here so that Node's static
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
"bin": {
"harper": "./dist/bin/harper.js"
},
"exports": {
".": "./index.js"
},
"types": "./index.d.ts",
"files": [
"dist",
"bin",
Expand Down Expand Up @@ -111,9 +115,6 @@
"onFail": "error"
}
},
"exports": {
".": "./dist/index.js"
},
"devDependencies": {
"@harperdb/code-guidelines": "^0.0.6",
"@types/fs-extra": "^11.0.4",
Expand Down
42 changes: 42 additions & 0 deletions resources/DatabaseInterface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { RocksDatabase } from '@harperfast/rocksdb-js';
import type { Database, RootDatabase } from 'lmdb';

export interface LMDBDatabase extends Database {
customIndex?: any;
isIndexing?: boolean;
indexNulls?: boolean;
}

export interface LMDBRootDatabase extends RootDatabase {
auditStore?: LMDBRootDatabase;
databaseName?: string;
dbisDb?: LMDBDatabase;
isLegacy?: boolean;
needsDeletion?: boolean;
path?: string;
status?: 'open' | 'closed';
}

export interface RocksDatabaseEx extends RocksDatabase {
customIndex?: any;
env: Record<string, any>;
isLegacy?: boolean;
isIndexing?: boolean;
indexNulls?: boolean;
getEntry?: (id: string | number | (string | number)[] | Buffer, options?: any) => { value: any };
}

export interface RocksRootDatabase extends RocksDatabaseEx {
auditStore?: RocksDatabaseEx;
databaseName?: string;
dbisDb?: RocksDatabaseEx;
}

export type DBI =
| LMDBDatabase
| (RocksDatabase & {
customIndex?: any;
isIndexing?: boolean;
indexNulls?: boolean;
rootStore?: RocksRootDatabase;
});
9 changes: 5 additions & 4 deletions resources/Resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ExtendedIterable } from '@harperfast/extended-iterable';
import type { User } from '../security/user.ts';
import type { RecordObject } from './RecordEncoder.js';
import {
import type {
ResourceInterface,
SubscriptionRequest,
Id,
Expand Down Expand Up @@ -314,10 +315,10 @@ export class Resource<Record extends object = any> implements ResourceInterface<
static coerceId(id: string): number | string {
return id;
}
static parseQuery(search, query) {
static parseQuery(search: string, query: RequestTarget): RequestTarget | Query | URLSearchParams | undefined {
return parseQuery(search, query);
}
static parsePath(path, context, query) {
static parsePath(path: string, context: Context, query: URLSearchParams) {
const dotIndex = path.indexOf('.');
if (dotIndex > -1) {
// handle paths of the form /path/id.property
Expand Down Expand Up @@ -436,7 +437,7 @@ export class Resource<Record extends object = any> implements ResourceInterface<
| AsyncIterable<Record & Partial<RecordObject>>
| Promise<AsyncIterable<Record & Partial<RecordObject>>>;

search?(target: RequestTargetOrId): AsyncIterable<Record & Partial<RecordObject>>;
search?(target: RequestTargetOrId): ExtendedIterable<Record & Partial<RecordObject>>;

create?(
newRecord: Partial<Record & RecordObject>,
Expand Down
109 changes: 76 additions & 33 deletions resources/ResourceInterface.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,106 @@
import type { ExtendedIterable } from '@harperfast/extended-iterable';
import type { User } from '../security/user.ts';
import type { OperationFunctionName } from '../server/serverHelpers/serverUtilities.ts';
import { DatabaseTransaction } from './DatabaseTransaction.ts';
import { IterableEventQueue } from './IterableEventQueue.ts';
import type { DatabaseTransaction } from './DatabaseTransaction.ts';
import type { IterableEventQueue } from './IterableEventQueue.ts';
import type { Entry, RecordObject } from './RecordEncoder.ts';
import { RequestTarget } from './RequestTarget.ts';
import type { RequestTarget } from './RequestTarget.ts';

export interface ResourceInterface<Record extends object = any>
extends Partial<RecordObject>, Pick<UpdatableRecord<Record>, 'addTo' | 'subtractFrom'> {
allowCreate(user: User, record: Promise<Record & RecordObject>, context: Context): boolean | Promise<boolean>;
create(newRecord: Partial<Record & RecordObject>, target: RequestTargetOrId): Promise<Record & Partial<RecordObject>>;
post(target: RequestTargetOrId, newRecord: Partial<Record & RecordObject>): Promise<Record & Partial<RecordObject>>;

allowRead(user: User, target: RequestTarget, context: Context): boolean | Promise<boolean>;
get?(
get(
target?: RequestTargetOrId
):
| (Record & Partial<RecordObject>)
| Promise<Record & Partial<RecordObject>>
| AsyncIterable<Record & Partial<RecordObject>>
| Promise<AsyncIterable<Record & Partial<RecordObject>>>;
search?(target: RequestTarget): AsyncIterable<Record & Partial<RecordObject>>;

allowCreate(user: User, record: Promise<Record & RecordObject>, context: Context): boolean | Promise<boolean>;
create?(
newRecord: Partial<Record & RecordObject>,
target: RequestTargetOrId
): void | (Record & Partial<RecordObject>) | Promise<Record & Partial<RecordObject>>;
post?(
target: RequestTargetOrId,
newRecord: Partial<Record & RecordObject>
): void | (Record & Partial<RecordObject>) | Promise<Record & Partial<RecordObject>>;
): Promise<Record & Partial<RecordObject>> | ExtendedIterable<Record & Partial<RecordObject>>;
search(target: RequestTarget): ExtendedIterable<Record & Partial<RecordObject>>;

allowUpdate(user: User, record: Promise<Record & RecordObject>, context: Context): boolean | Promise<boolean>;
put?(
record: Record & RecordObject,
target?: RequestTargetOrId
): void | (Record & Partial<RecordObject>) | Promise<void | (Record & Partial<RecordObject>)>;
patch?(
record: Partial<Record & RecordObject>,
target: RequestTargetOrId
): void | (Record & Partial<RecordObject>) | Promise<void | (Record & Partial<RecordObject>)>;
update?(updates: Record & RecordObject, fullUpdate: true): ResourceInterface<Record & Partial<RecordObject>>;
update?(
update(updates: Record & RecordObject, fullUpdate: true): ResourceInterface<Record & Partial<RecordObject>>;
update(
updates: Partial<Record & RecordObject>,
fullUpdate?: boolean
):
| ResourceInterface<Record & Partial<RecordObject>>
| Promise<ResourceInterface<Record & Partial<RecordObject>> | UpdatableRecord<Record & Partial<RecordObject>>>;
put(record: Record & RecordObject, target?: RequestTargetOrId): Promise<void>;
patch(record: Partial<Record & RecordObject>, target: RequestTargetOrId): Promise<void>;

allowDelete(user: User, target: RequestTarget, context: Context): boolean | Promise<boolean>;
delete?(target: RequestTargetOrId): boolean | Promise<boolean>;
delete(target: RequestTargetOrId): Promise<boolean>;

invalidate(target: RequestTargetOrId): void | Promise<void>;

publish?(target: RequestTargetOrId, record: Record, options?: any): void;
subscribe?(request: SubscriptionRequest): AsyncIterable<Record> | Promise<AsyncIterable<Record>>;
subscribe(request: SubscriptionRequest): AsyncIterable<Record> | Promise<AsyncIterable<Record>>;
publish(target: RequestTargetOrId, record: Record, options?: any): void;

doesExist(): boolean;
wasLoadedFromSource(): boolean | void;

getCurrentUser(): User | undefined;
}

export interface ResourceStaticInterface<Record extends object = any> {
new (identifier?: Id, source?: ResourceStaticInterface<Record>): ResourceInterface<Record>;

loadAsInstance?: boolean;

getNewId(): Id;
coerceId(id: Id): Id;

create(idPrefix: Id, record: Record, context: Context): Promise<Id>;
create(record: Record, context: Context): Promise<Id>;
create(idPrefix: any, record: Record, context?: Context): Promise<Id>;
post(target: RequestTargetOrId, dataOrContext?: Record | Context, context?: Context): Promise<Record>;
post(target: RequestTargetOrId, dataOrContext?: Record[] | Context, context?: Context): Promise<Record>;
post(target: RequestTargetOrId, dataOrContext?: Record | Context, context?: Context): Promise<Record>;

get(
target: RequestTargetOrId,
dataOrContext?: Record | Context,
context?: Context
): Promise<Record> | ExtendedIterable<Record>;
search(target: RequestTargetOrId, dataOrContext?: Record | Context, context?: Context): ExtendedIterable<Record>;
query(target: RequestTargetOrId, dataOrContext?: Record | Context, context?: Context): ExtendedIterable<Record>;

update(target: RequestTargetOrId, dataOrContext?: Record | Context, context?: Context): Promise<Record>;
put(target: RequestTargetOrId, dataOrContext?: Record | Context, context?: Context): Promise<void>;
put(target: RequestTargetOrId, dataOrContext?: Record[] | Context, context?: Context): Promise<void>;
patch(target: RequestTargetOrId, dataOrContext?: Record | Context, context?: Context): Promise<void>;

delete(target: RequestTargetOrId, dataOrContext?: Record | Context, context?: Context): Promise<void>;

invalidate(target: RequestTargetOrId, dataOrContext?: Record | Context, context?: Context): Promise<Record> | Record;

connect(target: RequestTargetOrId, dataOrContext?: Record | Context, context?: Context): IterableEventQueue;
subscribe(target: RequestTargetOrId, dataOrContext?: Record | Context, context?: Context): AsyncIterable<Record>;
publish(target: RequestTargetOrId, dataOrContext?: Record | Context, context?: Context): void;

copy(
target: RequestTargetOrId,
dataOrContext?: Record | Context,
context?: Context
): Promise<Record> | Record | void | Promise<void>;
move(
target: RequestTargetOrId,
dataOrContext?: Record | Context,
context?: Context
): Promise<Record> | Record | void | Promise<void>;

parseQuery(search: string, query: RequestTarget): RequestTarget | Query | URLSearchParams | undefined;
parsePath(path: string, context: Context, query: URLSearchParams): string | { property: string; id: string };
isCollection: boolean;

getResource(
target: RequestTargetOrId,
request: Context | SourceContext,
resourceOptions: any
): Promise<ResourceInterface> | ResourceInterface;
}

export interface Session {
id?: any;
user?: User;
Expand Down
2 changes: 1 addition & 1 deletion resources/RocksIndexStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
type StorePutOptions,
type StoreRemoveOptions,
} from '@harperfast/rocksdb-js';
import { Id } from './ResourceInterface.ts';
import type { Id } from './ResourceInterface.ts';
import { MAXIMUM_KEY } from 'ordered-binary';

declare module '@harperfast/rocksdb-js' {
Expand Down
Loading
Loading