Skip to content

Commit

Permalink
Rename file and use ESLint
Browse files Browse the repository at this point in the history
  • Loading branch information
darunrs committed Jul 18, 2024
1 parent bd8d8d6 commit 274d8f9
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 72 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TableDefinitionNames } from "../indexer";
import InMemoryDmlHandler from "./dml-handler-fixture";
import InMemoryDmlHandler from "./in-memory-dml-handler";

const DEFAULT_ITEM_1_WITHOUT_ID = {
account_id: 'TEST_NEAR',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { AST, Parser } from "node-sql-parser";
import { TableDefinitionNames } from "../indexer";
import { PostgresRow, WhereClauseMulti, WhereClauseSingle } from "./dml-handler";
import { DmlHandlerI } from "./dml-handler";
import { type AST, Parser } from 'node-sql-parser';
import { type TableDefinitionNames } from '../indexer';
import { type PostgresRow, type WhereClauseMulti, type WhereClauseSingle, type DmlHandlerI } from './dml-handler';

// TODO: Define class to represent specification
interface TableSpecification {
Expand All @@ -13,9 +12,9 @@ interface TableSpecification {

class PostgresRowEntity {
data: PostgresRow;
private primaryKeys: string[];
private readonly primaryKeys: string[];

constructor(data: any, primaryKeys: string[]) {
constructor (data: any, primaryKeys: string[]) {
this.data = data;
this.primaryKeys = primaryKeys.sort();

Expand All @@ -27,26 +26,26 @@ class PostgresRowEntity {
}
}

public primaryKey(): string {
public primaryKey (): string {
return JSON.stringify(
this.primaryKeys.reduce((acc, key) => {
this.primaryKeys.reduce<Record<string, any>>((acc, key) => {
acc[key] = this.data[key];
return acc;
}, {} as Record<string, any>)
}, {})
);
}

public isEqualRow(row: PostgresRow): boolean {
public isEqualRow (row: PostgresRow): boolean {
return this.primaryKeys.every(primaryKey => {
return row[primaryKey] === this.data[primaryKey];
});
}

public isEqualEntity(entity: PostgresRowEntity): boolean {
public isEqualEntity (entity: PostgresRowEntity): boolean {
return this.primaryKey() === entity.primaryKey();
}

public isEqualCriteria(criteria: WhereClauseMulti): boolean {
public isEqualCriteria (criteria: WhereClauseMulti): boolean {
return Object.keys(criteria).every(attribute => {
const toMatchValue = criteria[attribute];
if (Array.isArray(toMatchValue)) {
Expand All @@ -56,8 +55,8 @@ class PostgresRowEntity {
});
}

public update(updateObject: PostgresRow): void {
Object.keys(updateObject).map(updateKey => {
public update (updateObject: PostgresRow): void {
Object.keys(updateObject).forEach(updateKey => {
this.data[updateKey] = updateObject[updateKey];
});
}
Expand All @@ -68,15 +67,15 @@ class TableData {
data: PostgresRowEntity[];
serialCounter: Map<string, number>;

constructor(tableSpec: TableSpecification) {
constructor (tableSpec: TableSpecification) {
this.specification = tableSpec;
this.data = [];
this.serialCounter = new Map();
}

public getEntitiesByCriteria(criteria: WhereClauseMulti, limit: number | null): PostgresRowEntity[] {
public getEntitiesByCriteria (criteria: WhereClauseMulti, limit: number | null): PostgresRowEntity[] {
const matchedRows: PostgresRowEntity[] = [];
this.data.map(row => {
this.data.forEach(row => {
if (row.isEqualCriteria(criteria)) {
if (!limit || (limit && matchedRows.length < limit)) {
matchedRows.push(row);
Expand All @@ -86,41 +85,41 @@ class TableData {
return matchedRows;
}

private getSerialValue(columnName: string): number {
private getSerialValue (columnName: string): number {
const serialCounterKey = `${this.specification.tableName}-${columnName}`;
let counterValue: number = this.serialCounter.get(serialCounterKey) ?? 1;
const counterValue: number = this.serialCounter.get(serialCounterKey) ?? 1;
this.serialCounter.set(serialCounterKey, counterValue + 1);
return counterValue;
}

private fillSerialValues(row: PostgresRow): void {
private fillSerialValues (row: PostgresRow): void {
for (const serialColumnName of this.specification.serialColumns) {
if (row[serialColumnName] === undefined) {
row[serialColumnName] = this.getSerialValue(serialColumnName);
}
}
}

private createEntityFromRow(row: PostgresRow): PostgresRowEntity {
private createEntityFromRow (row: PostgresRow): PostgresRowEntity {
// TODO: Fill default values
// TODO: Assert non null values
this.fillSerialValues(row);
return new PostgresRowEntity(row, this.specification.primaryKeyColumns);
}

public rowIsUnique(otherRow: PostgresRow): boolean {
public rowIsUnique (otherRow: PostgresRow): boolean {
return this.data.every(entity => {
return !entity.isEqualRow(otherRow);
});
}

private entityIsUnique(otherEntity: PostgresRowEntity): boolean {
private entityIsUnique (otherEntity: PostgresRowEntity): boolean {
return this.data.every(entity => {
return !entity.isEqualEntity(otherEntity);
});
}

public insertRow(row: PostgresRow): PostgresRowEntity {
public insertRow (row: PostgresRow): PostgresRowEntity {
const entity: PostgresRowEntity = this.createEntityFromRow(row);
if (!this.entityIsUnique(entity)) {
throw new Error(`Cannot insert row twice into the same table: ${JSON.stringify(entity.data)}`);
Expand All @@ -130,7 +129,7 @@ class TableData {
return entity;
}

public insertEntity(entity: PostgresRowEntity): PostgresRowEntity {
public insertEntity (entity: PostgresRowEntity): PostgresRowEntity {
if (!this.entityIsUnique(entity)) {
throw new Error(`Cannot insert row twice into the same table: ${JSON.stringify(entity.data)}`);
}
Expand All @@ -139,12 +138,12 @@ class TableData {
return entity;
}

public removeEntitiesByCriteria(criteria: WhereClauseMulti): PostgresRowEntity[] {
public removeEntitiesByCriteria (criteria: WhereClauseMulti): PostgresRowEntity[] {
const remainingRows: PostgresRowEntity[] = [];
const matchedRows: PostgresRowEntity[] = [];
this.data.map(entity => {
this.data.forEach(entity => {
if (entity.isEqualCriteria(criteria)) {
matchedRows.push(entity)
matchedRows.push(entity);
} else {
remainingRows.push(entity);
}
Expand All @@ -157,14 +156,14 @@ class TableData {
class IndexerData {
private readonly tables: Map<string, TableData>;

constructor(schema: AST[]) {
constructor (schema: AST[]) {
this.tables = this.initializeTables(schema);
}

private initializeTables(schemaAST: AST[]): Map<string, TableData> {
const tables: Map<string, TableData> = new Map();
private initializeTables (schemaAST: AST[]): Map<string, TableData> {
const tables = new Map<string, TableData>();
for (const statement of schemaAST) {
if (statement.type === "create" && statement.keyword === "table") {
if (statement.type === 'create' && statement.keyword === 'table') {
const tableSpec = this.createTableSpecification(statement);
tables.set(tableSpec.tableName, new TableData(tableSpec));
}
Expand All @@ -173,7 +172,7 @@ class IndexerData {
return tables;
}

private createTableSpecification(createTableStatement: any): TableSpecification {
private createTableSpecification (createTableStatement: any): TableSpecification {
// TODO: Track foreign key columns and manage them during inserts/updates
const tableName = createTableStatement.table[0].table;
const columnNames: string[] = [];
Expand All @@ -194,7 +193,7 @@ class IndexerData {
if (columnDefinition.primary_key) {
primaryKeyColumns.push(columnName);
}
} else if (columnDefinition.constraint_type === "primary key") {
} else if (columnDefinition.constraint_type === 'primary key') {
for (const primaryKey of columnDefinition.definition) {
primaryKeyColumns.push(primaryKey.column.expr.value);
}
Expand All @@ -210,21 +209,21 @@ class IndexerData {
return tableSpec;
}

private getColumnName(columnDefinition: any): string {
private getColumnName (columnDefinition: any): string {
if (columnDefinition.column?.type === 'column_ref') {
return columnDefinition.column.column.expr.value;
}
return "";
return '';
}

private selectColumnsFromRow(row: PostgresRow, columnsToSelect: string[]): PostgresRow {
return columnsToSelect.reduce((newRow, columnName) => {
private selectColumnsFromRow (row: PostgresRow, columnsToSelect: string[]): PostgresRow {
return columnsToSelect.reduce<PostgresRow>((newRow, columnName) => {
newRow[columnName] = columnName in row ? row[columnName] : undefined;
return newRow;
}, {} as PostgresRow);
}, {});
}

private getTableData(tableName: string): TableData {
private getTableData (tableName: string): TableData {
const tableData = this.tables.get(tableName);
if (!tableData) {
throw new Error(`Invalid table name provided: ${tableName}`);
Expand All @@ -233,11 +232,11 @@ class IndexerData {
return tableData;
}

private copyRow(row: PostgresRow): PostgresRow {
private copyRow (row: PostgresRow): PostgresRow {
return JSON.parse(JSON.stringify(row));
}

private copyDataFromEntities(entities: PostgresRowEntity[]): PostgresRow[] {
private copyDataFromEntities (entities: PostgresRowEntity[]): PostgresRow[] {
const copiedRowData: PostgresRow[] = [];
for (const entity of entities) {
const copiedRow = this.copyRow(entity.data);
Expand All @@ -247,14 +246,14 @@ class IndexerData {
return copiedRowData;
}

public select(tableName: string, criteria: WhereClauseMulti, limit: number | null): PostgresRow[] {
public select (tableName: string, criteria: WhereClauseMulti, limit: number | null): PostgresRow[] {
const tableData = this.getTableData(tableName);
const matchedRows = tableData.getEntitiesByCriteria(criteria, limit);

return this.copyDataFromEntities(matchedRows);
}

public insert(tableName: string, rowsToInsert: PostgresRow[]): PostgresRow[] {
public insert (tableName: string, rowsToInsert: PostgresRow[]): PostgresRow[] {
// TODO: Check types of columns
// TODO: Verify columns are correctly named, and have any required values
// TODO: Verify inserts are unique before actual insertion
Expand All @@ -272,7 +271,7 @@ class IndexerData {
return this.copyDataFromEntities(insertedRows);
}

public update(tableName: string, criteria: WhereClauseSingle, updateObject: PostgresRow): PostgresRow[] {
public update (tableName: string, criteria: WhereClauseSingle, updateObject: PostgresRow): PostgresRow[] {
// TODO: Validate criteria passed in has valid column names
const tableData = this.getTableData(tableName);
const updatedRows: PostgresRowEntity[] = [];
Expand All @@ -286,7 +285,7 @@ class IndexerData {
return this.copyDataFromEntities(updatedRows);
}

public upsert(tableName: string, rowsToUpsert: PostgresRow[], conflictColumns: string[], updateColumns: string[]): PostgresRow[] {
public upsert (tableName: string, rowsToUpsert: PostgresRow[], conflictColumns: string[], updateColumns: string[]): PostgresRow[] {
// TODO: Verify conflictColumns is a superset of primary key set (For uniqueness constraint)
const tableData = this.getTableData(tableName);
const upsertedRows: PostgresRowEntity[] = [];
Expand All @@ -298,7 +297,7 @@ class IndexerData {

if (rowsMatchingUpdate.length > 1) {
throw new Error('Conflict update criteria cannot affect row twice');
} else if (rowsMatchingUpdate.length == 1) {
} else if (rowsMatchingUpdate.length === 1) {
const matchedEntity = rowsMatchingUpdate[0];
if (upsertedRows.some(upsertedEntity => upsertedEntity.isEqualEntity(matchedEntity))) {
throw new Error('Conflict update criteria cannot affect row twice');
Expand All @@ -315,7 +314,7 @@ class IndexerData {
return this.copyDataFromEntities(upsertedRows);
}

public delete(tableName: string, deleteCriteria: WhereClauseMulti): PostgresRow[] {
public delete (tableName: string, deleteCriteria: WhereClauseMulti): PostgresRow[] {
const tableData = this.getTableData(tableName);
const deletedRows = tableData.removeEntitiesByCriteria(deleteCriteria);

Expand All @@ -326,35 +325,34 @@ class IndexerData {
export default class InMemoryDmlHandler implements DmlHandlerI {
private readonly indexerData: IndexerData;

constructor(schema: string) {
constructor (schema: string) {
const parser = new Parser();
let schemaAST = parser.astify(schema, { database: 'Postgresql' });
schemaAST = Array.isArray(schemaAST) ? schemaAST : [schemaAST]; // Ensure iterable
this.indexerData = new IndexerData(schemaAST);
}

public async insert(tableDefinitionNames: TableDefinitionNames, rowsToInsert: PostgresRow[]): Promise<PostgresRow[]> {
public async insert (tableDefinitionNames: TableDefinitionNames, rowsToInsert: PostgresRow[]): Promise<PostgresRow[]> {
if (!rowsToInsert?.length) {
return [];
}

return this.indexerData.insert(tableDefinitionNames.tableName, rowsToInsert);
}

public async select(tableDefinitionNames: TableDefinitionNames, whereObject: WhereClauseMulti, limit: number | null = null): Promise<PostgresRow[]> {
public async select (tableDefinitionNames: TableDefinitionNames, whereObject: WhereClauseMulti, limit: number | null = null): Promise<PostgresRow[]> {
return this.indexerData.select(tableDefinitionNames.tableName, whereObject, limit);
}

public async update(tableDefinitionNames: TableDefinitionNames, whereObject: WhereClauseSingle, updateObject: any): Promise<PostgresRow[]> {
public async update (tableDefinitionNames: TableDefinitionNames, whereObject: WhereClauseSingle, updateObject: any): Promise<PostgresRow[]> {
return this.indexerData.update(tableDefinitionNames.tableName, whereObject, updateObject);
}

public async upsert(tableDefinitionNames: TableDefinitionNames, rowsToUpsert: PostgresRow[], conflictColumns: string[], updateColumns: string[]): Promise<PostgresRow[]> {
public async upsert (tableDefinitionNames: TableDefinitionNames, rowsToUpsert: PostgresRow[], conflictColumns: string[], updateColumns: string[]): Promise<PostgresRow[]> {
return this.indexerData.upsert(tableDefinitionNames.tableName, rowsToUpsert, conflictColumns, updateColumns);
}

public async delete(tableDefinitionNames: TableDefinitionNames, whereObject: WhereClauseMulti): Promise<PostgresRow[]> {
public async delete (tableDefinitionNames: TableDefinitionNames, whereObject: WhereClauseMulti): Promise<PostgresRow[]> {
return this.indexerData.delete(tableDefinitionNames.tableName, whereObject);
}
}

Loading

0 comments on commit 274d8f9

Please sign in to comment.