prisma-zod-generator
Version:
Prisma 2+ generator to emit Zod schemas from your Prisma schema
573 lines • 14.4 kB
JavaScript
"use strict";
/**
* Concurrency Control Utilities
*
* Provides mutex, semaphore, and atomic operation utilities
* to prevent race conditions in PZG Pro
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.RateLimiter = exports.CircuitBreaker = exports.ConcurrentArray = exports.ConcurrentMap = exports.AtomicCounter = exports.ReadWriteLock = exports.Semaphore = exports.Mutex = void 0;
exports.debounce = debounce;
/**
* Simple mutex implementation for async operations
*/
class Mutex {
constructor() {
this.locked = false;
this.waitQueue = [];
}
async acquire() {
return new Promise((resolve) => {
if (!this.locked) {
this.locked = true;
resolve(this.createLock());
}
else {
this.waitQueue.push(resolve);
}
});
}
createLock() {
return {
release: () => {
if (this.waitQueue.length > 0) {
const next = this.waitQueue.shift();
next(this.createLock());
}
else {
this.locked = false;
}
},
};
}
isLocked() {
return this.locked;
}
}
exports.Mutex = Mutex;
/**
* Semaphore for limiting concurrent operations
*/
class Semaphore {
constructor(permits) {
this.waitQueue = [];
this.permits = permits;
}
async acquire() {
return new Promise((resolve) => {
if (this.permits > 0) {
this.permits--;
resolve(() => this.release());
}
else {
this.waitQueue.push(() => {
this.permits--;
resolve(() => this.release());
});
}
});
}
release() {
this.permits++;
if (this.waitQueue.length > 0) {
const next = this.waitQueue.shift();
next();
}
}
available() {
return this.permits;
}
}
exports.Semaphore = Semaphore;
/**
* Read-Write lock for concurrent read access
*/
class ReadWriteLock {
constructor() {
this.readers = 0;
this.writers = 0;
this.readWaitQueue = [];
this.writeWaitQueue = [];
}
async acquireRead() {
return new Promise((resolve) => {
if (this.writers === 0 && this.writeWaitQueue.length === 0) {
this.readers++;
resolve(() => this.releaseRead());
}
else {
this.readWaitQueue.push(() => {
this.readers++;
resolve(() => this.releaseRead());
});
}
});
}
async acquireWrite() {
return new Promise((resolve) => {
if (this.readers === 0 && this.writers === 0) {
this.writers++;
resolve(() => this.releaseWrite());
}
else {
this.writeWaitQueue.push(() => {
this.writers++;
resolve(() => this.releaseWrite());
});
}
});
}
releaseRead() {
this.readers--;
if (this.readers === 0 && this.writeWaitQueue.length > 0) {
const next = this.writeWaitQueue.shift();
next();
}
}
releaseWrite() {
this.writers--;
// Prioritize writers if any are waiting
if (this.writeWaitQueue.length > 0) {
const next = this.writeWaitQueue.shift();
next();
}
else {
// Release all waiting readers
while (this.readWaitQueue.length > 0) {
const next = this.readWaitQueue.shift();
next();
}
}
}
}
exports.ReadWriteLock = ReadWriteLock;
/**
* Atomic counter for safe increment/decrement operations
*/
class AtomicCounter {
constructor() {
this.value = 0;
this.mutex = new Mutex();
}
async increment() {
const lock = await this.mutex.acquire();
try {
return ++this.value;
}
finally {
lock.release();
}
}
async decrement() {
const lock = await this.mutex.acquire();
try {
return --this.value;
}
finally {
lock.release();
}
}
async get() {
const lock = await this.mutex.acquire();
try {
return this.value;
}
finally {
lock.release();
}
}
async set(newValue) {
const lock = await this.mutex.acquire();
try {
this.value = newValue;
}
finally {
lock.release();
}
}
async compareAndSwap(expected, newValue) {
const lock = await this.mutex.acquire();
try {
if (this.value === expected) {
this.value = newValue;
return true;
}
return false;
}
finally {
lock.release();
}
}
}
exports.AtomicCounter = AtomicCounter;
/**
* Thread-safe Map implementation
*/
class ConcurrentMap {
constructor() {
this.map = new Map();
this.rwLock = new ReadWriteLock();
}
async get(key) {
const release = await this.rwLock.acquireRead();
try {
return this.map.get(key);
}
finally {
release();
}
}
async set(key, value) {
const release = await this.rwLock.acquireWrite();
try {
this.map.set(key, value);
}
finally {
release();
}
}
async delete(key) {
const release = await this.rwLock.acquireWrite();
try {
return this.map.delete(key);
}
finally {
release();
}
}
async has(key) {
const release = await this.rwLock.acquireRead();
try {
return this.map.has(key);
}
finally {
release();
}
}
async size() {
const release = await this.rwLock.acquireRead();
try {
return this.map.size;
}
finally {
release();
}
}
async keys() {
const release = await this.rwLock.acquireRead();
try {
return Array.from(this.map.keys());
}
finally {
release();
}
}
async values() {
const release = await this.rwLock.acquireRead();
try {
return Array.from(this.map.values());
}
finally {
release();
}
}
async entries() {
const release = await this.rwLock.acquireRead();
try {
return Array.from(this.map.entries());
}
finally {
release();
}
}
async clear() {
const release = await this.rwLock.acquireWrite();
try {
this.map.clear();
}
finally {
release();
}
}
async forEach(callback) {
const release = await this.rwLock.acquireRead();
try {
this.map.forEach(callback);
}
finally {
release();
}
}
/**
* Atomic update operation - ensures consistency
*/
async update(key, updater) {
const release = await this.rwLock.acquireWrite();
try {
const current = this.map.get(key);
const updated = updater(current);
this.map.set(key, updated);
return updated;
}
finally {
release();
}
}
/**
* Atomic upsert operation
*/
async upsert(key, initial, updater) {
const release = await this.rwLock.acquireWrite();
try {
const current = this.map.get(key);
const value = current ? updater(current) : initial;
this.map.set(key, value);
return value;
}
finally {
release();
}
}
}
exports.ConcurrentMap = ConcurrentMap;
/**
* Thread-safe Array implementation
*/
class ConcurrentArray {
constructor() {
this.array = [];
this.mutex = new Mutex();
}
async push(...items) {
const lock = await this.mutex.acquire();
try {
return this.array.push(...items);
}
finally {
lock.release();
}
}
async pop() {
const lock = await this.mutex.acquire();
try {
return this.array.pop();
}
finally {
lock.release();
}
}
async shift() {
const lock = await this.mutex.acquire();
try {
return this.array.shift();
}
finally {
lock.release();
}
}
async unshift(...items) {
const lock = await this.mutex.acquire();
try {
return this.array.unshift(...items);
}
finally {
lock.release();
}
}
async length() {
const lock = await this.mutex.acquire();
try {
return this.array.length;
}
finally {
lock.release();
}
}
async get(index) {
const lock = await this.mutex.acquire();
try {
return this.array[index];
}
finally {
lock.release();
}
}
async set(index, value) {
const lock = await this.mutex.acquire();
try {
this.array[index] = value;
}
finally {
lock.release();
}
}
async slice(start, end) {
const lock = await this.mutex.acquire();
try {
return this.array.slice(start, end);
}
finally {
lock.release();
}
}
async filter(predicate) {
const lock = await this.mutex.acquire();
try {
return this.array.filter(predicate);
}
finally {
lock.release();
}
}
async forEach(callback) {
const lock = await this.mutex.acquire();
try {
this.array.forEach(callback);
}
finally {
lock.release();
}
}
async clear() {
const lock = await this.mutex.acquire();
try {
this.array.length = 0;
}
finally {
lock.release();
}
}
/**
* Atomic batch operation
*/
async batch(operation) {
const lock = await this.mutex.acquire();
try {
return operation(this.array);
}
finally {
lock.release();
}
}
}
exports.ConcurrentArray = ConcurrentArray;
/**
* Debounce utility for preventing rapid successive calls
*/
function debounce(fn, delay) {
let timeoutId = null;
let resolvePromise = null;
let rejectPromise = null;
return (...args) => {
return new Promise((resolve, reject) => {
if (timeoutId) {
clearTimeout(timeoutId);
}
resolvePromise = resolve;
rejectPromise = reject;
timeoutId = setTimeout(async () => {
try {
const result = await fn(...args);
resolvePromise === null || resolvePromise === void 0 ? void 0 : resolvePromise(result);
}
catch (error) {
rejectPromise === null || rejectPromise === void 0 ? void 0 : rejectPromise(error);
}
}, delay);
});
};
}
/**
* Circuit breaker pattern for fault tolerance
*/
class CircuitBreaker {
constructor(threshold = 5, timeout = 60000, monitoringPeriod = 10000) {
this.threshold = threshold;
this.timeout = timeout;
this.monitoringPeriod = monitoringPeriod;
this.state = 'closed';
this.failureCount = 0;
this.nextAttempt = 0;
this.successCount = 0;
}
async execute(operation) {
if (this.state === 'open') {
if (Date.now() < this.nextAttempt) {
throw new Error('Circuit breaker is open');
}
this.state = 'half-open';
this.successCount = 0;
}
try {
const result = await operation();
this.onSuccess();
return result;
}
catch (error) {
this.onFailure();
throw error;
}
}
onSuccess() {
this.failureCount = 0;
if (this.state === 'half-open') {
this.successCount++;
if (this.successCount >= 3) {
this.state = 'closed';
}
}
}
onFailure() {
this.failureCount++;
if (this.failureCount >= this.threshold) {
this.state = 'open';
this.nextAttempt = Date.now() + this.timeout;
}
}
getState() {
return this.state;
}
reset() {
this.state = 'closed';
this.failureCount = 0;
this.successCount = 0;
this.nextAttempt = 0;
}
}
exports.CircuitBreaker = CircuitBreaker;
/**
* Rate limiter for controlling request frequency
*/
class RateLimiter {
constructor(capacity, refillRate, // tokens per second
refillPeriod = 1000) {
this.capacity = capacity;
this.refillRate = refillRate;
this.refillPeriod = refillPeriod;
this.lastRefill = Date.now();
this.tokens = capacity;
}
async acquire(tokensRequested = 1) {
this.refill();
if (this.tokens >= tokensRequested) {
this.tokens -= tokensRequested;
return true;
}
return false;
}
refill() {
const now = Date.now();
const timePassed = now - this.lastRefill;
const tokensToAdd = Math.floor((timePassed / this.refillPeriod) * this.refillRate);
if (tokensToAdd > 0) {
this.tokens = Math.min(this.capacity, this.tokens + tokensToAdd);
this.lastRefill = now;
}
}
available() {
this.refill();
return this.tokens;
}
}
exports.RateLimiter = RateLimiter;
//# sourceMappingURL=concurrency.js.map