or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

argument-transformation.mdcache-introspection.mdcache-management.mdcore-memoization.mdequality-comparison.mdindex.mdspecialized-memoization.mdstatistics-profiling.mdutility-methods.md

argument-transformation.mddocs/

0

# Argument Transformation

1

2

Methods for transforming and manipulating function arguments before caching, enabling advanced cache key customization and conditional cache updates.

3

4

## Capabilities

5

6

### Argument Transformation

7

8

Transform arguments before they are used to generate cache keys, allowing for normalization and custom cache key generation.

9

10

```typescript { .api }

11

/**

12

* Transform arguments before caching

13

* @param transformer Function to transform the argument array (cache key)

14

* @returns Moizer with argument transformation

15

*/

16

transformArgs<Transformer extends TransformKey>(

17

transformer: Transformer

18

): Moizer<{ transformArgs: Transformer }>;

19

20

type TransformKey = (key: Key) => Key;

21

type Key<Arg extends any = any> = Arg[];

22

```

23

24

**Usage Examples:**

25

26

```typescript

27

import moize from "moize";

28

29

// Normalize string arguments

30

const normalizeStrings = (key: any[]) => {

31

return key.map(arg =>

32

typeof arg === 'string' ? arg.toLowerCase().trim() : arg

33

);

34

};

35

36

const processText = (text: string, options: { uppercase: boolean }) => {

37

return options.uppercase ? text.toUpperCase() : text.toLowerCase();

38

};

39

40

const normalizedMemoized = moize.transformArgs(normalizeStrings)(processText);

41

42

console.log(normalizedMemoized(" Hello ", { uppercase: true })); // Computed

43

console.log(normalizedMemoized("hello", { uppercase: true })); // Cached (normalized match)

44

45

// Sort array arguments for order-independent caching

46

const sortArrayArgs = (key: any[]) => {

47

return key.map(arg => {

48

if (Array.isArray(arg)) {

49

return [...arg].sort();

50

}

51

return arg;

52

});

53

};

54

55

const sumArray = (numbers: number[]) => numbers.reduce((a, b) => a + b, 0);

56

const orderIndependentSum = moize.transformArgs(sortArrayArgs)(sumArray);

57

58

console.log(orderIndependentSum([3, 1, 2])); // 6 (computed)

59

console.log(orderIndependentSum([1, 2, 3])); // 6 (cached - same sorted values)

60

61

// Extract specific properties for cache key

62

const extractUserKey = (key: any[]) => {

63

return key.map(arg => {

64

if (arg && typeof arg === 'object' && 'id' in arg && 'role' in arg) {

65

return { id: arg.id, role: arg.role }; // Only use id and role for caching

66

}

67

return arg;

68

});

69

};

70

71

const processUser = (user: {

72

id: string;

73

name: string;

74

email: string;

75

role: string;

76

lastLogin?: Date;

77

}) => {

78

return `${user.role.toUpperCase()}: ${user.name}`;

79

};

80

81

const userMemoized = moize.transformArgs(extractUserKey)(processUser);

82

83

const user1 = { id: "1", name: "Alice", email: "alice@example.com", role: "admin", lastLogin: new Date() };

84

const user2 = { id: "1", name: "Alice", email: "alice@newdomain.com", role: "admin" }; // Different email, no lastLogin

85

86

console.log(userMemoized(user1)); // Computed

87

console.log(userMemoized(user2)); // Cached (same id and role)

88

```

89

90

### Conditional Cache Updates

91

92

Control when cache entries should be updated based on the current cache key.

93

94

```typescript { .api }

95

/**

96

* Conditionally update cache based on key analysis

97

* @param updateCacheForKey Function that determines when to update cache

98

* @returns Moizer with conditional cache updating

99

*/

100

updateCacheForKey<UpdateWhen extends UpdateCacheForKey>(

101

updateCacheForKey: UpdateWhen

102

): Moizer<{ updateCacheForKey: UpdateWhen }>;

103

104

type UpdateCacheForKey = (key: Key) => boolean;

105

```

106

107

**Usage Examples:**

108

109

