envio
Version:
A latency and sync speed optimized, developer friendly blockchain data indexer.
327 lines (308 loc) • 14.5 kB
JavaScript
// Generated by ReScript, PLEASE EDIT WITH CARE
;
var $$Array = require("rescript/lib/js/array.js");
var Table = require("./db/Table.res.js");
var Utils = require("./Utils.res.js");
var Schema = require("./db/Schema.res.js");
var Belt_Array = require("rescript/lib/js/belt_Array.js");
var Caml_option = require("rescript/lib/js/caml_option.js");
var Persistence = require("./Persistence.res.js");
var S$RescriptSchema = require("rescript-schema/src/S.res.js");
var Caml_js_exceptions = require("rescript/lib/js/caml_js_exceptions.js");
function makeCreateIndexSql(tableName, indexFields, pgSchema) {
var indexName = tableName + "_" + indexFields.join("_");
var index = Belt_Array.map(indexFields, (function (idx) {
return "\"" + idx + "\"";
})).join(", ");
return "CREATE INDEX IF NOT EXISTS \"" + indexName + "\" ON \"" + pgSchema + "\".\"" + tableName + "\"(" + index + ");";
}
function makeCreateTableIndicesSql(table, pgSchema) {
var tableName = table.tableName;
var createIndex = function (indexField) {
return makeCreateIndexSql(tableName, [indexField], pgSchema);
};
var createCompositeIndex = function (indexFields) {
return makeCreateIndexSql(tableName, indexFields, pgSchema);
};
var singleIndices = Table.getSingleIndices(table);
var compositeIndices = Table.getCompositeIndices(table);
return Belt_Array.map(singleIndices, createIndex).join("\n") + Belt_Array.map(compositeIndices, createCompositeIndex).join("\n");
}
function makeCreateTableSql(table, pgSchema) {
var fieldsMapped = Belt_Array.map(Table.getFields(table), (function (field) {
var defaultValue = field.defaultValue;
var fieldType = field.fieldType;
var fieldName = Table.getDbFieldName(field);
var tmp;
tmp = fieldType === "TIMESTAMP" || fieldType === "TIMESTAMP WITH TIME ZONE" || fieldType === "JSONB" || fieldType === "SERIAL" || fieldType === "TEXT" || fieldType === "DOUBLE PRECISION" || fieldType === "NUMERIC" || fieldType === "BOOLEAN" || fieldType === "INTEGER" || fieldType === "TIMESTAMP WITH TIME ZONE NULL" || fieldType.startsWith("NUMERIC(") ? fieldType : "\"" + pgSchema + "\"." + fieldType;
return "\"" + fieldName + "\" " + tmp + (
field.isArray ? "[]" : ""
) + (
defaultValue !== undefined ? " DEFAULT " + defaultValue : (
field.isNullable ? "" : " NOT NULL"
)
);
})).join(", ");
var primaryKeyFieldNames = Table.getPrimaryKeyFieldNames(table);
var primaryKey = Belt_Array.map(primaryKeyFieldNames, (function (field) {
return "\"" + field + "\"";
})).join(", ");
return "CREATE TABLE IF NOT EXISTS \"" + pgSchema + "\".\"" + table.tableName + "\"(" + fieldsMapped + (
primaryKeyFieldNames.length !== 0 ? ", PRIMARY KEY(" + primaryKey + ")" : ""
) + ");";
}
function makeInitializeTransaction(pgSchema, pgUser, generalTablesOpt, entitiesOpt, enumsOpt, cleanRunOpt) {
var generalTables = generalTablesOpt !== undefined ? generalTablesOpt : [];
var entities = entitiesOpt !== undefined ? entitiesOpt : [];
var enums = enumsOpt !== undefined ? enumsOpt : [];
var cleanRun = cleanRunOpt !== undefined ? cleanRunOpt : false;
var allTables = $$Array.copy(generalTables);
var allEntityTables = [];
entities.forEach(function (entity) {
allEntityTables.push(entity.table);
allTables.push(entity.table);
allTables.push(entity.entityHistory.table);
});
var derivedSchema = Schema.make(allEntityTables);
var query = {
contents: (
cleanRun ? "DROP SCHEMA IF EXISTS \"" + pgSchema + "\" CASCADE;\nCREATE SCHEMA \"" + pgSchema + "\";" : "CREATE SCHEMA IF NOT EXISTS \"" + pgSchema + "\";"
) + ("GRANT ALL ON SCHEMA \"" + pgSchema + "\" TO \"" + pgUser + "\";\nGRANT ALL ON SCHEMA \"" + pgSchema + "\" TO public;")
};
enums.forEach(function (enumConfig) {
var enumCreateQuery = "CREATE TYPE \"" + pgSchema + "\"." + enumConfig.name + " AS ENUM(" + enumConfig.variants.map(function (v) {
return "'" + v + "'";
}).join(", ") + ");";
query.contents = query.contents + "\n" + (
cleanRun ? enumCreateQuery : "IF NOT EXISTS (\n SELECT 1 FROM pg_type \n WHERE typname = '" + enumConfig.name.toLowerCase() + "' \n AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = '" + pgSchema + "')\n) THEN \n " + enumCreateQuery + "\nEND IF;"
);
});
allTables.forEach(function (table) {
query.contents = query.contents + "\n" + makeCreateTableSql(table, pgSchema);
});
allTables.forEach(function (table) {
var indices = makeCreateTableIndicesSql(table, pgSchema);
if (indices !== "") {
query.contents = query.contents + "\n" + indices;
return ;
}
});
var functionsQuery = {
contents: ""
};
entities.forEach(function (entity) {
functionsQuery.contents = functionsQuery.contents + "\n" + entity.entityHistory.createInsertFnQuery;
Table.getDerivedFromFields(entity.table).forEach(function (derivedFromField) {
var indexField = Utils.unwrapResultExn(Schema.getDerivedFromFieldName(derivedSchema, derivedFromField));
query.contents = query.contents + "\n" + makeCreateIndexSql(derivedFromField.derivedFromEntity, [indexField], pgSchema);
});
});
return [cleanRun || Utils.$$Array.isEmpty(enums) ? query.contents : "DO $$ BEGIN " + query.contents + " END $$;"].concat(functionsQuery.contents !== "" ? [functionsQuery.contents] : []);
}
function makeLoadByIdSql(pgSchema, tableName) {
return "SELECT * FROM \"" + pgSchema + "\".\"" + tableName + "\" WHERE id = $1 LIMIT 1;";
}
function makeLoadByIdsSql(pgSchema, tableName) {
return "SELECT * FROM \"" + pgSchema + "\".\"" + tableName + "\" WHERE id = ANY($1::text[]);";
}
function makeInsertUnnestSetSql(pgSchema, table, itemSchema, isRawEvents) {
var match = Table.toSqlParams(table, itemSchema);
var quotedNonPrimaryFieldNames = match.quotedNonPrimaryFieldNames;
var primaryKeyFieldNames = Table.getPrimaryKeyFieldNames(table);
return "INSERT INTO \"" + pgSchema + "\".\"" + table.tableName + "\" (" + match.quotedFieldNames.join(", ") + ")\nSELECT * FROM unnest(" + match.arrayFieldTypes.map(function (arrayFieldType, idx) {
return "$" + (idx + 1 | 0).toString() + "::" + arrayFieldType;
}).join(",") + ")" + (
isRawEvents || primaryKeyFieldNames.length === 0 ? "" : "ON CONFLICT(" + primaryKeyFieldNames.map(function (fieldName) {
return "\"" + fieldName + "\"";
}).join(",") + ") DO " + (
Utils.$$Array.isEmpty(quotedNonPrimaryFieldNames) ? "NOTHING" : "UPDATE SET " + quotedNonPrimaryFieldNames.map(function (fieldName) {
return fieldName + " = EXCLUDED." + fieldName;
}).join(",")
)
) + ";";
}
function makeInsertValuesSetSql(pgSchema, table, itemSchema, itemsCount) {
var match = Table.toSqlParams(table, itemSchema);
var quotedNonPrimaryFieldNames = match.quotedNonPrimaryFieldNames;
var quotedFieldNames = match.quotedFieldNames;
var primaryKeyFieldNames = Table.getPrimaryKeyFieldNames(table);
var fieldsCount = quotedFieldNames.length;
var placeholders = "";
for(var idx = 1; idx <= itemsCount; ++idx){
if (idx > 1) {
placeholders = placeholders + ",";
}
placeholders = placeholders + "(";
for(var fieldIdx = 0; fieldIdx < fieldsCount; ++fieldIdx){
if (fieldIdx > 0) {
placeholders = placeholders + ",";
}
placeholders = placeholders + ("$" + (Math.imul(fieldIdx, itemsCount) + idx | 0).toString());
}
placeholders = placeholders + ")";
}
return "INSERT INTO \"" + pgSchema + "\".\"" + table.tableName + "\" (" + quotedFieldNames.join(", ") + ")\nVALUES" + placeholders + (
primaryKeyFieldNames.length !== 0 ? "ON CONFLICT(" + primaryKeyFieldNames.map(function (fieldName) {
return "\"" + fieldName + "\"";
}).join(",") + ") DO " + (
Utils.$$Array.isEmpty(quotedNonPrimaryFieldNames) ? "NOTHING" : "UPDATE SET " + quotedNonPrimaryFieldNames.map(function (fieldName) {
return fieldName + " = EXCLUDED." + fieldName;
}).join(",")
) : ""
) + ";";
}
var rawEventsTableName = "raw_events";
function makeTableBatchSetQuery(pgSchema, table, itemSchema) {
var match = Table.toSqlParams(table, itemSchema);
var isRawEvents = table.tableName === rawEventsTableName;
if (isRawEvents || !match.hasArrayField) {
return {
sql: makeInsertUnnestSetSql(pgSchema, table, itemSchema, isRawEvents),
convertOrThrow: S$RescriptSchema.compile(S$RescriptSchema.unnest(match.dbSchema), "Output", "Input", "Sync", false),
isInsertValues: false
};
} else {
return {
sql: makeInsertValuesSetSql(pgSchema, table, itemSchema, 500),
convertOrThrow: S$RescriptSchema.compile(S$RescriptSchema.preprocess(S$RescriptSchema.unnest(itemSchema), (function (param) {
return {
s: (function (prim) {
return prim.flat(1);
})
};
})), "Output", "Input", "Sync", false),
isInsertValues: true
};
}
}
function chunkArray(arr, chunkSize) {
var chunks = [];
var i = 0;
while(i < arr.length) {
var chunk = arr.slice(i, i + chunkSize | 0);
chunks.push(chunk);
i = i + chunkSize | 0;
};
return chunks;
}
var setQueryCache = new WeakMap();
async function setOrThrow(sql, items, table, itemSchema, pgSchema) {
if (items.length === 0) {
return ;
}
var cached = setQueryCache.get(table);
var query;
if (cached !== undefined) {
query = Caml_option.valFromOption(cached);
} else {
var newQuery = makeTableBatchSetQuery(pgSchema, table, itemSchema);
setQueryCache.set(table, newQuery);
query = newQuery;
}
var sqlQuery = query.sql;
try {
if (!query.isInsertValues) {
return await sql.unsafe(sqlQuery, query.convertOrThrow(items), {prepare: true});
}
var chunks = chunkArray(items, 500);
var responses = [];
chunks.forEach(function (chunk) {
var chunkSize = chunk.length;
var isFullChunk = chunkSize === 500;
var response = sql.unsafe(isFullChunk ? sqlQuery : makeInsertValuesSetSql(pgSchema, table, itemSchema, chunkSize), query.convertOrThrow(chunk), {prepare: true});
responses.push(response);
});
await Promise.all(responses);
return ;
}
catch (raw_exn){
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
if (exn.RE_EXN_ID === S$RescriptSchema.Raised) {
throw {
RE_EXN_ID: Persistence.StorageError,
message: "Failed to convert items for table \"" + table.tableName + "\"",
reason: exn,
Error: new Error()
};
}
throw {
RE_EXN_ID: Persistence.StorageError,
message: "Failed to insert items into table \"" + table.tableName + "\"",
reason: exn,
Error: new Error()
};
}
}
function make(sql, pgSchema, pgUser) {
var isInitialized = async function () {
var schemas = await sql.unsafe("SELECT schema_name FROM information_schema.schemata WHERE schema_name = '" + pgSchema + "';");
return Utils.$$Array.notEmpty(schemas);
};
var initialize = async function (entitiesOpt, generalTablesOpt, enumsOpt, cleanRunOpt) {
var entities = entitiesOpt !== undefined ? entitiesOpt : [];
var generalTables = generalTablesOpt !== undefined ? generalTablesOpt : [];
var enums = enumsOpt !== undefined ? enumsOpt : [];
var cleanRun = cleanRunOpt !== undefined ? cleanRunOpt : false;
var queries = makeInitializeTransaction(pgSchema, pgUser, generalTables, entities, enums, cleanRun);
await sql.begin(function (sql) {
return queries.map(function (query) {
return sql.unsafe(query);
});
});
};
var loadByIdsOrThrow = async function (ids, table, rowsSchema) {
var rows;
try {
rows = await (
ids.length !== 1 ? sql.unsafe(makeLoadByIdsSql(pgSchema, table.tableName), [ids], {prepare: true}) : sql.unsafe(makeLoadByIdSql(pgSchema, table.tableName), ids, {prepare: true})
);
}
catch (raw_exn){
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
throw {
RE_EXN_ID: Persistence.StorageError,
message: "Failed loading \"" + table.tableName + "\" from storage by ids",
reason: exn,
Error: new Error()
};
}
try {
return S$RescriptSchema.parseOrThrow(rows, rowsSchema);
}
catch (raw_exn$1){
var exn$1 = Caml_js_exceptions.internalToOCamlException(raw_exn$1);
throw {
RE_EXN_ID: Persistence.StorageError,
message: "Failed to parse \"" + table.tableName + "\" loaded from storage by ids",
reason: exn$1,
Error: new Error()
};
}
};
var setOrThrow$1 = function (items, table, itemSchema) {
return setOrThrow(sql, items, table, itemSchema, pgSchema);
};
return {
isInitialized: isInitialized,
initialize: initialize,
loadByIdsOrThrow: loadByIdsOrThrow,
setOrThrow: setOrThrow$1
};
}
var maxItemsPerQuery = 500;
exports.makeCreateIndexSql = makeCreateIndexSql;
exports.makeCreateTableIndicesSql = makeCreateTableIndicesSql;
exports.makeCreateTableSql = makeCreateTableSql;
exports.makeInitializeTransaction = makeInitializeTransaction;
exports.makeLoadByIdSql = makeLoadByIdSql;
exports.makeLoadByIdsSql = makeLoadByIdsSql;
exports.makeInsertUnnestSetSql = makeInsertUnnestSetSql;
exports.makeInsertValuesSetSql = makeInsertValuesSetSql;
exports.rawEventsTableName = rawEventsTableName;
exports.maxItemsPerQuery = maxItemsPerQuery;
exports.makeTableBatchSetQuery = makeTableBatchSetQuery;
exports.chunkArray = chunkArray;
exports.setQueryCache = setQueryCache;
exports.setOrThrow = setOrThrow;
exports.make = make;
/* setQueryCache Not a pure module */