```typescript

110

import moize from "moize";

111

112

// Update cache only for specific conditions

113

const shouldUpdateCache = (key: any[]) => {

114

const [data, options] = key;

115

116

// Always update if force refresh is requested

117

if (options && options.forceRefresh) {

118

return true;

119

}

120

121

// Update if data is marked as stale

122

if (data && data.lastModified) {

123

const fiveMinutesAgo = Date.now() - 5 * 60 * 1000;

124

return data.lastModified > fiveMinutesAgo;

125

}

126

127

return false; // Use cached version otherwise

128

};

129

130

const processData = (

131

data: { content: any; lastModified?: number },

132

options: { forceRefresh?: boolean } = {}

133

) => {

134

console.log('Processing data...');

135

return { processed: data.content, timestamp: Date.now() };

136

};

137

138

const conditionalMemoized = moize.updateCacheForKey(shouldUpdateCache)(processData);

139

140

const oldData = { content: "test", lastModified: Date.now() - 10 * 60 * 1000 }; // 10 min ago

141

const freshData = { content: "test", lastModified: Date.now() }; // Now

142

143

console.log(conditionalMemoized(oldData)); // Uses cache if available

144

console.log(conditionalMemoized(freshData)); // Always recomputes (fresh data)

145

console.log(conditionalMemoized(oldData, { forceRefresh: true })); // Always recomputes (forced)

146

147

// Version-based cache updating

148

const versionBasedUpdate = (key: any[]) => {

149

const [resource] = key;

150

151

if (!resource || typeof resource.version !== 'number') {

152

return true; // Update if no version info

153

}

154

155

// Update if version is different from what might be cached

156

return true; // In practice, you'd compare with cached version

157

};

158

159

const fetchResource = (resource: { id: string; version: number }) => {

160

console.log(`Fetching resource ${resource.id} v${resource.version}`);

161

return { data: `Resource ${resource.id}`, version: resource.version };

162

};

163

164

const versionMemoized = moize.updateCacheForKey(versionBasedUpdate)(fetchResource);

165

166

// Time-based cache invalidation

167

const timeBasedUpdate = (key: any[]) => {

168

const [, options] = key;

169

170

if (options && options.timestamp) {

171

const thirtySecondsAgo = Date.now() - 30 * 1000;

172

return options.timestamp > thirtySecondsAgo; // Update if timestamp is recent

173

}

174

175

return false;

176

};

177

178

const timestampMemoized = moize.updateCacheForKey(timeBasedUpdate)(processData);

179

```

180

181

### Combining Transformation Methods

182

183

Argument transformation methods can be combined with other moize features for sophisticated caching strategies.

184

185

```typescript

186

import moize from "moize";

187

188

// Normalize and extract key properties

189

const normalizeAndExtract = (key: any[]) => {

190

return key.map(arg => {

191

if (typeof arg === 'string') {

192

return arg.toLowerCase().trim();

193

}

194

if (arg && typeof arg === 'object') {

195

// Extract only relevant properties

196

const { id, type, status } = arg;

197

return { id, type, status };

198

}

199

return arg;

200

});

201

};

202

203

// Update based on data freshness

204

const updateForFreshData = (key: any[]) => {

205

const [item] = key;

206

if (item && item.updatedAt) {

207

const oneHourAgo = Date.now() - 60 * 60 * 1000;

208

return item.updatedAt > oneHourAgo;

209

}

210

return true; // Update if no timestamp

211

};

212

213

const processItem = (item: {

214

id: string;

215

type: string;

216

status: string;

217

data: any;

218

updatedAt?: number;

219

metadata?: any;

220

}) => {

221

return {

222

processedId: item.id,

223

processedType: item.type.toUpperCase(),

224

processedStatus: item.status,

225

processedAt: Date.now()

226

};

227

};

228

229

const advancedMemoized = moize

230

.transformArgs(normalizeAndExtract) // Normalize cache keys

231

.updateCacheForKey(updateForFreshData) // Update for fresh data

232

.maxSize(50) // Limit cache size

233

.maxAge(3600000) // 1 hour TTL

234

.profile('item-processing') // Performance monitoring

235

(processItem);

236

237

// Chaining with other specialized methods

238

const apiProcessor = async (endpoint: string, params: Record<string, any>) => {

239

const response = await fetch(endpoint, {

240

method: 'POST',

241

body: JSON.stringify(params),

242

headers: { 'Content-Type': 'application/json' }

243

});

244

return response.json();

245

};

246

247

const normalizeApiArgs = (key: any[]) => {

248

const [endpoint, params] = key;

249

return [

250

endpoint.toLowerCase(),

251

params ? Object.keys(params).sort().reduce((sorted, k) => {

252

sorted[k] = params[k];

253

return sorted;

254

}, {} as any) : {}

255

];

256

};

257

258

const smartApiMemoized = moize.promise

259

.transformArgs(normalizeApiArgs)

260

.serialize

261

.maxAge(60000)

262

(apiProcessor);

263

```

264

265

### Performance Considerations

266

267

- **Transformation overhead**: Complex transformations add computation cost on every function call

268

- **Cache key size**: Transformed keys should be reasonably sized for memory efficiency

269

- **Conditional updates**: `updateCacheForKey` functions should be fast to avoid performance penalties